@dxos/plugin-github 0.13.0 → 0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a
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/dist/lib/GitHubCapabilities.mjs +1 -10
- package/dist/lib/GitHubEvents.mjs +1 -15
- package/dist/lib/GitHubOperation.mjs +1 -358
- package/dist/lib/GitHubPlugin.mjs +1 -16
- package/dist/lib/Walkthrough.mjs +1 -59
- package/dist/lib/capabilities.browser.mjs +1 -2
- package/dist/lib/capabilities.browser.mjs.map +1 -1
- package/dist/lib/capabilities.mjs +1 -2
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/capabilities.tauri.mjs +1 -2
- package/dist/lib/capabilities.tauri.mjs.map +1 -1
- package/dist/lib/chunk-Extensions.mjs +18 -0
- package/dist/lib/chunk-Extensions.mjs.map +1 -0
- package/dist/lib/chunk-GitHubCapabilities.mjs +10 -0
- package/dist/lib/chunk-GitHubCapabilities.mjs.map +1 -0
- package/dist/lib/chunk-GitHubEvents.mjs +15 -0
- package/dist/lib/chunk-GitHubEvents.mjs.map +1 -0
- package/dist/lib/chunk-GitHubOperation.mjs +386 -0
- package/dist/lib/chunk-GitHubOperation.mjs.map +1 -0
- package/dist/lib/chunk-GitHubPlugin.mjs +16 -0
- package/dist/lib/chunk-GitHubPlugin.mjs.map +1 -0
- package/dist/lib/chunk-ImportPullRequestDialog.mjs.map +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +1 -1
- package/dist/lib/chunk-PullRequestArticle.mjs +64 -21
- package/dist/lib/chunk-PullRequestArticle.mjs.map +1 -1
- package/dist/lib/chunk-PullRequestArticle2.mjs +1 -2
- package/dist/lib/chunk-PullRequestCardMenu.mjs +1 -1
- package/dist/lib/chunk-PullRequestsArticle.mjs +3 -3
- package/dist/lib/chunk-PullRequestsArticle.mjs.map +1 -1
- package/dist/lib/chunk-Walkthrough.mjs +59 -0
- package/dist/lib/chunk-Walkthrough.mjs.map +1 -0
- package/dist/lib/chunk-WalkthroughArticle.mjs +1 -1
- package/dist/lib/chunk-add-pull-request-comment.mjs.map +1 -1
- package/dist/lib/chunk-add-pull-request-review-comment.mjs.map +1 -1
- package/dist/lib/chunk-connector.mjs.map +1 -1
- package/dist/lib/chunk-generate-walkthrough.mjs.map +1 -1
- package/dist/lib/chunk-get-pull-request-diff.mjs.map +1 -1
- package/dist/lib/chunk-get-pull-request-status.mjs.map +1 -1
- package/dist/lib/chunk-get-repositories.mjs.map +1 -1
- package/dist/lib/chunk-github-api.mjs +1 -0
- package/dist/lib/chunk-github-api.mjs.map +1 -1
- package/dist/lib/chunk-import-pull-request.mjs +78 -3
- package/dist/lib/chunk-import-pull-request.mjs.map +1 -1
- package/dist/lib/chunk-link-resolver.mjs.map +1 -1
- package/dist/lib/chunk-pull-request2.mjs +1 -0
- package/dist/lib/chunk-pull-request2.mjs.map +1 -1
- package/dist/lib/chunk-react-surface.mjs +4 -4
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/chunk-refresh-pull-requests.mjs +49 -0
- package/dist/lib/chunk-refresh-pull-requests.mjs.map +1 -0
- package/dist/lib/chunk-submit-pull-request-approval.mjs.map +1 -1
- package/dist/lib/chunk-sync-pull-request.mjs +11 -9
- package/dist/lib/chunk-sync-pull-request.mjs.map +1 -1
- package/dist/lib/chunk-sync.mjs.map +1 -1
- package/dist/lib/index.mjs +2 -2
- package/dist/lib/meta.mjs.map +1 -1
- package/dist/lib/ns/Extensions.mjs +2 -16
- package/dist/lib/operations.mjs +2 -1
- package/dist/lib/operations.mjs.map +1 -1
- package/dist/lib/types.mjs +4 -4
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/cards/GitHubCard.d.ts.map +1 -1
- package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts +6 -3
- package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts.map +1 -1
- package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts +2 -0
- package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/PullRequestOverview.d.ts.map +1 -1
- package/dist/types/src/components/PullRequestStatus/PullRequestStatus.d.ts.map +1 -1
- package/dist/types/src/operations/import-pull-request.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/pull-request.d.ts.map +1 -1
- package/dist/types/src/operations/refresh-pull-requests.d.ts +5 -0
- package/dist/types/src/operations/refresh-pull-requests.d.ts.map +1 -0
- package/dist/types/src/operations/refresh.d.ts +37 -0
- package/dist/types/src/operations/refresh.d.ts.map +1 -0
- package/dist/types/src/operations/refresh.test.d.ts +2 -0
- package/dist/types/src/operations/refresh.test.d.ts.map +1 -0
- package/dist/types/src/operations/sync-pull-request.d.ts.map +1 -1
- package/dist/types/src/services/github-api.d.ts +1 -0
- package/dist/types/src/services/github-api.d.ts.map +1 -1
- package/dist/types/src/stories/PullRequestOverview.stories.d.ts +2 -0
- package/dist/types/src/stories/PullRequestOverview.stories.d.ts.map +1 -1
- package/dist/types/src/types/GitHubOperation.d.ts +14 -0
- package/dist/types/src/types/GitHubOperation.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +47 -47
- package/src/capabilities/gen/browser.ts +1 -3
- package/src/capabilities/gen/tauri.ts +1 -3
- package/src/capabilities/index.ts +1 -4
- package/src/cards/GitHubCard.tsx +7 -3
- package/src/components/PullRequestOverview/ArtifactPill.tsx +1 -1
- package/src/components/PullRequestOverview/CheckRunList.test.ts +29 -0
- package/src/components/PullRequestOverview/CheckRunList.tsx +62 -13
- package/src/components/PullRequestOverview/PullRequestOverview.tsx +5 -1
- package/src/components/PullRequestStatus/PullRequestStatus.tsx +8 -5
- package/src/containers/PullRequestsArticle/PullRequestsArticle.tsx +12 -10
- package/src/operations/import-pull-request.ts +8 -0
- package/src/operations/index.ts +1 -0
- package/src/operations/pull-request.ts +1 -0
- package/src/operations/refresh-pull-requests.ts +69 -0
- package/src/operations/refresh.test.ts +112 -0
- package/src/operations/refresh.ts +111 -0
- package/src/operations/sync-pull-request.ts +10 -13
- package/src/services/github-api.ts +1 -0
- package/src/stories/PullRequestOverview.stories.tsx +22 -1
- package/src/types/GitHubOperation.ts +28 -0
- package/dist/lib/GitHubCapabilities.mjs.map +0 -1
- package/dist/lib/GitHubEvents.mjs.map +0 -1
- package/dist/lib/GitHubOperation.mjs.map +0 -1
- package/dist/lib/GitHubPlugin.mjs.map +0 -1
- package/dist/lib/Walkthrough.mjs.map +0 -1
- package/dist/lib/ns/Extensions.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
4
4
|
"description": "DXOS plugin that integrates GitHub as a sync source via the generic Integration mechanism.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -133,61 +133,61 @@
|
|
|
133
133
|
"@codemirror/language": "^6.12.4",
|
|
134
134
|
"@codemirror/state": "^6.7.6",
|
|
135
135
|
"@codemirror/view": "^6.43.13",
|
|
136
|
-
"effect": "4.0.
|
|
137
|
-
"@dxos/ai": "0.
|
|
138
|
-
"@dxos/app-framework": "0.
|
|
139
|
-
"@dxos/app-graph": "0.
|
|
140
|
-
"@dxos/app-toolkit": "0.
|
|
141
|
-
"@dxos/compute": "0.
|
|
142
|
-
"@dxos/echo": "0.
|
|
143
|
-
"@dxos/echo-query": "0.
|
|
144
|
-
"@dxos/echo-react": "0.
|
|
145
|
-
"@dxos/effect": "0.
|
|
146
|
-
"@dxos/errors": "0.
|
|
147
|
-
"@dxos/graph": "0.
|
|
148
|
-
"@dxos/keys": "0.
|
|
149
|
-
"@dxos/link": "0.
|
|
150
|
-
"@dxos/lit-ui": "0.
|
|
151
|
-
"@dxos/log": "0.
|
|
152
|
-
"@dxos/plugin-connector": "0.
|
|
153
|
-
"@dxos/plugin-crx": "0.
|
|
154
|
-
"@dxos/plugin-markdown": "0.
|
|
155
|
-
"@dxos/plugin-preview": "0.
|
|
156
|
-
"@dxos/plugin-space": "0.
|
|
157
|
-
"@dxos/protocols": "0.
|
|
158
|
-
"@dxos/react-client": "0.
|
|
159
|
-
"@dxos/react-ui": "0.
|
|
160
|
-
"@dxos/react-ui-attention": "0.
|
|
161
|
-
"@dxos/react-ui-components": "0.
|
|
162
|
-
"@dxos/react-ui-editor": "0.
|
|
163
|
-
"@dxos/react-ui-
|
|
164
|
-
"@dxos/react-ui-
|
|
165
|
-
"@dxos/react-ui-markdown": "0.
|
|
166
|
-
"@dxos/react-ui-masonry": "0.
|
|
167
|
-
"@dxos/react-ui-menu": "0.
|
|
168
|
-
"@dxos/react-ui-query": "0.
|
|
169
|
-
"@dxos/
|
|
170
|
-
"@dxos/
|
|
171
|
-
"@dxos/ui-types": "0.
|
|
172
|
-
"@dxos/util": "0.
|
|
136
|
+
"effect": "4.0.4",
|
|
137
|
+
"@dxos/ai": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
138
|
+
"@dxos/app-framework": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
139
|
+
"@dxos/app-graph": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
140
|
+
"@dxos/app-toolkit": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
141
|
+
"@dxos/compute": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
142
|
+
"@dxos/echo": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
143
|
+
"@dxos/echo-query": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
144
|
+
"@dxos/echo-react": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
145
|
+
"@dxos/effect": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
146
|
+
"@dxos/errors": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
147
|
+
"@dxos/graph": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
148
|
+
"@dxos/keys": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
149
|
+
"@dxos/link": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
150
|
+
"@dxos/lit-ui": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
151
|
+
"@dxos/log": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
152
|
+
"@dxos/plugin-connector": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
153
|
+
"@dxos/plugin-crx": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
154
|
+
"@dxos/plugin-markdown": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
155
|
+
"@dxos/plugin-preview": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
156
|
+
"@dxos/plugin-space": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
157
|
+
"@dxos/protocols": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
158
|
+
"@dxos/react-client": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
159
|
+
"@dxos/react-ui": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
160
|
+
"@dxos/react-ui-attention": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
161
|
+
"@dxos/react-ui-components": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
162
|
+
"@dxos/react-ui-editor": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
163
|
+
"@dxos/react-ui-list": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
164
|
+
"@dxos/react-ui-form": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
165
|
+
"@dxos/react-ui-markdown": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
166
|
+
"@dxos/react-ui-masonry": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
167
|
+
"@dxos/react-ui-menu": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
168
|
+
"@dxos/react-ui-query": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
169
|
+
"@dxos/ui-editor": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
170
|
+
"@dxos/types": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
171
|
+
"@dxos/ui-types": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
172
|
+
"@dxos/util": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a"
|
|
173
173
|
},
|
|
174
174
|
"devDependencies": {
|
|
175
|
-
"@effect/atom-react": "4.0.
|
|
175
|
+
"@effect/atom-react": "4.0.4",
|
|
176
176
|
"@storybook/react-vite": "^10.6.0",
|
|
177
177
|
"@types/react": "~19.2.17",
|
|
178
178
|
"@types/react-dom": "~19.2.3",
|
|
179
179
|
"react": "~19.2.7",
|
|
180
180
|
"react-dom": "~19.2.7",
|
|
181
|
-
"vite": "^8.
|
|
182
|
-
"@dxos/echo-client": "0.
|
|
183
|
-
"@dxos/plugin-client": "0.
|
|
184
|
-
"@dxos/plugin-testing": "0.
|
|
185
|
-
"@dxos/random": "0.
|
|
186
|
-
"@dxos/react-ui-editor": "0.
|
|
181
|
+
"vite": "^8.3.4",
|
|
182
|
+
"@dxos/echo-client": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
183
|
+
"@dxos/plugin-client": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
184
|
+
"@dxos/plugin-testing": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
185
|
+
"@dxos/random": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a",
|
|
186
|
+
"@dxos/react-ui-editor": "0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a"
|
|
187
187
|
},
|
|
188
188
|
"peerDependencies": {
|
|
189
|
-
"@effect/atom-react": "4.0.
|
|
190
|
-
"effect": "4.0.
|
|
189
|
+
"@effect/atom-react": "4.0.4",
|
|
190
|
+
"effect": "4.0.4",
|
|
191
191
|
"react": "~19.2.7",
|
|
192
192
|
"react-dom": "~19.2.7"
|
|
193
193
|
},
|
|
@@ -19,8 +19,6 @@ import * as PreviewEvents from '@dxos/plugin-preview/PreviewEvents';
|
|
|
19
19
|
import { meta } from '#meta';
|
|
20
20
|
import { translations } from '#translations';
|
|
21
21
|
|
|
22
|
-
import pluginSpec from '../../../PLUGIN.mdl?raw';
|
|
23
|
-
|
|
24
22
|
export const Connector = Capability.lazyModule(
|
|
25
23
|
'GitHubConnector',
|
|
26
24
|
{ provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },
|
|
@@ -75,7 +73,7 @@ export const ReactSurface = AppCapability.surface(() => import('../react-surface
|
|
|
75
73
|
export const PluginAsset = AppCapability.pluginAsset({
|
|
76
74
|
pluginId: meta.profile.key,
|
|
77
75
|
path: 'PLUGIN.mdl',
|
|
78
|
-
content:
|
|
76
|
+
content: () => import('../../../PLUGIN.mdl?raw'),
|
|
79
77
|
mimeType: 'application/x-mdl',
|
|
80
78
|
});
|
|
81
79
|
|
|
@@ -19,8 +19,6 @@ import * as PreviewEvents from '@dxos/plugin-preview/PreviewEvents';
|
|
|
19
19
|
import { meta } from '#meta';
|
|
20
20
|
import { translations } from '#translations';
|
|
21
21
|
|
|
22
|
-
import pluginSpec from '../../../PLUGIN.mdl?raw';
|
|
23
|
-
|
|
24
22
|
export const Connector = Capability.lazyModule(
|
|
25
23
|
'GitHubConnector',
|
|
26
24
|
{ provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },
|
|
@@ -75,7 +73,7 @@ export const ReactSurface = AppCapability.surface(() => import('../react-surface
|
|
|
75
73
|
export const PluginAsset = AppCapability.pluginAsset({
|
|
76
74
|
pluginId: meta.profile.key,
|
|
77
75
|
path: 'PLUGIN.mdl',
|
|
78
|
-
content:
|
|
76
|
+
content: () => import('../../../PLUGIN.mdl?raw'),
|
|
79
77
|
mimeType: 'application/x-mdl',
|
|
80
78
|
});
|
|
81
79
|
|
|
@@ -17,9 +17,6 @@ import * as PreviewEvents from '@dxos/plugin-preview/PreviewEvents';
|
|
|
17
17
|
import { meta } from '#meta';
|
|
18
18
|
import { translations } from '#translations';
|
|
19
19
|
|
|
20
|
-
// eslint-disable-next-line import/no-relative-packages
|
|
21
|
-
import pluginSpec from '../../PLUGIN.mdl?raw';
|
|
22
|
-
|
|
23
20
|
export const Connector = Capability.lazyModule(
|
|
24
21
|
'GitHubConnector',
|
|
25
22
|
{ provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },
|
|
@@ -65,7 +62,7 @@ export const ReactSurface = AppCapability.surface(() => import('./react-surface.
|
|
|
65
62
|
export const PluginAsset = AppCapability.pluginAsset({
|
|
66
63
|
pluginId: meta.profile.key,
|
|
67
64
|
path: 'PLUGIN.mdl',
|
|
68
|
-
content:
|
|
65
|
+
content: () => import('../../PLUGIN.mdl?raw'),
|
|
69
66
|
mimeType: 'application/x-mdl',
|
|
70
67
|
});
|
|
71
68
|
export const Translations = AppCapability.translations(translations);
|
package/src/cards/GitHubCard.tsx
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
7
|
import type * as AppSurface from '@dxos/app-toolkit/AppSurface';
|
|
8
|
+
import { useObject } from '@dxos/echo-react';
|
|
8
9
|
import * as Card from '@dxos/react-ui/Card';
|
|
9
10
|
import * as Hooks from '@dxos/react-ui/Hooks';
|
|
10
11
|
import * as Layout from '@dxos/react-ui/Layout';
|
|
@@ -21,6 +22,8 @@ type Subject = Repo.Repo | Issue.Issue | PullRequest.PullRequest;
|
|
|
21
22
|
*/
|
|
22
23
|
type Fields = {
|
|
23
24
|
owner: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
repo?: string;
|
|
24
27
|
number?: number;
|
|
25
28
|
state?: PullRequest.State;
|
|
26
29
|
author?: string;
|
|
@@ -44,8 +47,9 @@ const stateHue: Record<PullRequest.State, Tag.TagHue> = {
|
|
|
44
47
|
*/
|
|
45
48
|
export const GitHubCard = ({ subject }: AppSurface.ObjectCardProps<Subject>) => {
|
|
46
49
|
const { t } = Hooks.useTranslation(meta.profile.key);
|
|
47
|
-
const
|
|
48
|
-
const
|
|
50
|
+
const [object] = useObject(subject);
|
|
51
|
+
const { owner, name, repo, number, state, author, additions, deletions, defaultBranch, description, url }: Fields =
|
|
52
|
+
object;
|
|
49
53
|
|
|
50
54
|
return (
|
|
51
55
|
<Card.Body>
|
|
@@ -59,7 +63,7 @@ export const GitHubCard = ({ subject }: AppSurface.ObjectCardProps<Subject>) =>
|
|
|
59
63
|
) : undefined
|
|
60
64
|
}
|
|
61
65
|
>
|
|
62
|
-
<Card.Text variant='muted'>{[`${owner}/${name}`, number].filter(Boolean).join('#')}</Card.Text>
|
|
66
|
+
<Card.Text variant='muted'>{[`${owner}/${name ?? repo}`, number].filter(Boolean).join('#')}</Card.Text>
|
|
63
67
|
</Card.Row>
|
|
64
68
|
{author && (
|
|
65
69
|
<Card.Row icon='ph--user--regular'>
|
|
@@ -67,7 +67,7 @@ export const ArtifactPill = ({ artifact, children }: ArtifactPillProps) => {
|
|
|
67
67
|
size='sm'
|
|
68
68
|
classNames='bg-input-surface text-fg font-normal ring-inset ring ring-neutral-border hover:bg-hover-surface hover:ring-info-border align-baseline'
|
|
69
69
|
icon={artifactIcon[artifact.kind]}
|
|
70
|
-
iconClassNames={artifact.kind === 'video' ? 'text-violet-
|
|
70
|
+
iconClassNames={artifact.kind === 'video' ? 'text-violet-text' : 'text-sky-text'}
|
|
71
71
|
label={label}
|
|
72
72
|
data-testid='pull-request.artifact.pill'
|
|
73
73
|
/>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { formatDuration } from './CheckRunList.tsx';
|
|
8
|
+
|
|
9
|
+
describe('formatDuration', () => {
|
|
10
|
+
const startedAt = '2026-10-08T10:00:00Z';
|
|
11
|
+
|
|
12
|
+
test('measures a finished run from start to completion', ({ expect }) => {
|
|
13
|
+
expect(formatDuration(startedAt, '2026-10-08T10:04:12Z')).toBe('4m 12s');
|
|
14
|
+
expect(formatDuration(startedAt, '2026-10-08T10:00:42Z')).toBe('42s');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('measures a running run up to now', ({ expect }) => {
|
|
18
|
+
expect(formatDuration(startedAt, undefined, Date.parse('2026-10-08T10:12:05Z'))).toBe('12m 5s');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('prefers completion over now', ({ expect }) => {
|
|
22
|
+
expect(formatDuration(startedAt, '2026-10-08T10:01:00Z', Date.parse('2026-10-08T11:00:00Z'))).toBe('1m 0s');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('is undefined without a start, or without an end of either kind', ({ expect }) => {
|
|
26
|
+
expect(formatDuration(undefined, '2026-10-08T10:01:00Z')).toBeUndefined();
|
|
27
|
+
expect(formatDuration(startedAt)).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
// Copyright 2026 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { useMemo } from 'react';
|
|
5
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
6
6
|
|
|
7
7
|
import { Listbox } from '@dxos/react-ui-list';
|
|
8
|
+
import * as Button from '@dxos/react-ui/Button';
|
|
8
9
|
import * as Hooks from '@dxos/react-ui/Hooks';
|
|
9
10
|
import * as Status from '@dxos/react-ui/Status';
|
|
10
11
|
|
|
@@ -22,12 +23,16 @@ const outcomeIcon: Record<GitHubOperation.CheckOutcome, { icon: string; classNam
|
|
|
22
23
|
// What needs attention first: a failure is the reason to open the list, a running check the next.
|
|
23
24
|
const outcomeOrder: GitHubOperation.CheckOutcome[] = ['failure', 'pending', 'success', 'neutral', 'skipped'];
|
|
24
25
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* `4m 12s` from start to finish, or to `now` for a run still in progress;
|
|
28
|
+
* undefined for a run that has not started, or has not finished when no `now` is given.
|
|
29
|
+
*/
|
|
30
|
+
export const formatDuration = (startedAt?: string, completedAt?: string, now?: number): string | undefined => {
|
|
31
|
+
const end = completedAt ? Date.parse(completedAt) : now;
|
|
32
|
+
if (!startedAt || end === undefined) {
|
|
28
33
|
return undefined;
|
|
29
34
|
}
|
|
30
|
-
const seconds = Math.max(0, Math.round((
|
|
35
|
+
const seconds = Math.max(0, Math.round((end - Date.parse(startedAt)) / 1000));
|
|
31
36
|
if (Number.isNaN(seconds)) {
|
|
32
37
|
return undefined;
|
|
33
38
|
}
|
|
@@ -35,6 +40,24 @@ export const formatDuration = (startedAt?: string, completedAt?: string): string
|
|
|
35
40
|
return minutes > 0 ? `${minutes}m ${seconds % 60}s` : `${seconds}s`;
|
|
36
41
|
};
|
|
37
42
|
|
|
43
|
+
/** The current time, re-rendering once a second while `active` so elapsed times stay current. */
|
|
44
|
+
const useNow = (active: boolean): number => {
|
|
45
|
+
const [now, setNow] = useState(() => Date.now());
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!active) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
setNow(Date.now());
|
|
51
|
+
const interval = setInterval(() => setNow(Date.now()), 1_000);
|
|
52
|
+
return () => clearInterval(interval);
|
|
53
|
+
}, [active]);
|
|
54
|
+
return now;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** The row's value: GitHub's run id, or its name and URL for a run recorded without one. */
|
|
58
|
+
const checkRunId = (run: GitHubOperation.CheckRun): string =>
|
|
59
|
+
run.id !== undefined ? String(run.id) : `${run.name}-${run.url ?? ''}`;
|
|
60
|
+
|
|
38
61
|
/** Sorts runs by what needs attention, then by name so shards read in order. */
|
|
39
62
|
export const sortCheckRuns = (runs: readonly GitHubOperation.CheckRun[]): GitHubOperation.CheckRun[] =>
|
|
40
63
|
[...runs].sort(
|
|
@@ -48,22 +71,29 @@ export type CheckRunListProps = {
|
|
|
48
71
|
runs?: readonly GitHubOperation.CheckRun[];
|
|
49
72
|
};
|
|
50
73
|
|
|
51
|
-
/** Every check on the head commit: its outcome, how long it took, and
|
|
74
|
+
/** Every check on the head commit: its outcome, how long it took, and a button to its logs. */
|
|
52
75
|
export const CheckRunList = ({ runs }: CheckRunListProps) => {
|
|
53
76
|
const { t } = Hooks.useTranslation(meta.profile.key);
|
|
54
77
|
const sorted = useMemo(() => (runs ? sortCheckRuns(runs) : undefined), [runs]);
|
|
55
78
|
const summary = useCheckSummary(runs);
|
|
79
|
+
const now = useNow(runs?.some((run) => run.outcome === 'pending' && run.startedAt) ?? false);
|
|
80
|
+
const [current, setCurrent] = useState<string>();
|
|
56
81
|
|
|
57
82
|
if (!sorted || sorted.length === 0) {
|
|
58
83
|
return <Status.Empty>{t(sorted ? 'no-checks.message' : 'checks-loading.message')}</Status.Empty>;
|
|
59
84
|
}
|
|
60
85
|
|
|
61
86
|
return (
|
|
62
|
-
<Listbox.Root
|
|
87
|
+
<Listbox.Root
|
|
88
|
+
items={sorted.map((run) => ({ value: checkRunId(run), label: run.name }))}
|
|
89
|
+
// Icon, name, a short time column, then the open button: one line per check.
|
|
90
|
+
columns='var(--dx-block-size) minmax(0, 1fr) max-content var(--dx-block-size)'
|
|
91
|
+
onHighlightChange={(value) => value && setCurrent(value)}
|
|
92
|
+
>
|
|
63
93
|
<Listbox.Content aria-label={summary} data-testid='pull-request.checks'>
|
|
64
94
|
{sorted.map((run) => {
|
|
65
95
|
const { icon, classNames } = outcomeIcon[run.outcome];
|
|
66
|
-
const duration = formatDuration(run.startedAt, run.completedAt);
|
|
96
|
+
const duration = formatDuration(run.startedAt, run.completedAt, run.outcome === 'pending' ? now : undefined);
|
|
67
97
|
// GitHub's own word when it says more than the outcome: `timed out` rather than `failed`.
|
|
68
98
|
const detail =
|
|
69
99
|
run.conclusion && run.conclusion !== run.outcome && run.conclusion !== 'failure'
|
|
@@ -72,19 +102,38 @@ export const CheckRunList = ({ runs }: CheckRunListProps) => {
|
|
|
72
102
|
const outcome =
|
|
73
103
|
run.outcome === 'skipped'
|
|
74
104
|
? t('check-outcome.skipped.label')
|
|
75
|
-
:
|
|
105
|
+
: run.outcome === 'pending'
|
|
106
|
+
? [t('check-outcome.pending.label'), duration].filter(Boolean).join(' · ')
|
|
107
|
+
: (duration ?? t(`check-outcome.${run.outcome}.label`));
|
|
76
108
|
const url = run.url;
|
|
109
|
+
const id = checkRunId(run);
|
|
77
110
|
return (
|
|
78
111
|
<Listbox.Item
|
|
79
|
-
key={
|
|
80
|
-
id={
|
|
112
|
+
key={id}
|
|
113
|
+
id={id}
|
|
114
|
+
current={id === current}
|
|
115
|
+
highlightOnHover={false}
|
|
116
|
+
classNames='dx-hover'
|
|
81
117
|
data-outcome={run.outcome}
|
|
82
118
|
data-testid='pull-request.check'
|
|
83
|
-
onClick={url ? () => window.open(url, '_blank', 'noopener,noreferrer') : undefined}
|
|
84
119
|
>
|
|
85
120
|
<Listbox.ItemIcon icon={icon} classNames={classNames} />
|
|
86
121
|
<Listbox.ItemText>{run.name}</Listbox.ItemText>
|
|
87
|
-
<Listbox.ItemDescription
|
|
122
|
+
<Listbox.ItemDescription classNames='text-right tabular-nums'>
|
|
123
|
+
{[detail, outcome].filter(Boolean).join(' · ')}
|
|
124
|
+
</Listbox.ItemDescription>
|
|
125
|
+
{url ? (
|
|
126
|
+
<Button.Root
|
|
127
|
+
iconOnly
|
|
128
|
+
variant='ghost'
|
|
129
|
+
icon='ph--arrow-square-out--regular'
|
|
130
|
+
label={t('open-link.label')}
|
|
131
|
+
data-testid='pull-request.check.open'
|
|
132
|
+
onClick={() => window.open(url, '_blank', 'noopener,noreferrer')}
|
|
133
|
+
/>
|
|
134
|
+
) : (
|
|
135
|
+
<span />
|
|
136
|
+
)}
|
|
88
137
|
</Listbox.Item>
|
|
89
138
|
);
|
|
90
139
|
})}
|
|
@@ -12,6 +12,7 @@ import { MarkdownLink, MarkdownView, type MarkdownViewProps } from '@dxos/react-
|
|
|
12
12
|
import * as UiHooks from '@dxos/react-ui/Hooks';
|
|
13
13
|
import * as Icon from '@dxos/react-ui/Icon';
|
|
14
14
|
import * as Status from '@dxos/react-ui/Status';
|
|
15
|
+
import * as Typography from '@dxos/react-ui/Typography';
|
|
15
16
|
|
|
16
17
|
import { meta } from '#meta';
|
|
17
18
|
import { type GitHubOperation } from '#types';
|
|
@@ -60,7 +61,10 @@ export const PullRequestOverview = ({ body, details, runs }: PullRequestOverview
|
|
|
60
61
|
<RelatedCards items={related} />
|
|
61
62
|
</Form.FieldSet>
|
|
62
63
|
)}
|
|
63
|
-
<Form.FieldSet label={
|
|
64
|
+
<Form.FieldSet label={t('checks.label')}>
|
|
65
|
+
{runs && runs.length > 0 && (
|
|
66
|
+
<Typography.Text data-testid='pull-request.checks.summary'>{checkSummary}</Typography.Text>
|
|
67
|
+
)}
|
|
64
68
|
<CheckRunList runs={runs} />
|
|
65
69
|
</Form.FieldSet>
|
|
66
70
|
</Form.Content>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
7
|
import * as Hooks from '@dxos/react-ui/Hooks';
|
|
8
|
+
import * as Layout from '@dxos/react-ui/Layout';
|
|
8
9
|
import { type PullRequest } from '@dxos/types';
|
|
9
10
|
|
|
10
11
|
import { meta } from '#meta';
|
|
@@ -43,16 +44,18 @@ export type PullRequestStatusProps = {
|
|
|
43
44
|
export const PullRequestStatus = ({ reference, title, state, review, ci }: PullRequestStatusProps) => {
|
|
44
45
|
const { t } = Hooks.useTranslation(meta.profile.key);
|
|
45
46
|
return (
|
|
46
|
-
<
|
|
47
|
+
<Layout.Flex
|
|
48
|
+
align='center'
|
|
49
|
+
gap='sm'
|
|
47
50
|
role='status'
|
|
48
|
-
|
|
51
|
+
classNames='px-3 py-1.5 border-b border-separator-subtle text-sm min-w-0'
|
|
49
52
|
data-testid='pull-request.status'
|
|
50
53
|
>
|
|
51
54
|
<span className='dx-tag dx-tag-inline shrink-0' data-hue='neutral'>
|
|
52
55
|
{reference}
|
|
53
56
|
</span>
|
|
54
57
|
{title && <span className='truncate grow'>{title}</span>}
|
|
55
|
-
<
|
|
58
|
+
<Layout.Flex align='center' gap='sm' classNames='shrink-0 ml-auto'>
|
|
56
59
|
{state && (
|
|
57
60
|
<span className='dx-tag dx-tag-inline' data-hue={stateHue[state]} data-testid='pull-request.status.state'>
|
|
58
61
|
{t(`pull-request-state.${state}.label`)}
|
|
@@ -75,7 +78,7 @@ export const PullRequestStatus = ({ reference, title, state, review, ci }: PullR
|
|
|
75
78
|
{ci ? t(`ci-status.${ci.state}.label`) : t('ci-status.unknown.label')}
|
|
76
79
|
{ci && ci.checks.total > 0 && ` ${ci.checks.passed}/${ci.checks.total}`}
|
|
77
80
|
</span>
|
|
78
|
-
</
|
|
79
|
-
</
|
|
81
|
+
</Layout.Flex>
|
|
82
|
+
</Layout.Flex>
|
|
80
83
|
);
|
|
81
84
|
};
|
|
@@ -185,16 +185,18 @@ const PullRequestList = ({ role, attendableId, db }: PullRequestsArticleProps &
|
|
|
185
185
|
</Status.Empty>
|
|
186
186
|
) : (
|
|
187
187
|
<Listbox.Root items={options}>
|
|
188
|
-
<Listbox.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
<Listbox.Viewport>
|
|
189
|
+
<Listbox.Content
|
|
190
|
+
classNames='dx-expand'
|
|
191
|
+
aria-label={t('typename.label_other', { ns: PULL_REQUEST_TYPENAME })}
|
|
192
|
+
>
|
|
193
|
+
{groups
|
|
194
|
+
? groups
|
|
195
|
+
.filter((group) => group.rows.length > 0)
|
|
196
|
+
.map((group) => <GroupSection key={group.id} group={group} onOpen={openObject} />)
|
|
197
|
+
: rows.map((row) => <PullRequestListRow key={row.pullRequest.id} row={row} onOpen={openObject} />)}
|
|
198
|
+
</Listbox.Content>
|
|
199
|
+
</Listbox.Viewport>
|
|
198
200
|
</Listbox.Root>
|
|
199
201
|
)}
|
|
200
202
|
</Panel.Body>
|
|
@@ -8,6 +8,7 @@ import * as Layer from 'effect/Layer';
|
|
|
8
8
|
|
|
9
9
|
import * as Operation from '@dxos/compute/Operation';
|
|
10
10
|
import { Database, Filter, Ref } from '@dxos/echo';
|
|
11
|
+
import { log } from '@dxos/log';
|
|
11
12
|
import * as SpaceOperation from '@dxos/plugin-space/SpaceOperation';
|
|
12
13
|
import { PullRequest } from '@dxos/types';
|
|
13
14
|
|
|
@@ -18,6 +19,7 @@ import { type PullRequestReference, parsePullRequestReference } from '../github-
|
|
|
18
19
|
import { toPullRequestProps } from '../pull-request.ts';
|
|
19
20
|
import { GitHubApi } from '../services/index.ts';
|
|
20
21
|
import { githubToken } from './pull-request.ts';
|
|
22
|
+
import { ensureRefreshTrigger } from './refresh.ts';
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Statuses that may report the token's reach rather than the repository's absence, and so are worth
|
|
@@ -133,6 +135,12 @@ const handler: Operation.WithHandler<typeof GitHubOperation.ImportPullRequest> =
|
|
|
133
135
|
return yield* Effect.die(new GitHubPullRequestReferenceError({ context: { reference } }));
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
// The first pull request a space holds is what makes refreshing them worth a schedule.
|
|
139
|
+
yield* ensureRefreshTrigger().pipe(
|
|
140
|
+
// The import already succeeded; a missing schedule is recovered the next time a pull request opens.
|
|
141
|
+
Effect.catchDefect((defect) => Effect.sync(() => log.warn('refresh trigger setup failed', { defect }))),
|
|
142
|
+
);
|
|
143
|
+
|
|
136
144
|
return { pullRequest: Ref.make(object), imported: true };
|
|
137
145
|
}, Effect.provide(FetchHttpClient.layer)),
|
|
138
146
|
),
|
package/src/operations/index.ts
CHANGED
|
@@ -25,5 +25,6 @@ export const GitHubOperationHandlerSet = OperationHandlerSet.lazy([
|
|
|
25
25
|
),
|
|
26
26
|
GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import('./get-pull-request-status.ts'))),
|
|
27
27
|
GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import('./sync-pull-request.ts'))),
|
|
28
|
+
GitHubOperation.RefreshPullRequests.pipe(Operation.lazyHandler(() => import('./refresh-pull-requests.ts'))),
|
|
28
29
|
GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import('./get-pull-request-diff.ts'))),
|
|
29
30
|
]);
|
|
@@ -82,6 +82,7 @@ export const toCheckRun = (run: GitHubApi.GitHubCheckRun): GitHubOperation.Check
|
|
|
82
82
|
: 'success';
|
|
83
83
|
const url = run.details_url ?? run.html_url;
|
|
84
84
|
return {
|
|
85
|
+
...(run.id !== undefined ? { id: run.id } : {}),
|
|
85
86
|
name: run.name,
|
|
86
87
|
outcome,
|
|
87
88
|
...(run.conclusion ? { conclusion: run.conclusion } : {}),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Clock from 'effect/Clock';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as FetchHttpClient from 'effect/http/FetchHttpClient';
|
|
8
|
+
|
|
9
|
+
import * as Operation from '@dxos/compute/Operation';
|
|
10
|
+
import { log } from '@dxos/log';
|
|
11
|
+
|
|
12
|
+
import { GitHubOperation } from '#types';
|
|
13
|
+
|
|
14
|
+
import { githubToken } from './pull-request.ts';
|
|
15
|
+
import { ensureRefreshTrigger, queryInFlightPullRequests, refreshPullRequest, selectRefreshBatch } from './refresh.ts';
|
|
16
|
+
|
|
17
|
+
/** Bounded so a space with many open pull requests does not burst GitHub's secondary rate limit. */
|
|
18
|
+
const REFRESH_CONCURRENCY = 2;
|
|
19
|
+
|
|
20
|
+
/** The hourly `REFRESH_CRON` period, so each scheduled run lands in its own batch window. */
|
|
21
|
+
const REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
22
|
+
|
|
23
|
+
const handler: Operation.WithHandler<typeof GitHubOperation.RefreshPullRequests> =
|
|
24
|
+
GitHubOperation.RefreshPullRequests.pipe(
|
|
25
|
+
Operation.withHandler(
|
|
26
|
+
Effect.fn(function* () {
|
|
27
|
+
// Collapses any duplicate a racing peer created, so the space keeps one schedule.
|
|
28
|
+
yield* ensureRefreshTrigger();
|
|
29
|
+
const inFlight = yield* queryInFlightPullRequests();
|
|
30
|
+
if (inFlight.length === 0) {
|
|
31
|
+
return { checked: 0, updated: 0, failed: 0 };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const window = Math.floor((yield* Clock.currentTimeMillis) / REFRESH_INTERVAL_MS);
|
|
35
|
+
const pullRequests = selectRefreshBatch(inFlight, window);
|
|
36
|
+
|
|
37
|
+
const token = yield* githubToken();
|
|
38
|
+
const results = yield* Effect.forEach(
|
|
39
|
+
pullRequests,
|
|
40
|
+
(pullRequest) =>
|
|
41
|
+
// One deleted or unreachable pull request must not fail the run: EDGE disables a trigger
|
|
42
|
+
// after repeated failures, which would stop refreshing every other one.
|
|
43
|
+
refreshPullRequest(pullRequest, token).pipe(
|
|
44
|
+
Effect.map((updated) => (updated.length > 0 ? 'updated' : 'unchanged')),
|
|
45
|
+
Effect.catchDefect((cause) =>
|
|
46
|
+
Effect.sync(() => {
|
|
47
|
+
log.warn('pull request refresh failed', {
|
|
48
|
+
owner: pullRequest.owner,
|
|
49
|
+
repo: pullRequest.repo,
|
|
50
|
+
number: pullRequest.number,
|
|
51
|
+
cause,
|
|
52
|
+
});
|
|
53
|
+
return 'failed' as const;
|
|
54
|
+
}),
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
{ concurrency: REFRESH_CONCURRENCY },
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
checked: pullRequests.length,
|
|
62
|
+
updated: results.filter((result) => result === 'updated').length,
|
|
63
|
+
failed: results.filter((result) => result === 'failed').length,
|
|
64
|
+
};
|
|
65
|
+
}, Effect.provide(FetchHttpClient.layer)),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export default handler;
|