paperclip-github-plugin 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,7 +34,7 @@ The plugin adds a full in-host workflow instead of a one-off import script:
34
34
  - saved sync diagnostics that let operators inspect the latest per-issue failures, raw errors, and suggested next steps
35
35
  - a project sidebar item that opens a live project-scoped Pull Requests page for the mapped repository and can show the open PR count through a lightweight badge read
36
36
  - manual sync actions from global, project, and issue toolbar surfaces
37
- - a GitHub detail tab on synced Paperclip issues
37
+ - a GitHub detail tab on synced Paperclip issues that stays hidden for Paperclip issues with no linked GitHub issue
38
38
  - GitHub link annotations on sync-generated status transition comments when the host supports comment annotations
39
39
 
40
40
  ## How it works
@@ -47,7 +47,7 @@ During sync, the plugin imports one top-level Paperclip issue per GitHub issue,
47
47
 
48
48
  When the host exposes plugin issue creation, imported GitHub issues are created through the Paperclip plugin SDK path so they are not attributed to the connected board user. The worker still uses direct local Paperclip REST calls for label sync and for description or status repair paths when those routes are available.
49
49
 
50
- Long-running syncs continue in the background, so quick actions do not have to wait for the whole import to finish. Once a sync has started, the settings page, dashboard widget, and toolbar actions can request cancellation; the worker stops cooperatively after the current repository or issue step finishes.
50
+ Long-running syncs continue in the background, so quick actions do not have to wait for the whole import to finish. Once a sync has started, the settings page, dashboard widget, and toolbar actions can request cancellation; the worker stops cooperatively after the current repository or issue step finishes. If the worker restarts mid-run, GitHub Sync now recovers that orphaned `running` state on the next read or control action instead of leaving the UI stuck in `running` or silently restarting the old run.
51
51
 
52
52
  ## Highlights
53
53
 
@@ -203,6 +203,7 @@ Current host caveat: on authenticated Paperclip deployments, the Paperclip host
203
203
  - If a GitHub-linked project does not show the **Pull requests** sidebar entry, reopen the plugin settings and re-save the mapping. The project pull request surfaces also recover older mappings when saved ids are missing, and they can fall back to the active project's bound GitHub repository when the project already has a GitHub workspace configured.
204
204
  - If GitHub rate limiting is hit, the plugin pauses sync until the reported reset time instead of retrying pointlessly.
205
205
  - If a manual sync takes longer than the host action window, it continues in the background and updates the UI when it finishes or when a cancellation request stops it.
206
+ - If a sync shows `running` after the worker has restarted, the next settings read, toolbar read, cancel action, or scheduler tick will reconcile that stale run into an interrupted error or a cancelled result so you can retry cleanly.
206
207
 
207
208
  ## Development
208
209
 
package/dist/manifest.js CHANGED
@@ -511,7 +511,7 @@ var require2 = createRequire(import.meta.url);
511
511
  var packageJson = require2("../package.json");
512
512
  var DASHBOARD_WIDGET_CAPABILITY = "ui.dashboardWidget.register";
513
513
  var SCHEDULE_TICK_CRON = "* * * * *";
