Skip to content

Commit 5849ecb

Browse files
authored
Merge pull request #13 from skaerg/update_export_csv
Update export CSV API
2 parents 3b9cf42 + 8a3b68e commit 5849ecb

File tree

2 files changed

+53
-29
lines changed

2 files changed

+53
-29
lines changed

src/Rudder/Table.elm

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ module Rudder.Table exposing
99
, CsvExportData
1010
, CsvExportConfig, CsvExportOptions
1111
, updateData, updateFilter, updateDataWithFilter
12+
, updateExportToCsv
1213
, Model, Msg
1314
, view, update, init
1415
, OutMsg(..)
16+
, viewCsvExportButton
1517
, Effect(..), updateWithEffect
1618
, sortColumn
1719
, storageOptions, getFilterOptionValue, getRows, getSort
@@ -46,13 +48,15 @@ It has a TEA approach, so it should be used with the [Nested TEA][nested-tea] ar
4648
# State-changing functions
4749
4850
@docs updateData, updateFilter, updateDataWithFilter
51+
@docs updateExportToCsv
4952
5053
5154
# Common TEA
5255
5356
@docs Model, Msg
5457
@docs view, update, init
5558
@docs OutMsg
59+
@docs viewCsvExportButton
5660
5761
5862
# Testing only
@@ -171,7 +175,7 @@ type alias StorageOptionsConfig msg =
171175
{-| CSV export configuration
172176
-}
173177
type alias CsvExportConfig row parentMsg =
174-
{ fileName : String, entryToStringList : row -> List String, btnAttributes : List (Attribute (Msg parentMsg)) }
178+
{ entryToStringList : row -> List String, btnAttributes : List (Attribute (Msg parentMsg)) }
175179

176180

