diff options
Diffstat (limited to 'pearl.el')
| -rw-r--r-- | pearl.el | 106 |
1 files changed, 93 insertions, 13 deletions
@@ -1182,6 +1182,31 @@ query takes. CALLBACK is invoked with a plist :error (format "%s" error)))))) (pearl--graphql-request-async query variables success-fn error-fn))) +(defun pearl--customview-delete-async (view-id callback) + "Delete a Custom View on Linear by VIEW-ID. +CALLBACK is invoked with a plist +`(:success BOOL :error STRING-OR-NIL)'. Linear's `customViewDelete' is +a soft delete that drops the view into the workspace trash (recoverable +within Linear's standard window)." + (let* ((query "mutation CustomViewDelete($id: String!) { + customViewDelete(id: $id) { + success + } +}") + (variables `(("id" . ,view-id))) + (success-fn + (lambda (response) + (let* ((cvd (cdr (assoc 'customViewDelete + (cdr (assoc 'data response))))) + (success (eq t (cdr (assoc 'success cvd))))) + (funcall callback (list :success success))))) + (error-fn + (lambda (error _response _data) + (funcall callback + (list :success nil + :error (format "%s" error)))))) + (pearl--graphql-request-async query variables success-fn error-fn))) + (defun pearl--customview-update-async (view-id update-input callback) "Update a Custom View on Linear by VIEW-ID. UPDATE-INPUT is an alist of `CustomViewUpdateInput' fields -- any subset @@ -3560,13 +3585,27 @@ an id), or `pearl--filter-any' (any assignee, no scoping)." :test #'string=)))) open state project labels assignee))) +(defun pearl--delete-saved-query-local (name) + "Remove NAME from `pearl-saved-queries' and persist via Customize. +The unconditional persistence path shared by the local-only delete and +the synced-entry unlink branch." + (setq pearl-saved-queries + (cl-remove name pearl-saved-queries :key #'car :test #'string=)) + (customize-save-variable 'pearl-saved-queries pearl-saved-queries)) + ;;;###autoload (defun pearl-delete-saved-query (name) "Delete the saved query NAME from `pearl-saved-queries' after confirmation. Interactively, completes over the configured query names with -`pearl--filter-cancel' at the top. Local-only: removes the entry from -the customized list and persists via `customize-save-variable'. Linear -is untouched (saved queries are local; syncing them up is a separate spec)." +`pearl--filter-cancel' at the top. Local-only entries are removed from +the customized list and persisted via `customize-save-variable'; entries +that carry a `:linear-view-id' (i.e. were synced up to Linear) trigger a +second yes-or-no prompt for whether to also delete the linked Linear +view (=customViewDelete=). Picking NO at the second prompt unlinks the +entry but leaves the Linear view in place; picking YES calls +=customViewDelete= and, on API failure, asks whether to drop the local +entry anyway (which leaves the Linear view orphaned -- the message names +the id so it can be deleted by hand)." (interactive (list (if (null pearl-saved-queries) (user-error "No saved queries to delete") @@ -3581,12 +3620,53 @@ is untouched (saved queries are local; syncing them up is a separate spec)." (message "Cancelled; no saved query deleted")) ((not (assoc name pearl-saved-queries)) (user-error "No saved query named %s" name)) - ((yes-or-no-p (format "Delete saved query %s? " name)) - (setq pearl-saved-queries - (cl-remove name pearl-saved-queries :key #'car :test #'string=)) - (customize-save-variable 'pearl-saved-queries pearl-saved-queries) - (message "Deleted saved query %s" name)) - (t (message "Kept saved query %s" name)))) + ((not (yes-or-no-p (format "Delete saved query %s? " name))) + (message "Kept saved query %s" name)) + (t + (let ((view-id (plist-get (cdr (assoc name pearl-saved-queries)) + :linear-view-id))) + (cond + ;; Local-only entry: unchanged behavior. + ((null view-id) + (pearl--delete-saved-query-local name) + (message "Deleted saved query %s" name)) + ;; Synced entry: ask whether to also drop the Linear view. + ((yes-or-no-p + (format "Also delete the linked Linear view (\"%s\")? " name)) + (pearl--delete-saved-query-do-linear-delete name view-id)) + (t + ;; Unlink only: drop the local entry, leave the Linear view alone. + (pearl--delete-saved-query-local name) + (message "Deleted saved query %s; Linear view kept (id %s)" + name view-id))))))) + +(defun pearl--delete-saved-query-do-linear-delete (name view-id) + "Call customViewDelete on VIEW-ID and remove NAME locally on success. +On API failure, ask whether to drop the local entry anyway; if accepted, +the message names the orphan view id so the user can delete it in Linear +by hand." + (pearl--progress "Deleting Linear view for %s..." name) + (let* ((result (pearl--sync-saved-query-await + #'pearl--customview-delete-async view-id)) + (success (plist-get result :success))) + (cond + (success + (pearl--delete-saved-query-local name) + (message "Deleted saved query %s and removed view from Linear" name)) + ((plist-get result :timeout) + (message + "Delete of Linear view for %s timed out after %ds; saved query left in place -- the delete may still have completed (view id %s) -- re-run after the network recovers." + name pearl-request-timeout view-id)) + ((yes-or-no-p + (format + "Linear delete failed (%s). Drop the local entry anyway? " + (or (plist-get result :error) "unknown error"))) + (pearl--delete-saved-query-local name) + (message + "Deleted saved query %s; Linear view is orphaned (id %s, delete manually)" + name view-id)) + (t + (message "Kept saved query %s; Linear view also untouched" name))))) (defun pearl--save-query (name filter-plist &optional sort order) "Save FILTER-PLIST as the saved query NAME, replacing any entry of that NAME. @@ -3753,10 +3833,10 @@ Returns one of the symbols `replace', `rename', `cancel'." (defun pearl--sync-saved-query-await (async-fn &rest args) "Run the async helper ASYNC-FN with ARGS, busy-waiting for its callback. -ASYNC-FN is one of `pearl--customview-create-async' / -`pearl--customview-update-async' -- both end by invoking a callback -appended to ARGS with a result plist. Returns that plist on completion, -or `(:success nil :timeout t)' if the wait elapsed without the callback +ASYNC-FN is one of the `pearl--customview-*-async' helpers (create, +update, or delete) -- each ends by invoking a callback appended to ARGS +with a result plist. Returns that plist on completion, or +`(:success nil :timeout t)' if the wait elapsed without the callback firing -- callers can distinguish a timeout from a Linear-side rejection so the user isn't told the API refused something that never reached it." (let ((done nil) (result nil)) |
