Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement undo/redo actions #269

Merged
merged 35 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
25fae59
Bootstrap undo with move and show/hide tables
Dec 8, 2023
6fa5755
Fix undo hide table
Dec 10, 2023
394ed71
Undo rename project
Dec 10, 2023
0342584
Fix Batch command to properly undo ShowTables
Dec 10, 2023
250bff2
Undo GoToTable
Dec 10, 2023
04c457e
Undo for ShowAllTables
Dec 10, 2023
1022df9
Undo for show/hide related tables
Dec 10, 2023
ab7896b
Undo for show/hide columns
Dec 11, 2023
7f0cbc5
Merge branch 'main' into undo-redo
Dec 18, 2023
602ec58
Undo for show/hide/sort columns
Dec 23, 2023
b843643
Undo for select items
Dec 23, 2023
6c600a4
Undo for layout items position
Dec 23, 2023
ac53df9
Flatten layout folders when possible
Dec 25, 2023
f748146
Refactor undo history
Dec 26, 2023
8ca5067
Undo table color
Dec 26, 2023
fc1aac8
Refactor table hover
Dec 26, 2023
04dc820
Undo for move column
Dec 27, 2023
9f32014
Undo for add relations
Dec 27, 2023
009ffde
Undo for layouts
Dec 27, 2023
0b83be0
Undo for groups
Dec 27, 2023
934f2b3
Undo for notes, tags & memos
Dec 29, 2023
1be483b
Undo for show/hide table-rows
Dec 30, 2023
8be4490
Undo for table-rows actions
Dec 30, 2023
3d0a1ee
Undo for AML editor
Dec 31, 2023
733b8fc
Undo for project settings
Dec 31, 2023
76a8b2b
Refactor actions without undo
Dec 31, 2023
7f56025
Undo for fit & arrange diagram
Jan 1, 2024
2450d44
Improve undo/redo buttons
Jan 2, 2024
96c62e3
Refacto with Extra type
Jan 2, 2024
24d9104
cleanup
Jan 2, 2024
1634271
cleanup 2
Jan 2, 2024
77e1890
code review
Jan 3, 2024
f1b66a6
code review 2
Jan 3, 2024
2347ffd
Refactor Extra data
Jan 3, 2024
acd5c83
last fixes
Jan 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/review/src/ReviewConfig.elm
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ config =
, NoDebug.TodoOrToString.rule |> Rule.ignoreErrorsForFiles [ "src/Libs/Debug.elm" ]
, NoExposingEverything.rule |> Rule.ignoreErrorsForDirectories [ "tests" ]
, NoMissingSubscriptionsCall.rule
, NoRecursiveUpdate.rule
, NoRecursiveUpdate.rule |> Rule.ignoreErrorsForFiles [ "src/PagesComponents/Organization_/Project_/Updates.elm" ]
, NoMissingTypeAnnotation.rule |> Rule.ignoreErrorsForDirectories [ ".elm-spa" ]
, NoMissingTypeAnnotationInLetIn.rule
, NoMissingTypeExpose.rule |> Rule.ignoreErrorsForDirectories [ ".elm-spa" ]
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/Components/Organisms/Table.elm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Components.Organisms.Table exposing (Actions, CheckConstraint, Column, DocState, IndexConstraint, Model, NestedColumns(..), ProjectInfo, Relation, SharedDocState, State, TableConf, UniqueConstraint, doc, docInit, table)
module Components.Organisms.Table exposing (Actions, CheckConstraint, Column, DocState, IndexConstraint, Model, NestedColumns(..), ProjectInfo, Relation, SharedDocState, State, TableConf, TableHover, UniqueConstraint, doc, docInit, table)

import Components.Atoms.Icon as Icon
import Components.Atoms.Icons as Icons
Expand Down Expand Up @@ -84,6 +84,10 @@ type NestedColumns
= NestedColumns Int (List Column)


type alias TableHover =
( TableId, Maybe ColumnPath )


