@hanzo/build 0.2.86 → 0.2.88
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 +2 -0
- package/lib/api/provider.d.ts +6 -1
- package/lib/api/provider.js +8 -3
- package/lib/forge.js +32 -2
- package/lib/settings/integrations.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -262,6 +262,8 @@ not there yet — then the ask, in the composer Chat draws too (`@hanzo/ui/chat`
|
|
|
262
262
|
paperclip and Build or Plan at its start; the effort, the model where the person
|
|
263
263
|
turned the selector on, dictation and send at its end. The three pills sit above
|
|
264
264
|
the field (environment, repository with its All / Organization / GitHub tabs, branch),
|
|
265
|
+
light round chips as tall as the composer's controls, on one centreline a gap apart
|
|
266
|
+
(the composer stands every `ChipSelect` in its pills so, on a phone and a laptop alike),
|
|
265
267
|
and Repos, Branches, Issues and Templates under it, each a press to its list. A codebase can be added to a project. Opening a codebase or an
|
|
266
268
|
issue from its own screen lands here with that choice already made.
|
|
267
269
|
|
package/lib/api/provider.d.ts
CHANGED
|
@@ -29,7 +29,12 @@ export declare const SOCIAL: readonly {
|
|
|
29
29
|
}[];
|
|
30
30
|
/** The provider's consent page for this org; its return lands on `back` when that is a Hanzo app page. */
|
|
31
31
|
export declare function authorize(t: Target, id: string, back?: string): Promise<string>;
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Forget the org's connection to a provider: every account, or the one `account`
|
|
34
|
+
* names (a GitHub login). For GitHub the platform also removes its App from an
|
|
35
|
+
* account no other org uses, so connecting that account again is a fresh install.
|
|
36
|
+
*/
|
|
37
|
+
export declare function disconnect(t: Target, id: string, account?: string): Promise<void>;
|
|
33
38
|
export interface Channel {
|
|
34
39
|
id: string;
|
|
35
40
|
name: string;
|
package/lib/api/provider.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* GET /v1/provider/{id} one connector and this org's connection to it
|
|
7
7
|
* POST /v1/provider/{id}/connect {return} → {authorizeUrl}: the provider's own consent page (org admin)
|
|
8
|
-
* POST /v1/provider/{id}/disconnect forget the org's connection (org admin)
|
|
8
|
+
* POST /v1/provider/{id}/disconnect {account?} → forget the org's connection, or one account of it (org admin)
|
|
9
9
|
* GET /v1/provider/slack/channels the connected workspace's channels, a page at a time
|
|
10
10
|
*
|
|
11
11
|
* Connecting leaves this page once, for the provider's consent screen, and only
|
|
@@ -76,8 +76,13 @@ export async function authorize(t, id, back) {
|
|
|
76
76
|
throw new Sentence(phrase('The platform did not name a {provider} address to connect at'), { provider: id });
|
|
77
77
|
return url;
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Forget the org's connection to a provider: every account, or the one `account`
|
|
81
|
+
* names (a GitHub login). For GitHub the platform also removes its App from an
|
|
82
|
+
* account no other org uses, so connecting that account again is a fresh install.
|
|
83
|
+
*/
|
|
84
|
+
export async function disconnect(t, id, account) {
|
|
85
|
+
await call(t, 'POST', `/v1/provider/${seg(id)}/disconnect`, account ? { account } : {});
|
|
81
86
|
}
|
|
82
87
|
export async function channels(t, cursor = '') {
|
|
83
88
|
const raw = obj(await call(t, 'GET', `/v1/provider/slack/channels${query({ cursor })}`));
|
package/lib/forge.js
CHANGED
|
@@ -30,7 +30,8 @@ import { useHost, useTarget } from './host.js';
|
|
|
30
30
|
import { path } from './route.js';
|
|
31
31
|
import { Customize } from './customize/index.js';
|
|
32
32
|
import { Sync } from './sync.js';
|
|
33
|
-
import { connect, connection, grants, installations, linked, syncIssues } from './api/github.js';
|
|
33
|
+
import { connect, connection, disconnect as unlink, grants, installations, linked, syncIssues } from './api/github.js';
|
|
34
|
+
import { disconnect } from './api/provider.js';
|
|
34
35
|
import { here, useBack } from './back.js';
|
|
35
36
|
import { Out } from './out.js';
|
|
36
37
|
import { ask, assemble, attach, closes, facets, handle, home, keyOf, matches, pickProjects, place } from './merge.js';
|
|
@@ -150,6 +151,10 @@ function Choice({ label, icon, says, onPress }) {
|
|
|
150
151
|
* the accounts the org has bound the App on (`linked`), so an org that installed
|
|
151
152
|
* the App in onboarding does not read as unconnected here. GitHub returns here,
|
|
152
153
|
* and this page finishes the connect (../back.ts).
|
|
154
|
+
*
|
|
155
|
+
* Disconnect lets go of it, so another account can be connected: the person's own
|
|
156
|
+
* link, or (for an org admin) the org's App accounts, which the platform also
|
|
157
|
+
* uninstalls on GitHub. It asks once before doing either.
|
|
153
158
|
*/
|
|
154
159
|
function GitHubLink({ onSync }) {
|
|
155
160
|
const host = useHost();
|
|
@@ -160,6 +165,7 @@ function GitHubLink({ onSync }) {
|
|
|
160
165
|
const installed = useRead(() => installations(target).catch(() => []), [], [target]);
|
|
161
166
|
const [note, setNote] = useState('');
|
|
162
167
|
const [busy, setBusy] = useState(false);
|
|
168
|
+
const [asking, setAsking] = useState(false);
|
|
163
169
|
useBack(target, true, setNote, () => {
|
|
164
170
|
me.reload();
|
|
165
171
|
installed.reload();
|
|
@@ -179,7 +185,31 @@ function GitHubLink({ onSync }) {
|
|
|
179
185
|
setBusy(false);
|
|
180
186
|
}
|
|
181
187
|
};
|
|
182
|
-
|
|
188
|
+
// The person's own link is theirs to drop; the org's App accounts are an org admin's.
|
|
189
|
+
const own = me.value?.connected === true;
|
|
190
|
+
const leave = c.connected && (own || host.admin);
|
|
191
|
+
const drop = async () => {
|
|
192
|
+
setBusy(true);
|
|
193
|
+
setNote('');
|
|
194
|
+
try {
|
|
195
|
+
await (own ? unlink(target) : disconnect(target, 'github'));
|
|
196
|
+
setAsking(false);
|
|
197
|
+
setNote(t('GitHub is disconnected. Connect it again to choose another account.'));
|
|
198
|
+
me.reload();
|
|
199
|
+
installed.reload();
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
setNote(e.message);
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
setBusy(false);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
return (_jsxs(XStack, { items: "center", gap: "$3", px: "$3", py: "$2.5", rounded: "$3", borderWidth: 1, borderColor: "$borderColor", bg: "$panel", flexWrap: "wrap", children: [_jsx(Github, { size: 16 }), _jsxs(YStack, { flex: 1, minW: 200, children: [_jsx(SizableText, { size: "$2", color: "$ink", children: c.connected ? t('GitHub connected as {login}', { login: `@${c.login}` }) : t('Connect GitHub to bring your repositories here') }), _jsx(SizableText, { size: "$1", color: "$soft", children: asking
|
|
209
|
+
? own
|
|
210
|
+
? t('Disconnect your GitHub from Hanzo?')
|
|
211
|
+
: t('Disconnect @{login}? Hanzo’s GitHub App is removed from it too, unless another organization uses it.', { login: c.login })
|
|
212
|
+
: note || (c.connected ? t('Choose repositories to mirror; each stays in step with GitHub.') : t('One step on GitHub, then pick the repositories to sync.')) })] }), c.connected && asking ? (_jsxs(XStack, { gap: "$2", children: [_jsx(Button, { size: "sm", variant: "outline", disabled: busy, onPress: () => setAsking(false), children: t('Cancel') }), _jsx(Button, { size: "sm", variant: "primary", disabled: busy, onPress: () => void drop(), children: busy ? t('Disconnecting…') : t('Disconnect') })] })) : c.connected ? (_jsxs(XStack, { gap: "$2", children: [_jsxs(Button, { size: "sm", variant: "outline", onPress: onSync, children: [_jsx(RefreshCw, { size: 14 }), t('Sync repositories')] }), leave ? (_jsx(Button, { size: "sm", variant: "outline", disabled: busy, onPress: () => setAsking(true), children: t('Disconnect') })) : null] })) : (_jsxs(Button, { size: "sm", variant: "primary", disabled: busy, onPress: () => void link(), children: [_jsx(Github, { size: 14 }), busy ? t('Opening GitHub…') : t('Connect GitHub')] }))] }));
|
|
183
213
|
}
|
|
184
214
|
/** The menus' words, marked (`phrase`) and drawn through `t`; GitHub and Hanzo are names, drawn as given. */
|
|
185
215
|
const KINDS = { all: phrase('Issues and pull requests'), issue: phrase('Issues'), pr: phrase('Pull requests') };
|
|
@@ -85,7 +85,7 @@ export function Integrations() {
|
|
|
85
85
|
? t('This deployment cannot connect GitHub yet.')
|
|
86
86
|
: me.connected
|
|
87
87
|
? t('Connected as @{login}', { login: me.login })
|
|
88
|
-
: t('Not connected'), trailing: me?.configured ? (me.connected ? (_jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void act(() => unlinkGithub(target), t('Your GitHub is disconnected'), mine.reload), children: t('Disconnect') })) : (_jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void away(() => connect(target, here())), children: t('Connect') }))) : null }), installed.error ? (_jsx(Row, { title: t('App installations'), detail: told(installed.error, t) })) : (installed.value.map((i) => (_jsx(Row, { leading: _jsx(Github, { size: 16 }), title: i.login, detail: [i.type, i.grant === 'all' ? t('every repository') : i.grant === 'selected' ? t('selected repositories') : ''].filter(Boolean).join(' · '), trailing: _jsx(SizableText, { size: "$1", color: i.connected ? '$ink' : '$soft', children: i.connected ? t('Installed') : t('Removed on GitHub') }) }, i.login)))), !installed.error && !installed.loading && installed.value.length === 0 ? (_jsx(Row, { title: t('No GitHub accounts installed'), detail: t('Install the App on a GitHub account to bring its repositories here.') })) : null] }), host.admin ? (_jsx(XStack, { children: _jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void away(() => authorize(target, 'github', here())), children: t('Install on a GitHub account') }) })) : (_jsx(SizableText, { size: "$1", color: "$soft", children: t('An org admin installs the App on a GitHub account.') }))] }), _jsxs(Group, { title: "Slack", detail: t('Talk to Hanzo from your workspace’s channels.'), children: [_jsxs(Card, { children: [_jsx(Row, { first: true, leading: _jsx(Slack, { size: 16 }), title: s?.connected && s.account ? s.account : 'Slack', detail: slack.error
|
|
88
|
+
: t('Not connected'), trailing: me?.configured ? (me.connected ? (_jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void act(() => unlinkGithub(target), t('Your GitHub is disconnected'), mine.reload), children: t('Disconnect') })) : (_jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void away(() => connect(target, here())), children: t('Connect') }))) : null }), installed.error ? (_jsx(Row, { title: t('App installations'), detail: told(installed.error, t) })) : (installed.value.map((i) => (_jsx(Row, { leading: _jsx(Github, { size: 16 }), title: i.login, detail: [i.type, i.grant === 'all' ? t('every repository') : i.grant === 'selected' ? t('selected repositories') : ''].filter(Boolean).join(' · '), trailing: _jsxs(XStack, { gap: "$2", items: "center", children: [_jsx(SizableText, { size: "$1", color: i.connected ? '$ink' : '$soft', children: i.connected ? t('Installed') : t('Removed on GitHub') }), host.admin ? (_jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void act(() => disconnect(target, 'github', i.login), t('@{login} is disconnected', { login: i.login }), installed.reload), children: t('Disconnect') })) : null] }) }, i.login)))), !installed.error && !installed.loading && installed.value.length === 0 ? (_jsx(Row, { title: t('No GitHub accounts installed'), detail: t('Install the App on a GitHub account to bring its repositories here.') })) : null] }), host.admin ? (_jsx(XStack, { children: _jsx(Button, { size: "sm", variant: "outline", disabled: working, onPress: () => void away(() => authorize(target, 'github', here())), children: t('Install on a GitHub account') }) })) : (_jsx(SizableText, { size: "$1", color: "$soft", children: t('An org admin installs the App on a GitHub account.') }))] }), _jsxs(Group, { title: "Slack", detail: t('Talk to Hanzo from your workspace’s channels.'), children: [_jsxs(Card, { children: [_jsx(Row, { first: true, leading: _jsx(Slack, { size: 16 }), title: s?.connected && s.account ? s.account : 'Slack', detail: slack.error
|
|
89
89
|
? told(slack.error, t)
|
|
90
90
|
: !s
|
|
91
91
|
? t('Reading…')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/build",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.88",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"description": "Hanzo Build — say what you want, watch it built, deployed and running. The builder as a component, mounted by the Hanzo app at hanzo.ai.",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@hanzo/gui": "8.3.5",
|
|
14
14
|
"@hanzo/i18n": "0.4.0",
|
|
15
15
|
"@hanzo/iam": "0.21.28",
|
|
16
|
-
"@hanzo/ui": "8.29.
|
|
16
|
+
"@hanzo/ui": "8.29.27",
|
|
17
17
|
"@hanzo/vite": "0.1.4",
|
|
18
18
|
"@hanzo/voice": "0.1.19",
|
|
19
19
|
"@hanzogui/lucide-icons-2": "8.3.5",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"@hanzo/gui": ">=8.3.5",
|
|
76
|
-
"@hanzo/ui": ">=8.29.
|
|
76
|
+
"@hanzo/ui": ">=8.29.27",
|
|
77
77
|
"@hanzogui/lucide-icons-2": ">=8.3.5",
|
|
78
78
|
"react": ">=19.2.8",
|
|
79
79
|
"@hanzo/voice": ">=0.1.19",
|