paperclip-github-plugin 0.4.6 → 0.4.8

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
@@ -33,8 +33,8 @@ The plugin adds a full in-host workflow instead of a one-off import script:
33
33
  - a dashboard widget that shows readiness, sync status, and last-run results
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
- - manual sync actions from global, project, and issue toolbar surfaces
37
- - a GitHub detail tab on synced Paperclip issues that stays hidden for Paperclip issues with no linked GitHub issue
36
+ - manual sync actions from global, project, and issue surfaces
37
+ - a GitHub detail tab on synced Paperclip issues that stays hidden for Paperclip issues with no linked GitHub issue and includes GitHub-marked action buttons plus the GitHub issue creator with avatar
38
38
  - GitHub link annotations on sync-generated status transition comments when the host supports comment annotations
39
39
 
40
40
  ## How it works
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.6"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
514
+ var MANIFEST_VERSION = "0.4.8"?.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
@@ -22868,6 +22868,12 @@ function LoadingIconButtonContent(props) {
22868
22868
  function LoadingSkeleton(props) {
22869
22869
  return /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: ["ghsync__skeleton", props.className].filter(Boolean).join(" "), style: props.style });
22870
22870
  }
22871
+ function GitHubButtonLabel(props) {
22872
+ return /* @__PURE__ */ jsxs2("span", { className: "ghsync__button-content", children: [
22873
+ /* @__PURE__ */ jsx2(GitHubMarkIcon, { className: "ghsync-prs-icon" }),
22874
+ /* @__PURE__ */ jsx2("span", { children: props.label })
22875
+ ] });
22876
+ }
22871
22877
  var PROJECT_PULL_REQUESTS_PAGE_ROUTE_PATH = "github-pull-requests";