type alias State =
{ color : Color
, isHover : Bool
Expand Down
108 changes: 66 additions & 42 deletions frontend/src/Components/Organisms/TableRow.elm
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ import Models.Size as Size
import Models.SqlQuery exposing (SqlQuery, SqlQueryOrigin)
import PagesComponents.Organization_.Project_.Models.ErdConf as ErdConf exposing (ErdConf)
import PagesComponents.Organization_.Project_.Models.PositionHint as PositionHint exposing (PositionHint)
import PagesComponents.Organization_.Project_.Updates.Extra as Extra exposing (Extra)
import PagesComponents.Organization_.Project_.Views.Modals.ColumnRowContextMenu as ColumnRowContextMenu
import PagesComponents.Organization_.Project_.Views.Modals.TableRowContextMenu as TableRowContextMenu
import Ports
import Services.Lenses exposing (mapColumns, mapHidden, mapSelected, mapShowHiddenColumns, mapState, setCollapsed, setPrevious, setState)
import Services.Lenses exposing (mapCollapsedT, mapColumns, mapHidden, mapSelected, mapShowHiddenColumns, mapState, mapStateT, setPrevious, setState)
import Services.Toasts as Toasts
import Set exposing (Set)
import Time
Expand All @@ -84,9 +85,8 @@ type Msg
= GotResult QueryResult
| Refresh
| Cancel
| Restore TableRow.SuccessState
| Collapse
| Expand
| SetState State
| SetCollapsed Bool
| ShowColumn ColumnPathStr
| HideColumn ColumnPathStr
| ToggleHiddenColumns
Expand Down Expand Up @@ -144,7 +144,10 @@ init project id now source query hidden previous hint =
, selected = False
, collapsed = False
}
, Cmd.batch [ previous |> Maybe.mapOrElse (\_ -> Cmd.none) (Ports.runDatabaseQuery (dbPrefix ++ "/" ++ String.fromInt id) source.db.url sqlQuery), Track.tableRowOpened previous source sqlQuery project ]
, Cmd.batch
[ previous |> Maybe.mapOrElse (\_ -> Cmd.none) (Ports.runDatabaseQuery (dbPrefix ++ "/" ++ String.fromInt id) source.db.url sqlQuery)
, Track.tableRowOpened previous source sqlQuery project
]
)


Expand Down Expand Up @@ -181,22 +184,31 @@ initRelation src ref =
-- UPDATE


update : (HtmlId -> msg) -> (Toasts.Msg -> msg) -> Time.Posix -> ProjectInfo -> List Source -> HtmlId -> Msg -> Model -> ( Model, Cmd msg )
update toggleDropdown showToast now project sources openedDropdown msg model =
update : (Msg -> msg) -> (HtmlId -> msg) -> (Toasts.Msg -> msg) -> msg -> (TableRow -> msg) -> Time.Posix -> ProjectInfo -> List Source -> HtmlId -> Msg -> Model -> ( Model, Extra msg )
update wrap toggleDropdown showToast deleteTableRow unDeleteTableRow now project sources openedDropdown msg model =
case msg of
GotResult res ->
( model
|> mapStateLoading (\l -> res.result |> Result.fold (initFailure l.query l.previous res.started res.finished) (initSuccess res.started res.finished))
|> mapHidden
(\h ->
if Set.isEmpty h then
res.result |> Result.mapOrElse defaultHidden Set.empty

else
h
)
, Track.tableRowResult res project
)
model
|> mapStateLoadingTM (\l -> ( res.result |> Result.fold (initFailure l.query l.previous res.started res.finished) (initSuccess res.started res.finished), l.previous ))
|> (\( newModel, previous ) ->
( newModel
|> mapHidden
(\h ->
if Set.isEmpty h then
res.result |> Result.mapOrElse defaultHidden Set.empty

else
h
)
, Extra.new
(Track.tableRowResult res project)
(previous
|> Maybe.map (\s -> ( wrap (SetState (StateSuccess s)), wrap (SetState newModel.state) ))
|> Maybe.withDefault ( deleteTableRow, unDeleteTableRow newModel )
-- if no previous, add history for show table row (initial loading, cf frontend/src/PagesComponents/Organization_/Project_/Updates/TableRow.elm#showTableRow)
)
)
)

Refresh ->
withDbSource showToast
Expand All @@ -209,30 +221,27 @@ update toggleDropdown showToast now project sources openedDropdown msg model =
DbQuery.findRow dbSrc.db.kind { table = model.table, primaryKey = model.primaryKey }
in
( model |> setState (StateLoading { query = sqlQuery, startedAt = now, previous = model |> TableRow.stateSuccess })
, Ports.runDatabaseQuery (dbPrefix ++ "/" ++ String.fromInt model.id) dbSrc.db.url sqlQuery
, Ports.runDatabaseQuery (dbPrefix ++ "/" ++ String.fromInt model.id) dbSrc.db.url sqlQuery |> Extra.cmd
)
)

Cancel ->
( model |> mapStateLoading (\l -> initFailure l.query l.previous l.startedAt now "Query canceled"), Cmd.none )

Restore success ->
( model |> setState (StateSuccess success), Cmd.none )
( model |> mapStateLoading (\l -> initFailure l.query l.previous l.startedAt now "Query canceled"), Extra.none )

