Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions shared/src/logseq/core/core_effect.ml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ let request ~now ~fresh_id payload =
| "set-page-favorite" -> let* uuid = text () in let* value = integer fields "value" in
json "setPageFavorite" (["pageUuid", `String uuid; "favorite", `Bool (value = 1)] @ operation ())
| "delete-page" -> let* uuid = text () in json "deletePage" (("pageUuid", `String uuid) :: operation ())
| "delete-block" -> let* uuid = text () in let* cursor = integer fields "value" in
json "deleteBlock" (["uuid", `String uuid; "expectedServerT", `Int cursor] @ operation ())
| "review-flashcard" -> let* uuid = string fields "uuid" in let* rating = text () in
json "reviewFlashcard" (["uuid", `String uuid; "rating", `String rating] @ operation ())
| "tap-outliner-block" -> text_event "tapBlock" "uuid"
Expand Down
65 changes: 40 additions & 25 deletions shared/src/logseq/model.ml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type sidebar_page =
; title : string
}

type node_deletion = PageToDelete of sidebar_page | BlockToDelete of sidebar_page

type ui_session =
{ graph_id : string option
; destination : primary_destination
Expand Down Expand Up @@ -298,6 +300,7 @@ type logseq_effect =
| PresentPageShareEffect of int * string * string list
| SetPageFavoriteEffect of int * string * bool
| DeletePageEffect of int * string
| DeleteBlockEffect of int * string * int
| SyncNowEffect of int
| SyncPendingEffect of int
| SetOutlinerTaskStatusEffect of int * string * task_status
Expand Down Expand Up @@ -399,7 +402,7 @@ type logseq_model =
; new_graph_password_required : bool
; new_graph_encrypted : bool
; pending_graph_deletion : graph option
; pending_page_deletion : sidebar_page option
; pending_node_deletion : node_deletion option
; pending_sign_out : bool
; connection_menu_open : bool
; settings_open : bool
Expand Down Expand Up @@ -579,9 +582,9 @@ type logseq_action =
| CloseConnectionMenu
| ToggleActivePageFavorite
| ShareActivePage
| RequestDeleteActivePage
| CancelDeleteActivePage
| ConfirmDeleteActivePage
| RequestDeleteActiveNode
| CancelDeleteActiveNode
| ConfirmDeleteActiveNode
| OpenSyncDetails
| CloseSyncDetails
| SyncNow
Expand Down Expand Up @@ -762,7 +765,7 @@ let initial () =
new_graph_password_required = false;
new_graph_encrypted = true;
pending_graph_deletion = None;
pending_page_deletion = None;
pending_node_deletion = None;
pending_sign_out = false;
connection_menu_open = false;
settings_open = false;
Expand Down Expand Up @@ -878,7 +881,7 @@ let effect_id eff =
| PresentAssetEffect (id, _, _, _) -> id
| PresentPageShareEffect (id, _, _) -> id
| SetPageFavoriteEffect (id, _, _) -> id
| DeletePageEffect (id, _) -> id
| DeletePageEffect (id, _) | DeleteBlockEffect (id, _, _) -> id
| SyncNowEffect id -> id
| SyncPendingEffect id -> id
| SetOutlinerTaskStatusEffect (id, _, _) -> id
Expand Down Expand Up @@ -1448,7 +1451,17 @@ let node_permission (current : logseq_model) uuid permission =
List.assoc_opt permission fields <> Some (`Bool false)
| _ -> true

let page_can_delete current uuid = node_permission current uuid "canDelete"
let active_delete_target (current : logseq_model) =
let routes = if current.search_open then
app_node_routes_from current current.search_navigation_path 0
else app_node_routes current in
match last_opt routes with
| Some route when route.node_uuid <> route.node_page_uuid ->
if current.applied_server_t <> None && node_permission current route.node_uuid "canDelete" then
Some (BlockToDelete {uuid = route.node_uuid; title = route.node_title})
else None
| _ -> Option.bind (active_page current) (fun page ->
if node_permission current page.uuid "canDelete" then Some (PageToDelete page) else None)
let node_can_set_tags current uuid = node_permission current uuid "canAdd"

let page_is_favorite_ (current : logseq_model) uuid =
Expand Down Expand Up @@ -1675,6 +1688,11 @@ let search_query_ready query = String.trim query <> ""

let resolve_successful_effect (current : logseq_model) eff message =
match eff with
| DeleteBlockEffect (_, uuid, _) ->
let path = if current.search_open then current.search_navigation_path else current.app_navigation_path in
if Option.map navigation_route_uuid (last_opt path) <> Some uuid then current
else if current.search_open then back_search_navigation current 1
else back_app_navigation current 1
| MaintainSearchIndexEffect (_, graph_id) ->
let ready = try
let open Yojson.Basic.Util in
Expand Down Expand Up @@ -2848,23 +2866,19 @@ let rec update (current : logseq_model) action =
, page_share_text page current.outliner_rows
, page_share_asset_paths current.outliner_rows ))
| None -> current)
| RequestDeleteActivePage ->
(match active_page current with
| Some page when page_can_delete current page.uuid ->
{
current with
connection_menu_open = false;
pending_page_deletion = Some page;
}
| _ -> current)
| CancelDeleteActivePage ->
{ current with pending_page_deletion = None }
| ConfirmDeleteActivePage ->
(match current.pending_page_deletion with
| Some page when not (page_can_delete current page.uuid) ->
{ current with pending_page_deletion = None }
| Some page ->
let updated = { current with pending_page_deletion = None } in
| RequestDeleteActiveNode ->
(match active_delete_target current with
| Some target -> {current with connection_menu_open = false; pending_node_deletion = Some target}
| None -> current)
| CancelDeleteActiveNode ->
{ current with pending_node_deletion = None }
| ConfirmDeleteActiveNode ->
let target = current.pending_node_deletion in
let updated = {current with pending_node_deletion = None} in
(match target, active_delete_target current, current.applied_server_t with
| Some (BlockToDelete block), Some (BlockToDelete active), Some cursor when block.uuid = active.uuid ->
enqueue_effect updated (DeleteBlockEffect (updated.next_effect_id, block.uuid, cursor))
| Some (PageToDelete page), Some (PageToDelete active), _ when page.uuid = active.uuid ->
let delete_id = updated.next_effect_id in
let deleting =
enqueue_effect updated (DeletePageEffect (delete_id, page.uuid))
Expand All @@ -2886,7 +2900,7 @@ let rec update (current : logseq_model) action =
enqueue_effect closed
(CloseAppNodeEffect (close_id, navigation_route_uuid route))
end
| None -> current)
| _ -> updated)
| OpenJournalCalendar -> enqueue_effect current (PresentJournalCalendarEffect current.next_effect_id)
| OpenSettings ->
{
Expand Down Expand Up @@ -3327,6 +3341,7 @@ and apply_core_snapshot (current : logseq_model)
else SyncedState
else OfflineState);
applied_server_t = projection.applied_server_t;
pending_node_deletion = (if selected_graph_changed then None else current.pending_node_deletion);
has_pending_semantic_operations =
projection.has_pending_semantic_operations;
has_pending_sync_request = projection.has_pending_sync_request;
Expand Down
13 changes: 8 additions & 5 deletions shared/src/logseq/model.mli
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type sidebar_page =
; title : string
}