22872
22878
  var LIGHT_PALETTE = {
22873
22879
  text: "#18181b",
@@ -26422,6 +26428,42 @@ var EXTENSION_SURFACE_STYLES = `
26422
26428
  align-items: start;
26423
26429
  }
26424
26430
 
26431
+ .ghsync-issue-detail__actions {
26432
+ display: flex;
26433
+ flex-wrap: wrap;
26434
+ gap: 8px;
26435
+ align-items: center;
26436
+ justify-content: flex-end;
26437
+ }
26438
+
26439
+ .ghsync-issue-detail__headline {
26440
+ display: grid;
26441
+ gap: 8px;
26442
+ min-width: 0;
26443
+ }
26444
+
26445
+ .ghsync-issue-detail__creator-row {
26446
+ display: flex;
26447
+ align-items: center;
26448
+ flex-wrap: wrap;
26449
+ gap: 8px;
26450
+ }
26451
+
26452
+ .ghsync-issue-detail__creator-label {
26453
+ color: var(--ghsync-muted);
26454
+ font-size: 11px;
26455
+ font-weight: 700;
26456
+ letter-spacing: 0.08em;
26457
+ line-height: 1;
26458
+ text-transform: uppercase;
26459
+ }
26460
+
26461
+ .ghsync-issue-detail__creator .ghsync-prs-avatar {
26462
+ width: 20px;
26463
+ height: 20px;
26464
+ font-size: 10px;
26465
+ }
26466
+
26425
26467
  .ghsync-extension-heading h3,
26426
26468
  .ghsync-extension-heading h4 {
26427
26469
  margin: 0;
@@ -33133,10 +33175,9 @@ function PullRequestCopilotActionMenu(props) {
33133
33175
  );
33134
33176
  }
33135
33177
  function GitHubSyncToolbarButtonSurface(props) {
33136
- const toast = usePluginToast();
33137
- const runSyncNow = usePluginAction("sync.runNow");
33138
- const cancelSync = usePluginAction("sync.cancel");
33139
- const pluginIdFromLocation = getPluginIdFromLocation();
33178
+ const themeMode = useResolvedThemeMode();
33179
+ const theme = themeMode === "light" ? LIGHT_PALETTE : DARK_PALETTE;
33180
+ const themeVars = buildThemeVars(theme, themeMode);
33140
33181
  const surfaceRef = useRef(null);
33141
33182
  const resolvedIssue = useResolvedIssueId({
33142
33183
  companyId: props.companyId,
@@ -33144,7 +33185,70 @@ function GitHubSyncToolbarButtonSurface(props) {
33144
33185
  entityId: props.entityId,
33145
33186
  entityType: props.entityType
33146
33187
  });
33147
- const effectiveEntityId = props.entityType === "issue" ? resolvedIssue.issueId ?? "__ghsync_unresolved_issue__" : props.entityId;
33188
+ const buttonController = useGitHubSyncButtonController({
33189
+ ...props,
33190
+ resolvedIssueId: resolvedIssue.issueId
33191
+ });
33192
+ useEffect2(() => {
33193
+ if (!props.entityType) {
33194
+ return;
33195
+ }
33196
+ const hostWrapper = surfaceRef.current?.parentElement;
33197
+ if (!hostWrapper) {
33198
+ return;
33199
+ }
33200
+ const previousMarginLeft = hostWrapper.style.marginLeft;
33201
+ const previousMarginInlineStart = hostWrapper.style.marginInlineStart;
33202
+ hostWrapper.style.marginLeft = "auto";
33203
+ hostWrapper.style.marginInlineStart = "auto";
33204
+ return () => {
33205
+ hostWrapper.style.marginLeft = previousMarginLeft;
33206
+ hostWrapper.style.marginInlineStart = previousMarginInlineStart;
33207
+ };
33208
+ }, [props.entityType]);
33209
+ if (!buttonController.visible) {
33210
+ return null;
33211
+ }
33212
+ return /* @__PURE__ */ jsxs2(
33213
+ "div",
33214
+ {
33215
+ ref: surfaceRef,
33216
+ className: `ghsync-toolbar-button${props.entityType ? " ghsync-toolbar-button--entity" : ""}`,
33217
+ style: themeVars,
33218
+ title: buttonController.title,
33219
+ children: [
33220
+ /* @__PURE__ */ jsx2("style", { children: EXTENSION_SURFACE_STYLES }),
33221
+ /* @__PURE__ */ jsx2(
33222
+ "button",
33223
+ {
33224
+ type: "button",
33225
+ "data-slot": "button",
33226
+ "data-variant": "outline",
33227
+ "data-size": "sm",
33228
+ className: props.entityType ? HOST_ENTITY_BUTTON_CLASSNAME : HOST_GLOBAL_BUTTON_CLASSNAME,
33229
+ disabled: buttonController.disabled,
33230
+ onClick: buttonController.onClick,
33231
+ children: /* @__PURE__ */ jsx2(
33232
+ LoadingButtonContent,
33233
+ {
33234
+ busy: buttonController.busy,
33235
+ label: buttonController.label,
33236
+ busyLabel: buttonController.busyLabel,
33237
+ icon: /* @__PURE__ */ jsx2(GitHubMarkIcon, { className: "h-3.5 w-3.5" })
33238
+ }
33239
+ )
33240
+ }
33241
+ )
33242
+ ]
33243
+ }
33244
+ );
33245
+ }
33246
+ function useGitHubSyncButtonController(props) {
33247
+ const toast = usePluginToast();
33248
+ const runSyncNow = usePluginAction("sync.runNow");
33249
+ const cancelSync = usePluginAction("sync.cancel");
33250
+ const pluginIdFromLocation = getPluginIdFromLocation();
33251
+ const effectiveEntityId = props.entityType === "issue" ? props.resolvedIssueId ?? "__ghsync_unresolved_issue__" : props.entityId;
33148
33252
  const toolbarState = usePluginData("sync.toolbarState", {
33149
33253
  ...props.companyId ? { companyId: props.companyId } : {},
33150
33254
  ...effectiveEntityId ? { entityId: effectiveEntityId } : {},
@@ -33157,10 +33261,7 @@ function GitHubSyncToolbarButtonSurface(props) {
33157
33261
  const [runningSync, setRunningSync] = useState2(false);
33158
33262
  const [cancellingSync, setCancellingSync] = useState2(false);
33159
33263
  const [syncStateOverride, setSyncStateOverride] = useState2(null);
33160
- const themeMode = useResolvedThemeMode();
33161
33264
  const boardAccessRequirement = usePaperclipBoardAccessRequirement();
33162
- const theme = themeMode === "light" ? LIGHT_PALETTE : DARK_PALETTE;
33163
- const themeVars = buildThemeVars(theme, themeMode);
33164
33265
  const state = toolbarState.data ?? {
33165
33266
  kind: props.entityType ?? "global",
33166
33267
  visible: !props.entityType,
@@ -33192,9 +33293,7 @@ function GitHubSyncToolbarButtonSurface(props) {
33192
33293
  disabled: toolbarButtonDisabled,
33193
33294
  label: toolbarButtonLabel,
33194
33295
  busyLabel: toolbarButtonBusyLabel,
33195
- syncPersistedRunning,
33196
- syncStartPending,
33197
- cancellationRequested
33296
+ syncPersistedRunning
33198
33297
  } = toolbarButtonState;
33199
33298
  const armSyncCompletionToast = useSyncCompletionToast(effectiveSyncState, toast);
33200
33299
  useEffect2(() => {
@@ -33256,26 +33355,6 @@ function GitHubSyncToolbarButtonSurface(props) {
33256
33355
  document.removeEventListener("visibilitychange", handleVisibilityChange);
33257
33356
  };
33258
33357
  }, [toolbarState.refresh, settingsRegistration.refresh, props.companyId, effectiveEntityId, props.entityType]);
33259
- useEffect2(() => {
33260
- if (!props.entityType) {
33261
- return;
33262
- }
33263
- const hostWrapper = surfaceRef.current?.parentElement;
33264
- if (!hostWrapper) {
33265
- return;
33266
- }
33267
- const previousMarginLeft = hostWrapper.style.marginLeft;
33268
- const previousMarginInlineStart = hostWrapper.style.marginInlineStart;
33269
- hostWrapper.style.marginLeft = "auto";
33270
- hostWrapper.style.marginInlineStart = "auto";
33271
- return () => {
33272
- hostWrapper.style.marginLeft = previousMarginLeft;
33273
- hostWrapper.style.marginInlineStart = previousMarginInlineStart;
33274
- };
33275
- });
33276
- if (!state.visible) {
33277
- return null;
33278
- }
33279
33358
  async function handleRunSync() {
33280
33359
  try {
33281
33360
  if (!effectiveCanRun) {
@@ -33287,7 +33366,7 @@ function GitHubSyncToolbarButtonSurface(props) {
33287
33366
  waitForCompletion: false,
33288
33367
  ...props.companyId ? { companyId: props.companyId } : {},
33289
33368
  ...props.entityType === "project" && props.entityId ? { projectId: props.entityId } : {},
33290
- ...props.entityType === "issue" && resolvedIssue.issueId ? { issueId: resolvedIssue.issueId } : {},
33369
+ ...props.entityType === "issue" && props.resolvedIssueId ? { issueId: props.resolvedIssueId } : {},
33291
33370
  ...trustedPaperclipApiBaseUrl ? { paperclipApiBaseUrl: trustedPaperclipApiBaseUrl } : {}
33292
33371
  });
33293
33372
  const nextSyncState = result.syncState ?? EMPTY_SETTINGS.syncState;
@@ -33353,39 +33432,15 @@ function GitHubSyncToolbarButtonSurface(props) {
33353
33432
  setCancellingSync(false);
33354
33433
  }
33355
33434
  }
33356
- return /* @__PURE__ */ jsxs2(
33357
- "div",
33358
- {
33359
- ref: surfaceRef,
33360
- className: `ghsync-toolbar-button${props.entityType ? " ghsync-toolbar-button--entity" : ""}`,
33361
- style: themeVars,
33362
- title: toolbarState.error?.message ?? effectiveMessage,
33363
- children: [
33364
- /* @__PURE__ */ jsx2("style", { children: EXTENSION_SURFACE_STYLES }),
33365
- /* @__PURE__ */ jsx2(
33366
- "button",
33367
- {
33368
- type: "button",
33369
- "data-slot": "button",
33370
- "data-variant": "outline",
33371
- "data-size": "sm",
33372
- className: props.entityType ? HOST_ENTITY_BUTTON_CLASSNAME : HOST_GLOBAL_BUTTON_CLASSNAME,
33373
- disabled: toolbarButtonDisabled,
33374
- onClick: syncPersistedRunning && allowToolbarCancellation ? handleCancelSync : handleRunSync,
33375
- children: /* @__PURE__ */ jsx2(
33376
- LoadingButtonContent,
33377
- {
33378
- busy: toolbarButtonBusy,
33379
- label: toolbarButtonLabel,
33380
- busyLabel: toolbarButtonBusyLabel,
33381
- icon: /* @__PURE__ */ jsx2(GitHubMarkIcon, { className: "h-3.5 w-3.5" })
33382
- }
33383
- )
33384
- }
33385
- )
33386
- ]
33387
- }
33388
- );
33435
+ return {
33436
+ visible: props.forceVisible ? true : state.visible,
33437
+ title: toolbarState.error?.message ?? effectiveMessage ?? "GitHub sync",
33438
+ busy: toolbarButtonBusy,
33439
+ disabled: toolbarButtonDisabled,
33440
+ label: toolbarButtonLabel,
33441
+ busyLabel: toolbarButtonBusyLabel,
33442
+ onClick: syncPersistedRunning && allowToolbarCancellation ? handleCancelSync : handleRunSync
33443
+ };
33389
33444
  }
33390
33445
  function GitHubSyncGlobalToolbarButton() {
33391
33446
  const context = useHostContext();
@@ -33418,6 +33473,13 @@ function GitHubSyncIssueDetailTabContent(props) {
33418
33473
  detailsError: Boolean(details.error),
33419
33474
  issueDetails
33420
33475
  });
33476
+ const issueSyncButton = useGitHubSyncButtonController({
33477
+ companyId: props.companyId,
33478
+ entityId: props.issueId,
33479
+ entityType: "issue",
33480
+ resolvedIssueId: props.issueId,
33481
+ forceVisible: true
33482
+ });
33421
33483
  useEffect2(() => {
33422
33484
  if (!props.companyId || !props.issueId) {
33423
33485
  return;
@@ -33437,27 +33499,71 @@ function GitHubSyncIssueDetailTabContent(props) {
33437
33499
  detailTabState === "error" && details.error ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: details.error.message }) : null,
33438
33500
  detailTabState === "ready" && issueDetails ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
33439
33501
  /* @__PURE__ */ jsxs2("div", { className: "ghsync-extension-heading", children: [
33440
- /* @__PURE__ */ jsxs2("div", { children: [
33502
+ /* @__PURE__ */ jsxs2("div", { className: "ghsync-issue-detail__headline", children: [
33441
33503
  /* @__PURE__ */ jsxs2("h4", { children: [
33442
33504
  "Issue #",
33443
33505
  issueDetails.githubIssueNumber
33444
33506
  ] }),
33445
- /* @__PURE__ */ jsx2("p", { children: formatGitHubRepositoryLabel(issueDetails.repositoryUrl) })
33507
+ /* @__PURE__ */ jsx2("p", { children: formatGitHubRepositoryLabel(issueDetails.repositoryUrl) }),
33508
+ issueDetails.creator ? /* @__PURE__ */ jsxs2("div", { className: "ghsync-issue-detail__creator-row", children: [
33509
+ /* @__PURE__ */ jsx2("span", { className: "ghsync-issue-detail__creator-label", children: "Creator" }),
33510
+ /* @__PURE__ */ jsxs2(
33511
+ "a",
33512
+ {
33513
+ href: issueDetails.creator.profileUrl,
33514
+ target: "_blank",
33515
+ rel: "noreferrer",
33516
+ className: "ghsync-prs-table__person ghsync-issue-detail__creator",
33517
+ children: [
33518
+ /* @__PURE__ */ jsx2(PreviewAvatar, { person: issueDetails.creator }),
33519
+ /* @__PURE__ */ jsxs2("span", { className: "ghsync-prs-table__person-copy", children: [
33520
+ /* @__PURE__ */ jsx2("span", { className: "ghsync-prs-table__person-name", children: issueDetails.creator.name }),
33521
+ /* @__PURE__ */ jsx2("span", { className: "ghsync-prs-table__person-handle", children: issueDetails.creator.handle })
33522
+ ] })
33523
+ ]
33524
+ }
33525
+ )
33526
+ ] }) : null
33446
33527
  ] }),
33447
- /* @__PURE__ */ jsx2(
33448
- "a",
33449
- {
33450
- href: issueDetails.githubIssueUrl,
33451
- target: "_blank",
33452
- rel: "noreferrer",
33453
- className: getPluginActionClassName({
33454
- variant: "secondary",
33455
- size: "sm",
33456
- extraClassName: "ghsync-extension-link"
33457
- }),
33458
- children: "Open on GitHub"
33459
- }
33460
- )
33528
+ /* @__PURE__ */ jsxs2("div", { className: "ghsync-issue-detail__actions", children: [
33529
+ issueSyncButton.visible ? /* @__PURE__ */ jsx2(
33530
+ "button",
33531
+ {
33532
+ type: "button",
33533
+ className: getPluginActionClassName({
33534
+ variant: "secondary",
33535
+ size: "sm",
33536
+ extraClassName: "ghsync-extension-link"
33537
+ }),
33538
+ disabled: issueSyncButton.disabled,
33539
+ onClick: issueSyncButton.onClick,
33540
+ title: issueSyncButton.title,
33541
+ children: /* @__PURE__ */ jsx2(
33542
+ LoadingButtonContent,
33543
+ {
33544
+ busy: issueSyncButton.busy,
33545
+ label: issueSyncButton.label,
33546
+ busyLabel: issueSyncButton.busyLabel,
33547
+ icon: /* @__PURE__ */ jsx2(GitHubMarkIcon, { className: "ghsync-prs-icon" })
33548
+ }
33549
+ )
33550
+ }
33551
+ ) : null,
33552
+ /* @__PURE__ */ jsx2(
33553
+ "a",
33554
+ {
33555
+ href: issueDetails.githubIssueUrl,
33556
+ target: "_blank",
33557
+ rel: "noreferrer",
33558
+ className: getPluginActionClassName({
33559
+ variant: "secondary",
33560
+ size: "sm",
33561
+ extraClassName: "ghsync-extension-link"
33562
+ }),
33563
+ children: /* @__PURE__ */ jsx2(GitHubButtonLabel, { label: "Open on GitHub" })
33564
+ }
33565
+ )
33566
+ ] })
33461
33567
  ] }),
33462
33568
  /* @__PURE__ */ jsxs2("div", { className: "ghsync-extension-grid", children: [
33463
33569
  /* @__PURE__ */ jsxs2("div", { className: "ghsync-extension-metric", children: [
@@ -33479,7 +33585,7 @@ function GitHubSyncIssueDetailTabContent(props) {
33479
33585
  ] }),
33480
33586
  issueDetails.linkedPullRequestNumbers.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "ghsync-issue-detail__section", children: [
33481
33587
  /* @__PURE__ */ jsx2("div", { className: "ghsync-issue-detail__section-heading", children: "Linked pull requests" }),
33482
- /* @__PURE__ */ jsx2("div", { className: "ghsync-extension-links", children: issueDetails.linkedPullRequestNumbers.map((pullRequestNumber) => /* @__PURE__ */ jsxs2(
33588
+ /* @__PURE__ */ jsx2("div", { className: "ghsync-extension-links", children: issueDetails.linkedPullRequestNumbers.map((pullRequestNumber) => /* @__PURE__ */ jsx2(
33483
33589
  "a",
33484
33590
  {
33485
33591
  href: `${issueDetails.repositoryUrl}/pull/${pullRequestNumber}`,
@@ -33490,10 +33596,7 @@ function GitHubSyncIssueDetailTabContent(props) {
33490
33596
  size: "sm",
33491
33597
  extraClassName: "ghsync-extension-link"
33492
33598
  }),
33493
- children: [
33494
- "PR #",
33495
- pullRequestNumber
33496
- ]
33599
+ children: /* @__PURE__ */ jsx2(GitHubButtonLabel, { label: `PR #${pullRequestNumber}` })
33497
33600
  },