514
- var MANIFEST_VERSION = "0.4.5"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
514
+ var MANIFEST_VERSION = "0.4.6"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
515
515
  var manifest = {
516
516
  id: "paperclip-github-plugin",
517
517
  apiVersion: 1,
package/dist/ui/index.js CHANGED
@@ -23091,6 +23091,21 @@ function getActiveRateLimitPause(syncState, referenceTimeMs = Date.now()) {
23091
23091
  function isSyncCancellationRequested(syncState) {
23092
23092
  return syncState.status === "running" && Boolean(syncState.cancelRequestedAt?.trim());
23093
23093
  }
23094
+ function resolveToolbarButtonState(params) {
23095
+ const syncPersistedRunning = params.syncState.status === "running";
23096
+ const syncStartPending = params.runningSync && !syncPersistedRunning;
23097
+ const cancellationRequested = syncPersistedRunning && (params.cancellingSync || isSyncCancellationRequested(params.syncState));
23098
+ const loadingVisible = params.loading && !syncPersistedRunning;
23099
+ return {
23100
+ busy: loadingVisible || syncStartPending || cancellationRequested || !params.allowToolbarCancellation && syncPersistedRunning,
23101
+ disabled: loadingVisible || syncStartPending || (syncPersistedRunning ? params.allowToolbarCancellation ? cancellationRequested : true : !params.effectiveCanRun),
23102
+ label: syncPersistedRunning && params.allowToolbarCancellation ? "Cancel sync" : params.effectiveLabel,
23103
+ busyLabel: syncPersistedRunning ? cancellationRequested ? "Cancelling\u2026" : "Syncing\u2026" : loadingVisible ? "Loading\u2026" : "Syncing\u2026",
23104
+ cancellationRequested,
23105
+ syncPersistedRunning,
23106
+ syncStartPending
23107
+ };
23108
+ }
23094
23109
  function getSyncToastTitle(syncState) {
23095
23110
  if (getActiveRateLimitPause(syncState)) {
23096
23111
  return "GitHub sync is paused";
@@ -33162,13 +33177,25 @@ function GitHubSyncToolbarButtonSurface(props) {
33162
33177
  const effectiveCanRun = state.canRun && !boardAccessSetupIssue;
33163
33178
  const effectiveMessage = boardAccessSetupIssue ? getSyncSetupMessage(boardAccessSetupIssue, hasCompanyContext) : state.message;
33164
33179
  const effectiveLabel = boardAccessSetupIssue ? "Board access required" : state.label;
33165
- const syncPersistedRunning = effectiveSyncState.status === "running";
33166
- const syncStartPending = runningSync && !syncPersistedRunning;
33167
33180
  const allowToolbarCancellation = Boolean(props.entityType);
33168
- const cancellationRequested = syncPersistedRunning && (cancellingSync || isSyncCancellationRequested(effectiveSyncState));
33169
- const toolbarButtonBusy = toolbarState.loading || syncStartPending || cancellationRequested || !allowToolbarCancellation && syncPersistedRunning;
33170
- const toolbarButtonLabel = syncPersistedRunning && allowToolbarCancellation ? "Cancel sync" : effectiveLabel;
33171
- const toolbarButtonBusyLabel = toolbarState.loading ? "Loading\u2026" : syncPersistedRunning ? cancellationRequested ? "Cancelling\u2026" : "Syncing\u2026" : "Syncing\u2026";
33181
+ const toolbarButtonState = resolveToolbarButtonState({
33182
+ loading: toolbarState.loading,
33183
+ runningSync,
33184
+ cancellingSync,
33185
+ syncState: effectiveSyncState,
33186
+ allowToolbarCancellation,
33187
+ effectiveCanRun,
33188
+ effectiveLabel
33189
+ });
33190
+ const {
33191
+ busy: toolbarButtonBusy,
33192
+ disabled: toolbarButtonDisabled,
33193
+ label: toolbarButtonLabel,
33194
+ busyLabel: toolbarButtonBusyLabel,
33195
+ syncPersistedRunning,
33196
+ syncStartPending,
33197
+ cancellationRequested
33198
+ } = toolbarButtonState;
33172
33199
  const armSyncCompletionToast = useSyncCompletionToast(effectiveSyncState, toast);
33173
33200
  useEffect2(() => {
33174
33201
  if (effectiveSyncState.status !== "running") {
@@ -33343,7 +33370,7 @@ function GitHubSyncToolbarButtonSurface(props) {
33343
33370
  "data-variant": "outline",
33344
33371
  "data-size": "sm",
33345
33372
  className: props.entityType ? HOST_ENTITY_BUTTON_CLASSNAME : HOST_GLOBAL_BUTTON_CLASSNAME,
33346
- disabled: toolbarState.loading || syncStartPending || (syncPersistedRunning ? allowToolbarCancellation ? cancellationRequested : true : !effectiveCanRun),
33373
+ disabled: toolbarButtonDisabled,
33347
33374
  onClick: syncPersistedRunning && allowToolbarCancellation ? handleCancelSync : handleRunSync,
33348
33375
  children: /* @__PURE__ */ jsx2(
33349
33376
  LoadingButtonContent,
@@ -33385,6 +33412,12 @@ function GitHubSyncIssueDetailTabContent(props) {
33385
33412
  ...props.issueId ? { issueId: props.issueId } : {}
33386
33413
  });
33387
33414
  const issueDetails = details.data?.paperclipIssueId === props.issueId ? details.data : null;
33415
+ const detailTabState = resolveGitHubIssueDetailTabState({
33416
+ loadingIssueId: props.loadingIssueId,
33417
+ detailsLoading: details.loading,
33418
+ detailsError: Boolean(details.error),
33419
+ issueDetails
33420
+ });
33388
33421
  useEffect2(() => {
33389
33422
  if (!props.companyId || !props.issueId) {
33390
33423
  return;
@@ -33395,12 +33428,14 @@ function GitHubSyncIssueDetailTabContent(props) {
33395
33428
  return;
33396
33429
  }
33397
33430
  }, [details.refresh, props.companyId, props.issueId]);
33431
+ if (detailTabState === "hidden") {
33432
+ return null;
33433
+ }
33398
33434
  return /* @__PURE__ */ jsxs2("section", { className: "ghsync-issue-detail", style: props.themeVars, children: [
33399
33435
  /* @__PURE__ */ jsx2("style", { children: EXTENSION_SURFACE_STYLES }),
33400
- props.loadingIssueId || details.loading && !issueDetails ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: "Loading GitHub sync details\u2026" }) : null,
33401
- details.error ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: details.error.message }) : null,
33402
- !props.loadingIssueId && !details.loading && !details.error && !issueDetails ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: "GitHub Sync has not linked this Paperclip issue to a GitHub issue yet." }) : null,
33403
- issueDetails ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
33436
+ detailTabState === "loading" ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: "Loading GitHub sync details\u2026" }) : null,
33437
+ detailTabState === "error" && details.error ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: details.error.message }) : null,
33438
+ detailTabState === "ready" && issueDetails ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
33404
33439
  /* @__PURE__ */ jsxs2("div", { className: "ghsync-extension-heading", children: [
33405
33440
  /* @__PURE__ */ jsxs2("div", { children: [
33406
33441
  /* @__PURE__ */ jsxs2("h4", { children: [
@@ -33479,6 +33514,18 @@ function GitHubSyncIssueDetailTabContent(props) {
33479
33514
  ] }) : null
33480
33515
  ] });
33481
33516
  }
33517
+ function resolveGitHubIssueDetailTabState(params) {
33518
+ if (params.loadingIssueId || params.detailsLoading && !params.issueDetails) {
33519
+ return "loading";
33520
+ }
33521
+ if (params.issueDetails) {
33522
+ return "ready";
33523
+ }
33524
+ if (params.detailsError) {
33525
+ return "error";
33526
+ }
33527
+ return "hidden";
33528
+ }
33482
33529
  function GitHubSyncIssueTaskDetailView() {
33483
33530
  const context = useHostContext();
33484
33531
  const themeMode = useResolvedThemeMode();
@@ -33553,8 +33600,10 @@ export {
33553
33600
  GitHubSyncProjectPullRequestsSidebarItem,
33554
33601
  GitHubSyncSettingsPage,
33555
33602
  index_default as default,
33603
+ resolveGitHubIssueDetailTabState,
33556
33604
  resolveOrCreateProject,
33557
33605
  resolveSavedTokenUiState,
33606
+ resolveToolbarButtonState,
33558
33607
  syncGitHubTokenPropagationForAgents
33559
33608
  };
33560
33609
  //# sourceMappingURL=index.js.map