type node_deletion = PageToDelete of sidebar_page | BlockToDelete of sidebar_page

type ui_session =
{ graph_id : string option
; destination : primary_destination
Expand Down Expand Up @@ -295,6 +297,7 @@ type logseq_effect =
| PresentPageShareEffect of int * string * string list
| SetPageFavoriteEffect of int * string * bool
| DeletePageEffect of int * string
| DeleteBlockEffect of int * string * int
| SyncNowEffect of int
| SyncPendingEffect of int
| SetOutlinerTaskStatusEffect of int * string * task_status
Expand Down Expand Up @@ -396,7 +399,7 @@ type logseq_model =
; new_graph_password_required : bool
; new_graph_encrypted : bool
; pending_graph_deletion : graph option
; pending_page_deletion : sidebar_page option
; pending_node_deletion : node_deletion option
; pending_sign_out : bool
; connection_menu_open : bool
; settings_open : bool
Expand Down Expand Up @@ -576,9 +579,9 @@ type logseq_action =
| CloseConnectionMenu
| ToggleActivePageFavorite
| ShareActivePage
| RequestDeleteActivePage
| CancelDeleteActivePage
| ConfirmDeleteActivePage
| RequestDeleteActiveNode
| CancelDeleteActiveNode
| ConfirmDeleteActiveNode
| OpenSyncDetails
| CloseSyncDetails
| SyncNow
Expand Down Expand Up @@ -706,7 +709,7 @@ val indexed_outliner_autocomplete_candidates :
val valid_authentication_state_ : string -> bool
val current_settings : logseq_model -> settings_projection
val active_page : logseq_model -> sidebar_page option
val page_can_delete : logseq_model -> string -> bool
val active_delete_target : logseq_model -> node_deletion option
val node_can_set_tags : logseq_model -> string -> bool
val page_is_favorite_ : logseq_model -> string -> bool
val page_share_text : sidebar_page -> outline_row list -> string
Expand Down
3 changes: 3 additions & 0 deletions shared/src/logseq/native_bridge.ml
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ let encode_effect (eff : Model.logseq_effect) =
| DeletePageEffect (id, uuid) ->
"{\"id\":" ^ string_of_int id ^ ",\"kind\":\"delete-page\",\"text\":"
^ Lui_wire.quoted uuid ^ "}"
| DeleteBlockEffect (id, uuid, cursor) ->
Yojson.Basic.to_string (`Assoc ["id", `Int id; "kind", `String "delete-block";
"text", `String uuid; "value", `Int cursor])
| PdfAnnotationEffect (id, payload) ->
Yojson.Basic.to_string (`Assoc ["id", `Int id; "kind", `String "pdf-annotation"; "text", `String payload])
| ResultViewEffect (id, _, payload) ->
Expand Down
4 changes: 2 additions & 2 deletions shared/src/logseq/view_base.ml
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ let active_page_favorite_label (current : Model.logseq_model) =
else "Favorite"
| None -> "Favorite"

let page_deletion_pending_ (current : Model.logseq_model) =
current.pending_page_deletion <> None
let node_deletion_pending_ (current : Model.logseq_model) =
current.pending_node_deletion <> None

let sign_out_pending_ (current : Model.logseq_model) =
current.pending_sign_out
Expand Down
2 changes: 1 addition & 1 deletion shared/src/logseq/view_base.mli
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ val sync_cursor_label : Model.logseq_model -> string
val active_page_actions_visible_ : Model.logseq_model -> bool
val connection_settings_visible_ : Model.logseq_model -> bool
val active_page_favorite_label : Model.logseq_model -> string
val page_deletion_pending_ : Model.logseq_model -> bool
val node_deletion_pending_ : Model.logseq_model -> bool
val sign_out_pending_ : Model.logseq_model -> bool
val sidebar_page_identifier : Model.sidebar_page -> string
val sidebar_page_title : Model.sidebar_page -> string
Expand Down
24 changes: 13 additions & 11 deletions shared/src/logseq/view_screens.ml
Original file line number Diff line number Diff line change
Expand Up @@ -568,15 +568,17 @@ let active_overflow_menu model_source send : t =
(menu_item ~text:(View_base.tr (Signal.sample model_source) "Share") ?icon:(item_icon "share")
~on_press:(press send Model.ShareActivePage)
[]);
if_ ~test:(Signal.map (fun current ->
match Model.active_page current with
| Some page -> Model.page_can_delete current page.uuid
| None -> false) model_source)
(menu_item ~text:(View_base.tr (Signal.sample model_source) "Delete") ~variant:`destructive
~accessibility_identifier:"button.page.delete"
?icon:(item_icon "toolbar-delete")
~on_press:(press send Model.RequestDeleteActivePage)
[]);
keyed ~source:(own (Signal.map (fun model -> Option.to_list (Model.active_delete_target model)) model_source))
~key:(function Model.BlockToDelete _ -> `Block | Model.PageToDelete _ -> `Page) ~cmp:compare
~mount:(fun source -> match Signal.sample source with
| Model.BlockToDelete _ ->
menu_item ~text:(View_base.tr (Signal.sample model_source) "Delete block") ~variant:`destructive
~accessibility_identifier:"button.block.delete" ?icon:(item_icon "toolbar-delete")
~on_press:(press send Model.RequestDeleteActiveNode) []
| Model.PageToDelete _ ->
menu_item ~text:(View_base.tr (Signal.sample model_source) "Delete") ~variant:`destructive
~accessibility_identifier:"button.page.delete" ?icon:(item_icon "toolbar-delete")
~on_press:(press send Model.RequestDeleteActiveNode) []);
if_ ~test:settings_source
(menu_item ~text:(View_base.tr (Signal.sample model_source) "Settings") ?icon:(item_icon "settings")
~on_press:(press send Model.OpenSettings)
Expand Down Expand Up @@ -984,7 +986,7 @@ let application_main_content (context : Lui_ui.ui_context) model_source
model_source)
(View_graphs.graph_password_sheet context model_source send);
if_
~test:(Signal.map View_base.page_deletion_pending_ model_source)
~test:(Signal.map View_base.node_deletion_pending_ model_source)
(View_settings.page_delete_dialog model_source context send);
if_
~test:(Signal.map View_base.sign_out_pending_ model_source)
Expand Down Expand Up @@ -1029,7 +1031,7 @@ let application_main_content (context : Lui_ui.ui_context) model_source
model_source)
(View_graphs.graph_password_sheet context model_source send);
if_
~test:(Signal.map View_base.page_deletion_pending_ model_source)
~test:(Signal.map View_base.node_deletion_pending_ model_source)
(View_settings.page_delete_dialog model_source context send);
if_
~test:(Signal.map View_base.sign_out_pending_ model_source)
Expand Down
25 changes: 15 additions & 10 deletions shared/src/logseq/view_settings.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1172,14 +1172,19 @@ let settings_sheet (context : Lui_ui.ui_context) model_source send : t =
else settings_main_sheet context model_source send

let page_delete_dialog model_source (context : Lui_ui.ui_context) send : t =
let label page block = Signal.map (fun (model : Model.logseq_model) ->
View_base.tr model (match model.pending_node_deletion with
| Some (Model.BlockToDelete _) -> block | _ -> page)) model_source in
let title = label "Delete page?" "Delete block?" in
let description = label "The page will be moved to Recycle." "The block and its children will be deleted." in
if Lui_ui.host context = KotlinHost then
dialog ~text:(View_base.tr (Signal.sample model_source) "Delete page?") ~height:280
dialog ~text_signal:title ~height:280
~accessibility_identifier:"dialog.page-delete"
~on_dismiss:(press send Model.CancelDeleteActivePage)
~on_dismiss:(press send Model.CancelDeleteActiveNode)
[
column ~gap:16 ~cross:`stretch
[
text ~value:(View_base.tr (Signal.sample model_source) "The page will be moved to Recycle.") ~grow:1.0 [];
text ~value_signal:description ~grow:1.0 [];
spacer ~grow:1.0 [];
row ~main:`end_
[
Expand All @@ -1190,12 +1195,12 @@ let page_delete_dialog model_source (context : Lui_ui.ui_context) send : t =
button ~variant:`ghost ~style_class:"cancellation-action"
~accessibility_identifier:
"button.page-delete.cancel"
~on_press:(press send Model.CancelDeleteActivePage)
~on_press:(press send Model.CancelDeleteActiveNode)
~text:(View_base.tr (Signal.sample model_source) "Cancel") [];
button ~variant:`destructive
~accessibility_identifier:
"button.page-delete.confirm"
~on_press:(press send Model.ConfirmDeleteActivePage)
~on_press:(press send Model.ConfirmDeleteActiveNode)
~text:(View_base.tr (Signal.sample model_source) "Delete") [];
];
];
Expand All @@ -1204,18 +1209,18 @@ let page_delete_dialog model_source (context : Lui_ui.ui_context) send : t =
else
(* Text-and-buttons-only children keep the dialog on the native alert
path (rich children fall back to a custom sheet). *)
dialog ~text:(View_base.tr (Signal.sample model_source) "Delete page?") ~style_class:"alert"
dialog ~text_signal:title ~style_class:"alert"
~accessibility_identifier:"dialog.page-delete"
~on_dismiss:(press send Model.CancelDeleteActivePage)
~on_dismiss:(press send Model.CancelDeleteActiveNode)
[
text ~value:(View_base.tr (Signal.sample model_source) "The page will be moved to Recycle.") [];
text ~value_signal:description [];
button ~style_class:"cancellation-action"
~accessibility_identifier:"button.page-delete.cancel"
~on_press:(press send Model.CancelDeleteActivePage)
~on_press:(press send Model.CancelDeleteActiveNode)
~text:(View_base.tr (Signal.sample model_source) "Cancel") [];
button ~variant:`destructive
~accessibility_identifier:"button.page-delete.confirm"
~on_press:(press send Model.ConfirmDeleteActivePage)
~on_press:(press send Model.ConfirmDeleteActiveNode)
~text:(View_base.tr (Signal.sample model_source) "Delete") [];
]

Expand Down
Loading
Loading