177181
{-| Options for CSV export support of a given table
@@ -184,7 +188,7 @@ type CsvExportOptions row msg
184188
{-| Datatype that represents the result of exporting a table to CSV
185189
-}
186190
type alias CsvExportData =
187-
{ fileName : String, csv : String }
191+
{ filename : String, csv : String }
188192

189193

190194
{-| Table display customizations for adding custom HTML attributes, e.g. `class` to parts of the table.
@@ -255,15 +259,17 @@ type Msg parentMsg
255259
| RefreshMsg
256260
| FilterInputChanged String
257261
| UpdateFilterMsg SearchFilterState
258-
| ExportCsvMsg
262+
| ExportCsvRequest
263+
| ExportCsvMsg String
259264
| ParentMsg parentMsg
260265

261266

262267
{-| The public message to be exposed to parent components
263268
-}
264269
type OutMsg parentMsg
265-
= Refresh
270+
= RefreshRequested
266271
| OnHtml parentMsg
272+
| CsvExportRequested
267273

268274

269275
{-| A representation of concrete effects in the type system to allow testing
@@ -461,15 +467,26 @@ interpret =
461467
SaveFilterInLocalStorage key filter cb ->
462468
cb (encodeStorageEffect key filter)
463469

464-
DownloadTableAsCsv { fileName, csv } ->
465-
File.Download.string fileName "text/csv" csv
470+
DownloadTableAsCsv { filename, csv } ->
471+
File.Download.string filename "text/csv" csv
466472

467473
IgnoreExportCsvMsgNoConfig ->
468474
Cmd.none
469475
)
470476
>> Cmd.batch
471477

472478

479+
{-| Update function to call in order to send the an "Export to CSV" Msg from the parent component
480+
-}
481+
updateExportToCsv : Model row msg -> String -> ( Model row msg, Cmd msg, Maybe (OutMsg msg) )
482+
updateExportToCsv model filename =
483+
let
484+
( updatedModel, effect, outMsg ) =
485+
updateWithEffect (ExportCsvMsg filename) model
486+
in
487+
( updatedModel, interpret effect, outMsg )
488+
489+
473490
{-| Concrete implementation of the update loop, using the [effect] pattern.
474491
Would be useful for testing, not for public API.
475492
@@ -485,7 +502,7 @@ updateWithEffect msg (Model model) =
485502

486503
RefreshMsg ->
487504
-- FIXME: disable button
488-
( Model model, [], Just Refresh )
505+
( Model model, [], Just RefreshRequested )
489506

490507
FilterInputChanged s ->
491508
updateWithEffect (UpdateFilterMsg (substring s)) (Model model)
@@ -497,10 +514,13 @@ updateWithEffect msg (Model model) =
497514
in
498515
( newModel, effects, Nothing )
499516

500-
ExportCsvMsg ->
517+
ExportCsvRequest ->
518+
( Model model, [], Just CsvExportRequested )
519+
520+
ExportCsvMsg filename ->
501521
case model.options.csvExport of
502522
CsvExportButton csvExportConfig ->
503-
( Model model, [ DownloadTableAsCsv (tableToCsv (Model model) csvExportConfig) ], Nothing )
523+
( Model model, [ DownloadTableAsCsv (tableToCsv (Model model) csvExportConfig filename) ], Nothing )
504524

505525
NoCsvExportButton ->
506526
( Model model, [ IgnoreExportCsvMsgNoConfig ], Nothing )
@@ -603,7 +623,7 @@ updateFilter =
603623

604624
{-| Internal Msg that produces the CSV export event; used in tests
605625
-}
606-
exportCsv : Msg msg
626+
exportCsv : String -> Msg msg
607627
exportCsv =
608628
ExportCsvMsg
609629

@@ -689,8 +709,8 @@ storageValueTypeText valueType =
689709

690710
{-| Table to CSV export function
691711
-}
692-
tableToCsv : Model row msg -> CsvExportConfig row msg -> CsvExportData
693-
tableToCsv (Model model) { fileName, entryToStringList } =
712+
tableToCsv : Model row msg -> CsvExportConfig row msg -> String -> CsvExportData
713+
tableToCsv (Model model) { entryToStringList } filename =
694714
let
695715
-- first row contains column names
696716
columns : List String
@@ -711,7 +731,7 @@ tableToCsv (Model model) { fileName, entryToStringList } =
711731
(\entry -> List.map2 Tuple.pair columns entry)
712732
, fieldSeparator = ','
713733
}
714-
|> CsvExportData fileName
734+
|> CsvExportData filename
715735

716736

717737

@@ -802,7 +822,7 @@ viewHeaderButtons { refresh, csvExport } =
802822

803823
( NoRefreshButton, csvOptions ) ->
804824
[ div [ style "margin-left" "auto", style "margin-right" "0" ]
805-
[ div [] [ viewCsvExportButton csvOptions ]
825+
[ div [] [ viewCsvExportButtonOption csvOptions ]
806826
]
807827
]
808828

@@ -812,7 +832,7 @@ viewHeaderButtons { refresh, csvExport } =
812832
( refreshOptions, csvOptions ) ->
813833
[ div [ style "margin-left" "auto", style "display" "flex" ]
814834
[ div [ style "margin-right" ".5rem" ]
815-
[ div [] [ viewCsvExportButton csvOptions ] ]
835+
[ div [] [ viewCsvExportButtonOption csvOptions ] ]
816836
, viewRefreshButton refreshOptions
817837
]
818838
]
@@ -828,8 +848,8 @@ viewRefreshButton option =
828848
button (onClick RefreshMsg :: attrs) [ i [ class "fa fa-refresh" ] [] ]
829849

830850

831-
viewCsvExportButton : CsvExportOptions row msg -> Html (Msg msg)
832-
viewCsvExportButton option =
851+
viewCsvExportButtonOption : CsvExportOptions row msg -> Html (Msg msg)
852+
viewCsvExportButtonOption option =
833853
case option of
834854
NoCsvExportButton ->
835855
text ""
@@ -839,7 +859,7 @@ viewCsvExportButton option =
839859
([ class "btn btn-primary"
840860
, tabindex 0
841861
, type_ "button"
842-
, onClick ExportCsvMsg
862+
, onClick ExportCsvRequest
843863
]
844864
++ btnAttributes
845865
)
@@ -851,6 +871,13 @@ viewCsvExportButton option =
851871
]
852872

853873

874+
{-| View for the CSV export button in case the button should be displayed outside of the table
875+
-}
876+
viewCsvExportButton : Model row msg -> Html (Msg msg)
877+
viewCsvExportButton (Model model) =
878+
viewCsvExportButtonOption model.options.csvExport
879+
880+
854881
tableHeader : NonEmptyList.Nonempty (Column row msg) -> Sort a -> Html (Msg msg)
855882
tableHeader columns sort =
856883
tr [ class "head" ]

tests/TestTable.elm

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,13 @@ csvColumnFuzz (NonEmptyList.Nonempty head tail) =
103103
(sequence (List.map colNameToColumnFuzz tail))
104104

105105

106-
csvModelFuzz : NonEmptyList.Nonempty String -> String -> (row -> List String) -> List row -> Fuzzer (RudderTable.Model row msg)
107-
csvModelFuzz columnNames fileName entryToStringList data =
106+
csvModelFuzz : NonEmptyList.Nonempty String -> (row -> List String) -> List row -> Fuzzer (RudderTable.Model row msg)
107+
csvModelFuzz columnNames entryToStringList data =
108108
let
109109
options =
110110
buildOptions.newOptions
111111
|> buildOptions.withCsvExport
112-
{ fileName = fileName
113-
, entryToStringList = entryToStringList
112+
{ entryToStringList = entryToStringList
114113
, btnAttributes = []
115114
}
116115

@@ -241,36 +240,34 @@ suite =
241240
[ fuzz (nonEmptyListFuzzer columnFuzz) "test csv export on empty table that does not define a csv export configuration" <|
242241
\c ->
243242
init (buildConfig.newConfig c) []
244-
|> updateWithEffect exportCsv
243+
|> updateWithEffect (exportCsv "filename")
245244
|> effect
246245
|> Expect.equal [ IgnoreExportCsvMsgNoConfig ]
247246
, fuzz
248-
(csvModelFuzz (NonEmptyList.Nonempty "name" []) "myFile" (\row -> row) [])
247+
(csvModelFuzz (NonEmptyList.Nonempty "name" []) (\row -> row) [])
249248
"test csv export on empty table that defines a csv export configuration"
250249
<|
251250
\m ->
252251
m
253-
|> updateWithEffect exportCsv
252+
|> updateWithEffect (exportCsv "myFile")
254253
|> effect
255254
|> Expect.equal [ DownloadTableAsCsv (CsvExportData "myFile" "") ]
256255
, fuzz
257256
(csvModelFuzz
258257
(NonEmptyList.Nonempty "name" [ "age" ])
259-
"otherFile"
260258
(\{ a, b } -> [ a, String.fromInt b ])
261259
[ { a = "Alice", b = 45 }, { a = "Bob", b = 37 } ]
262260
)
263261
"test csv export on non-empty table that defines a csv export configuration"
264262
<|
265263
\m ->
266264
m
267-
|> updateWithEffect exportCsv
265+
|> updateWithEffect (exportCsv "otherFile")
268266
|> effect
269267
|> Expect.equal [ DownloadTableAsCsv (CsvExportData "otherFile" "name,age\u{000D}\nAlice,45\u{000D}\nBob,37") ]
270268
, fuzz
271269
(csvModelFuzz
272270
(NonEmptyList.Nonempty "\"Name\"" [ "Age,probably" ])
273-
"yetAnotherFile"
274271
(\{ a, b } -> [ a, String.fromInt b ])
275272
[ { a = "\"Al\"ice\"", b = 45 }
276273
, { a = "Bo,b", b = 37 }
@@ -281,7 +278,7 @@ suite =
281278
<|
282279
\m ->
283280
m
284-
|> updateWithEffect exportCsv
281+
|> updateWithEffect (exportCsv "yetAnotherFile")
285282
|> effect
286283
|> Expect.equal [ DownloadTableAsCsv (CsvExportData "yetAnotherFile" "\"\"\"Name\"\"\",\"Age,probably\"\u{000D}\n\"\"\"Al\"\"ice\"\"\",45\u{000D}\n\"Bo,b\",37\u{000D}\n\"\nEve\",28") ]
287284
]

0 commit comments

Comments
 (0)