@hanzo/build 0.2.49 → 0.2.50
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/lib/choice.d.ts +22 -0
- package/lib/choice.js +3 -0
- package/lib/landing.js +23 -8
- package/package.json +1 -1
package/lib/choice.d.ts
CHANGED
|
@@ -21,6 +21,28 @@ export declare const boardKey: (org: string | null) => string;
|
|
|
21
21
|
export declare function pinCodebase(org: string | null, c: Codebase, ask?: string): void;
|
|
22
22
|
/** Which board Issues is showing. '' is every board. */
|
|
23
23
|
export declare function pinBoard(org: string | null, key: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* A repository on GitHub, chosen from the org's installation: the run works there.
|
|
26
|
+
* Its `full_name` is GitHub's address, `github.com/owner/name` — what the list
|
|
27
|
+
* shows, so a forge codebase of the same name is never mistaken for it, and what
|
|
28
|
+
* a coding run takes to clone, push and propose on GitHub.
|
|
29
|
+
*/
|
|
30
|
+
export interface HubRepo {
|
|
31
|
+
owner: string;
|
|
32
|
+
name: string;
|
|
33
|
+
full_name: string;
|
|
34
|
+
private: boolean;
|
|
35
|
+
default_branch: string;
|
|
36
|
+
pushed_at: string;
|
|
37
|
+
installation_id: number;
|
|
38
|
+
github: true;
|
|
39
|
+
}
|
|
40
|
+
export declare const isHub: (repo: {
|
|
41
|
+
github?: boolean;
|
|
42
|
+
full_name?: string;
|
|
43
|
+
} | null) => repo is HubRepo;
|
|
44
|
+
/** A GitHub listing row as the composer offers it. */
|
|
45
|
+
export declare const asHub: (r: Omit<HubRepo, 'github'>) => HubRepo;
|
|
24
46
|
export declare const isForge: (repo: {
|
|
25
47
|
forge?: boolean;
|
|
26
48
|
name?: string;
|
package/lib/choice.js
CHANGED
|
@@ -41,6 +41,9 @@ export function pinBoard(org, key) {
|
|
|
41
41
|
}
|
|
42
42
|
window.dispatchEvent(new CustomEvent('hanzo-board', { detail: key }));
|
|
43
43
|
}
|
|
44
|
+
export const isHub = (repo) => Boolean(repo && repo.github === true && repo.full_name?.startsWith('github.com/'));
|
|
45
|
+
/** A GitHub listing row as the composer offers it. */
|
|
46
|
+
export const asHub = (r) => ({ ...r, full_name: `github.com/${r.owner}/${r.name}`, github: true });
|
|
44
47
|
export const isForge = (repo) => Boolean(repo && repo.forge === true && repo.name);
|
|
45
48
|
const syncingKey = (org) => `hanzo.build.sync.${org ?? 'none'}`;
|
|
46
49
|
export function readPending(org) {
|
package/lib/landing.js
CHANGED
|
@@ -23,12 +23,13 @@ import { useLimits } from '@hanzo/ui/product/useLimits';
|
|
|
23
23
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
24
24
|
import { start, unhonoured } from './api/coding.js';
|
|
25
25
|
import { asRepo, chosen, codebases, one } from './api/codebases.js';
|
|
26
|
+
import { repos as githubRepos } from './api/github.js';
|
|
26
27
|
import { read, SETUP } from './api/environment.js';
|
|
27
28
|
import { SetupDialog } from './environment.js';
|
|
28
29
|
import { ENSO, limits as readLimits, models } from './api/models.js';
|
|
29
30
|
import { usePick } from './pick.js';
|
|
30
31
|
import { ready, SANDBOX } from './api/places.js';
|
|
31
|
-
import { isForge } from './choice.js';
|
|
32
|
+
import { asHub, isForge, isHub } from './choice.js';
|
|
32
33
|
import { useKept, usePlaces, useRead } from './data.js';
|
|
33
34
|
import { useHost, useTarget } from './host.js';
|
|
34
35
|
import { pane } from './pane.js';
|
|
@@ -111,12 +112,20 @@ export function Landing({ onStarted }) {
|
|
|
111
112
|
const env = useRead(signed && codebase ? () => read(t, codebase) : null, null, [t, signed, codebase]);
|
|
112
113
|
const place = places.value.find((p) => p.id === kept.place) ?? SANDBOX;
|
|
113
114
|
const known = useRef(new Map());
|
|
115
|
+
const hubs = useRef(new Map());
|
|
116
|
+
// The forge's codebases, then the repositories the org's GitHub installation
|
|
117
|
+
// grants. A GitHub row is chosen as GitHub's address, so a run on it clones,
|
|
118
|
+
// pushes and proposes on GitHub, where its people work. A GitHub read that
|
|
119
|
+
// fails leaves the forge's list standing.
|
|
114
120
|
const loadRepos = useCallback(async (q) => {
|
|
115
|
-
const page = await codebases(t, q);
|
|
121
|
+
const [page, hub] = await Promise.all([codebases(t, q), githubRepos(t, { q }).catch(() => null)]);
|
|
116
122
|
const repos = page.map(asRepo);
|
|
117
123
|
for (const r of repos)
|
|
118
124
|
known.current.set(r.name, r);
|
|
119
|
-
|
|
125
|
+
const github = (hub?.repos ?? []).map(asHub);
|
|
126
|
+
for (const r of github)
|
|
127
|
+
hubs.current.set(r.full_name.toLowerCase(), r);
|
|
128
|
+
return { repos: [...repos, ...github], next: null };
|
|
120
129
|
}, [t]);
|
|
121
130
|
// Drawn only once a forge codebase is chosen; one the forge no longer lists offers its default branch.
|
|
122
131
|
const home = kept.repo?.default_branch || 'main';
|
|
@@ -134,7 +143,8 @@ export function Landing({ onStarted }) {
|
|
|
134
143
|
return;
|
|
135
144
|
}
|
|
136
145
|
const repo = isForge(kept.repo) ? kept.repo : null;
|
|
137
|
-
|
|
146
|
+
const hub = isHub(kept.repo) ? kept.repo : null;
|
|
147
|
+
if (!repo && !hub && place.id) {
|
|
138
148
|
setNote(`A run on ${place.label} works in its own checkout: choose the codebase, or run it in Cloud.`);
|
|
139
149
|
return;
|
|
140
150
|
}
|
|
@@ -146,8 +156,8 @@ export function Landing({ onStarted }) {
|
|
|
146
156
|
// The name alone. The org rides the request, and a slash is not a repo name.
|
|
147
157
|
// No codebase is not sent, and the run starts a new project.
|
|
148
158
|
// An empty base or place is not sent: the default branch, and the sandbox.
|
|
149
|
-
repo: repo?.name,
|
|
150
|
-
base: repo ? kept.branch : undefined,
|
|
159
|
+
repo: repo?.name ?? hub?.full_name,
|
|
160
|
+
base: repo ? kept.branch : hub ? kept.branch || hub.default_branch : undefined,
|
|
151
161
|
targetId: place.id,
|
|
152
162
|
mode: kept.mode,
|
|
153
163
|
model: model === ENSO ? undefined : model,
|
|
@@ -195,13 +205,18 @@ export function Landing({ onStarted }) {
|
|
|
195
205
|
place: p,
|
|
196
206
|
})), [places.value, setUp]);
|
|
197
207
|
const branch = kept.branch || kept.repo?.default_branch || 'main';
|
|
198
|
-
const head = (_jsxs(XStack, { gap: 6, items: "center", flexWrap: "wrap", children: [_jsx(ChipSelect, { name: "Where the run runs", icon: place.id ? _jsx(Monitor, { size: 13 }) : _jsx(Cloud, { size: 13 }), label: place.id ? place.label : 'Cloud', chosen: placeItems.find((i) => i.place.id === place.id), items: placeItems, onChange: (i) => set({ place: i.place.id }), placeholder: "Search machines\u2026", loading: places.loading, error: places.error?.message ?? null, footer: _jsxs(YStack, { gap: "$0.5", children: [_jsx(SizableText, { size: "$1", color: "$ink", children: "Set up remote control" }), _jsxs(SizableText, { size: "$1", color: "$soft", children: ["Run", ' ', _jsx(SizableText, { size: "$1", color: "$ink", style: { fontFamily: 'var(--f-mono, ui-monospace, monospace)' }, children: "hanzo link" }), ' ', "on a machine: it joins this list, and a run there uses its checkout and credentials."] })] }) }), _jsx(RepoSelect, { open: picking, onOpenChange: setPicking, value: isForge(kept.repo) ? kept.repo : null, onChange: (r) => {
|
|
208
|
+
const head = (_jsxs(XStack, { gap: 6, items: "center", flexWrap: "wrap", children: [_jsx(ChipSelect, { name: "Where the run runs", icon: place.id ? _jsx(Monitor, { size: 13 }) : _jsx(Cloud, { size: 13 }), label: place.id ? place.label : 'Cloud', chosen: placeItems.find((i) => i.place.id === place.id), items: placeItems, onChange: (i) => set({ place: i.place.id }), placeholder: "Search machines\u2026", loading: places.loading, error: places.error?.message ?? null, footer: _jsxs(YStack, { gap: "$0.5", children: [_jsx(SizableText, { size: "$1", color: "$ink", children: "Set up remote control" }), _jsxs(SizableText, { size: "$1", color: "$soft", children: ["Run", ' ', _jsx(SizableText, { size: "$1", color: "$ink", style: { fontFamily: 'var(--f-mono, ui-monospace, monospace)' }, children: "hanzo link" }), ' ', "on a machine: it joins this list, and a run there uses its checkout and credentials."] })] }) }), _jsx(RepoSelect, { open: picking, onOpenChange: setPicking, value: isForge(kept.repo) || isHub(kept.repo) ? kept.repo : null, onChange: (r) => {
|
|
209
|
+
const hub = r.github ? hubs.current.get((r.full_name ?? "").toLowerCase()) : undefined;
|
|
210
|
+
if (hub) {
|
|
211
|
+
set({ repo: hub, branch: hub.default_branch });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
199
214
|
const row = known.current.get(r.name) ?? chosen(r);
|
|
200
215
|
set({ repo: row, branch: row.default_branch });
|
|
201
216
|
}, load: loadRepos, troubleshoot: {
|
|
202
217
|
label: 'Missing a GitHub repository? Bring it onto the forge',
|
|
203
218
|
onPress: () => host.go(path({ kind: 'screen', screen: 'sync' })),
|
|
204
|
-
}, connect: _jsx(XStack, { justify: "flex-end", children: _jsx(FooterLink, { label: "Refresh list", onPress: () => setRound((n) => n + 1) }) }), note: "Repositories on the forge. Type to search.", action: {
|
|
219
|
+
}, connect: _jsx(XStack, { justify: "flex-end", children: _jsx(FooterLink, { label: "Refresh list", onPress: () => setRound((n) => n + 1) }) }), note: "Repositories on the forge and on your organization's GitHub. Type to search.", action: {
|
|
205
220
|
label: 'Add to project',
|
|
206
221
|
onPress: (r) => {
|
|
207
222
|
const row = known.current.get(r.name);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/build",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.50",
|
|
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.",
|