Collapse ->
( model |> setCollapsed True, Cmd.none )
SetState state ->
model |> mapStateT (\s -> ( state, Extra.history ( wrap (SetState s), wrap msg ) ))

Expand ->
( model |> setCollapsed False, Cmd.none )
SetCollapsed value ->
model |> mapCollapsedT (\c -> ( value, Extra.history ( wrap (SetCollapsed c), wrap msg ) ))

ShowColumn pathStr ->
( model |> mapHidden (Set.remove pathStr), Cmd.none )
( model |> mapHidden (Set.remove pathStr), Extra.history ( wrap (HideColumn pathStr), wrap msg ) )

HideColumn pathStr ->
( model |> mapHidden (Set.insert pathStr), Cmd.none )
( model |> mapHidden (Set.insert pathStr), Extra.history ( wrap (ShowColumn pathStr), wrap msg ) )

ToggleHiddenColumns ->
( model |> mapShowHiddenColumns not, Cmd.none )
( model |> mapShowHiddenColumns not, Extra.history ( wrap ToggleHiddenColumns, wrap ToggleHiddenColumns ) )

ToggleIncomingRows dropdown column relations ->
if Dict.isEmpty column.linkedBy && openedDropdown /= dropdown then
Expand All @@ -245,11 +254,11 @@ update toggleDropdown showToast now project sources openedDropdown msg model =
sqlQuery =
DbQuery.incomingRows dbSrc.db.kind relations { table = model.table, primaryKey = model.primaryKey }
in
( model, Cmd.batch [ toggleDropdown dropdown |> T.send, Ports.runDatabaseQuery (dbPrefix ++ "/" ++ String.fromInt model.id ++ "/" ++ column.pathStr) dbSrc.db.url sqlQuery ] )
( model, Extra.cmdL [ toggleDropdown dropdown |> T.send, Ports.runDatabaseQuery (dbPrefix ++ "/" ++ String.fromInt model.id ++ "/" ++ column.pathStr) dbSrc.db.url sqlQuery ] )
)

else
( model, toggleDropdown dropdown |> T.send )
( model, toggleDropdown dropdown |> Extra.msg )

GotIncomingRows column result ->
let
Expand All @@ -258,20 +267,20 @@ update toggleDropdown showToast now project sources openedDropdown msg model =
result.result |> Result.fold (\_ -> Dict.empty) (.rows >> List.head >> Maybe.mapOrElse (Dict.mapBoth TableId.parse parsePks) Dict.empty)
in
( model |> mapState (mapSuccess (mapColumns (List.mapBy .path column (\c -> { c | linkedBy = linkedBy }))))
, result.result |> Result.fold (\err -> Toasts.error ("Can't get incoming rows: " ++ err) |> showToast |> T.send) (\_ -> Cmd.none)
, result.result |> Result.fold (\err -> "Can't get incoming rows: " ++ err |> Toasts.error |> showToast |> Extra.msg) (\_ -> Extra.none)
)


withDbSource : (Toasts.Msg -> msg) -> List Source -> Model -> (DbSourceInfo -> ( Model, Cmd msg )) -> ( Model, Cmd msg )
withDbSource : (Toasts.Msg -> msg) -> List Source -> Model -> (DbSourceInfo -> ( Model, Extra msg )) -> ( Model, Extra msg )
withDbSource showToast sources model f =
sources
|> List.findBy .id model.source
|> Maybe.map
(DbSourceInfo.fromSource
>> Maybe.map f
>> Maybe.withDefault ( model, Toasts.error "Can't refresh row, source is not a database." |> showToast |> T.send )
>> Maybe.withDefault ( model, "Can't refresh row, source is not a database." |> Toasts.error |> showToast |> Extra.msg )
)
|> Maybe.withDefault ( model, Toasts.error "Can't refresh row, source not found." |> showToast |> T.send )
|> Maybe.withDefault ( model, "Can't refresh row, source not found." |> Toasts.error |> showToast |> Extra.msg )


parsePks : DbValue -> List RowPrimaryKey
Expand Down Expand Up @@ -320,6 +329,16 @@ mapStateLoading f row =
row


mapStateLoadingTM : (TableRow.LoadingState -> ( State, Maybe a )) -> TableRow -> ( TableRow, Maybe a )
mapStateLoadingTM f row =
case row.state of
StateLoading s ->
f s |> Tuple.mapFirst (\res -> { row | state = res })

_ ->
( row, Nothing )


