aboutsummaryrefslogtreecommitdiff
path: root/pearl.el
diff options
context:
space:
mode:
Diffstat (limited to 'pearl.el')
-rw-r--r--pearl.el106
1 files changed, 93 insertions, 13 deletions
diff --git a/pearl.el b/pearl.el
index 9dfc2ef..cb65ab3 100644
--- a/pearl.el
+++ b/pearl.el
@@ -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))