33498
33601
  pullRequestNumber
33499
33602
  )) })
@@ -33510,7 +33613,7 @@ function GitHubSyncIssueDetailTabContent(props) {
33510
33613
  `${label.name}:${label.color ?? "none"}`
33511
33614
  )) })
33512
33615
  ] }) : null,
33513
- issueDetails.source !== "entity" ? /* @__PURE__ */ jsx2("div", { className: "ghsync-extension-note", children: "GitHub Sync recovered this link from older sync metadata. Run sync once to refresh GitHub state, labels, and linked PRs in this panel." }) : null
33616
+ issueDetails.source !== "entity" ? /* @__PURE__ */ jsx2("div", { className: "ghsync-extension-note", children: "GitHub Sync recovered this link from older sync metadata. Run sync once to refresh the creator, GitHub state, labels, and linked PRs in this panel." }) : null
33514
33617
  ] }) : null
33515
33618
  ] });
33516
33619
  }
@@ -33581,7 +33684,7 @@ function GitHubSyncCommentAnnotation() {
33581
33684
  size: "sm",
33582
33685
  extraClassName: "ghsync-extension-link"
33583
33686
  }),
33584
- children: link3.label
33687
+ children: /* @__PURE__ */ jsx2(GitHubButtonLabel, { label: link3.label })
33585
33688
  },
33586
33689
  `${link3.type}:${link3.href}`
33587
33690
  ))