mapLoading : (TableRow.LoadingState -> TableRow.LoadingState) -> State -> State
mapLoading f state =
case state of
Expand Down Expand Up @@ -419,7 +438,7 @@ viewHeader wrap noop toggleDropdown createContextMenu selectItem showTable delet

dropdown : Html msg
dropdown =
TableRowContextMenu.view (wrap Refresh) openNotes (wrap Collapse) (wrap Expand) delete platform conf defaultSchema row notes
TableRowContextMenu.view (wrap Refresh) openNotes (SetCollapsed >> wrap) delete platform conf defaultSchema row notes

tableLabel : String
tableLabel =
Expand Down Expand Up @@ -470,7 +489,7 @@ viewLoading wrap delete res =
, viewQuery "mt-2 px-3 py-2 text-sm" res.query
, div [ class "mt-6 flex justify-around" ]
[ Button.white1 Tw.indigo [ onClick (Cancel |> wrap), title "Cancel fetching data" ] [ text "Cancel" ]
, res.previous |> Maybe.map (\p -> Button.white1 Tw.emerald [ onClick (Restore p |> wrap), title "Restore previous data" ] [ text "Restore" ]) |> Maybe.withDefault (text "")
, res.previous |> Maybe.map (\p -> Button.white1 Tw.emerald [ onClick (StateSuccess p |> SetState |> wrap), title "Restore previous data" ] [ text "Restore" ]) |> Maybe.withDefault (text "")
, Button.white1 Tw.red [ onClick delete, title "Remove this row" ] [ text "Delete" ]
]
]
Expand All @@ -485,7 +504,7 @@ viewFailure wrap delete res =
, viewQuery "mt-1 px-3 py-2" res.query
, div [ class "mt-6 flex justify-around" ]
[ Button.white1 Tw.indigo [ onClick (Refresh |> wrap), title "Retry fetching data" ] [ text "Refresh" ]
, res.previous |> Maybe.map (\p -> Button.white1 Tw.emerald [ onClick (Restore p |> wrap), title "Restore previous data" ] [ text "Restore" ]) |> Maybe.withDefault (text "")
, res.previous |> Maybe.map (\p -> Button.white1 Tw.emerald [ onClick (StateSuccess p |> SetState |> wrap), title "Restore previous data" ] [ text "Restore" ]) |> Maybe.withDefault (text "")
, Button.white1 Tw.red [ onClick delete, title "Remove this row" ] [ text "Delete" ]
]
]
Expand Down Expand Up @@ -718,7 +737,7 @@ viewColumnRowIncomingRows noop showTableRow openDataExplorer defaultSchema sourc
, action = showTableRow source { table = tableId, primaryKey = r } Nothing (Just (PositionHint.PlaceRight row.position row.size))
}
)
|> List.add { label = "See all", action = openDataExplorer (Just source.id) (Just (DbQuery.filterTable source.db.kind { table = tableId, filters = query.foreignKeys |> List.map (\( fk, _ ) -> TableFilter DbOr fk DbEqual rowColumn.value) })) }
|> List.insert { label = "See all", action = openDataExplorer (Just source.id) (Just (DbQuery.filterTable source.db.kind { table = tableId, filters = query.foreignKeys |> List.map (\( fk, _ ) -> TableFilter DbOr fk DbEqual rowColumn.value) })) }
)
ContextMenu.BottomRight
}
Expand Down Expand Up @@ -1008,7 +1027,7 @@ docRelation ( fromSchema, fromTable, fromColumn ) ( toSchema, toTable, toColumn

docUpdate : DocState -> (DocState -> Model) -> (DocState -> Model -> DocState) -> Msg -> ElmBook.Msg (SharedDocState x)
docUpdate s get set msg =
s |> get |> update (docToggleDropdown s) docShowToast Time.zero ProjectInfo.zero [ docSource ] s.openedDropdown msg |> Tuple.first |> set s |> docSetState
s |> get |> update (\_ -> logAction "msg") (docToggleDropdown s) docShowToast docDelete docUnDelete Time.zero ProjectInfo.zero [ docSource ] s.openedDropdown msg |> Tuple.first |> set s |> docSetState


docSetState : DocState -> ElmBook.Msg (SharedDocState x)
Expand Down Expand Up @@ -1069,6 +1088,11 @@ docDelete =
logAction "delete"


docUnDelete : TableRow -> ElmBook.Msg state
docUnDelete _ =
logAction "unDelete"


docOpenNotes : TableId -> Maybe ColumnPath -> ElmBook.Msg state
docOpenNotes _ _ =
logAction "openNotes"
Expand Down
Loading
Loading