sitevision-cli 1.0.0-beta.2 → 1.0.0-beta.21
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/app.d.ts +1 -1
- package/dist/app.js +59 -8
- package/dist/cli.js +96 -39
- package/dist/commands/build.js +1 -1
- package/dist/commands/deploy.d.ts +2 -2
- package/dist/commands/deploy.js +135 -25
- package/dist/commands/dev.d.ts +8 -10
- package/dist/commands/dev.js +77 -366
- package/dist/commands/info.js +2 -2
- package/dist/commands/watch.js +5 -23
- package/dist/components/AnimatedLogo.js +8 -2
- package/dist/components/AuthLoginScreen.d.ts +21 -0
- package/dist/components/AuthLoginScreen.js +90 -0
- package/dist/components/DevPropertiesForm.d.ts +2 -1
- package/dist/components/DevPropertiesForm.js +198 -33
- package/dist/components/InfoScreen.js +2 -2
- package/dist/components/MainMenu.js +7 -2
- package/dist/components/PasswordInput.js +2 -1
- package/dist/components/SetupFlow.d.ts +2 -1
- package/dist/components/SetupFlow.js +100 -11
- package/dist/shell/AddonPicker.d.ts +14 -0
- package/dist/shell/AddonPicker.js +54 -0
- package/dist/shell/CommandPalette.d.ts +8 -0
- package/dist/shell/CommandPalette.js +63 -0
- package/dist/shell/ConfigForm.d.ts +36 -0
- package/dist/shell/ConfigForm.js +558 -0
- package/dist/shell/Frame.d.ts +59 -0
- package/dist/shell/Frame.js +134 -0
- package/dist/shell/Settings.d.ts +6 -0
- package/dist/shell/Settings.js +96 -0
- package/dist/shell/Shell.d.ts +9 -0
- package/dist/shell/Shell.js +586 -0
- package/dist/shell/Tabs.d.ts +36 -0
- package/dist/shell/Tabs.js +90 -0
- package/dist/shell/actions.d.ts +45 -0
- package/dist/shell/actions.js +0 -0
- package/dist/types/index.d.ts +44 -5
- package/dist/utils/config.d.ts +10 -0
- package/dist/utils/config.js +14 -0
- package/dist/utils/environments.d.ts +20 -0
- package/dist/utils/environments.js +74 -0
- package/dist/utils/i18n.d.ts +12 -0
- package/dist/utils/i18n.js +279 -0
- package/dist/utils/jsonc.d.ts +19 -0
- package/dist/utils/jsonc.js +74 -0
- package/dist/utils/keychain.d.ts +9 -0
- package/dist/utils/keychain.js +54 -0
- package/dist/utils/oauth2-auth.d.ts +64 -0
- package/dist/utils/oauth2-auth.js +242 -0
- package/dist/utils/password-prompt.d.ts +5 -0
- package/dist/utils/password-prompt.js +28 -0
- package/dist/utils/project-detection.d.ts +105 -6
- package/dist/utils/project-detection.js +411 -54
- package/dist/utils/session-cookie-auth.d.ts +35 -0
- package/dist/utils/session-cookie-auth.js +99 -0
- package/dist/utils/sitevision-api.d.ts +64 -5
- package/dist/utils/sitevision-api.js +195 -33
- package/dist/utils/tasks.d.ts +48 -0
- package/dist/utils/tasks.js +371 -0
- package/dist/utils/workspace.d.ts +17 -0
- package/dist/utils/workspace.js +67 -0
- package/package.json +3 -1
- package/readme.md +102 -121
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import Spinner from 'ink-spinner';
|
|
5
|
+
import { t } from '../utils/i18n.js';
|
|
6
|
+
import { beginOAuth2Login, openBrowser } from '../utils/oauth2-auth.js';
|
|
7
|
+
import { beginCookieLogin, } from '../utils/session-cookie-auth.js';
|
|
8
|
+
/**
|
|
9
|
+
* Ink-native interactive login for OAuth2 and session-cookie auth. Drives the
|
|
10
|
+
* browser and (for cookie) the "press Enter to capture" handoff through Ink's
|
|
11
|
+
* own input, so it works inside the TUI as well as the standalone command —
|
|
12
|
+
* neither needs to own raw stdin the way the old console prompt did.
|
|
13
|
+
*/
|
|
14
|
+
export function AuthLoginScreen({ method, devProperties, onComplete, onError, onCancel, }) {
|
|
15
|
+
const [phase, setPhase] = React.useState('starting');
|
|
16
|
+
const [authUrl, setAuthUrl] = React.useState('');
|
|
17
|
+
const [note, setNote] = React.useState('');
|
|
18
|
+
const [loginUrl, setLoginUrl] = React.useState('');
|
|
19
|
+
const cookieRef = React.useRef(null);
|
|
20
|
+
const cancelOAuthRef = React.useRef(null);
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
void (async () => {
|
|
23
|
+
if (method === 'oauth2') {
|
|
24
|
+
const session = beginOAuth2Login(devProperties);
|
|
25
|
+
if (!session) {
|
|
26
|
+
onError('OAuth2 is not fully configured (authorization/token endpoint or client ID missing).');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
cancelOAuthRef.current = session.cancel;
|
|
30
|
+
setAuthUrl(session.authUrl);
|
|
31
|
+
openBrowser(session.authUrl);
|
|
32
|
+
setPhase('awaiting');
|
|
33
|
+
const { token, error } = await session.complete();
|
|
34
|
+
cancelOAuthRef.current = null;
|
|
35
|
+
if (token) {
|
|
36
|
+
onComplete({ accessToken: token });
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
onError(error ?? 'OAuth2 login failed.');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const session = await beginCookieLogin(devProperties);
|
|
44
|
+
if (!session) {
|
|
45
|
+
onError('Could not open a login browser (is Chrome installed?). Set SITEVISION_SESSION_COOKIE or pass --cookie with a cookie copied from your browser.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
cookieRef.current = session;
|
|
49
|
+
setLoginUrl(session.loginUrl);
|
|
50
|
+
setPhase('awaiting');
|
|
51
|
+
}
|
|
52
|
+
})();
|
|
53
|
+
// Release resources if the screen unmounts before completing: close the
|
|
54
|
+
// browser (cookie) and the loopback server (oauth2, frees the port).
|
|
55
|
+
return () => {
|
|
56
|
+
void cookieRef.current?.close();
|
|
57
|
+
cookieRef.current = null;
|
|
58
|
+
cancelOAuthRef.current?.();
|
|
59
|
+
cancelOAuthRef.current = null;
|
|
60
|
+
};
|
|
61
|
+
// Run once: the parent mounts this fresh when a login is needed.
|
|
62
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
63
|
+
}, []);
|
|
64
|
+
useInput((_input, key) => {
|
|
65
|
+
if (key.escape) {
|
|
66
|
+
onCancel();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (method === 'cookie' && phase === 'awaiting' && key.return) {
|
|
70
|
+
const session = cookieRef.current;
|
|
71
|
+
if (!session)
|
|
72
|
+
return;
|
|
73
|
+
setPhase('capturing');
|
|
74
|
+
void (async () => {
|
|
75
|
+
const result = await session.capture();
|
|
76
|
+
if (result.cookie) {
|
|
77
|
+
cookieRef.current = null;
|
|
78
|
+
await session.close();
|
|
79
|
+
onComplete({ sessionCookie: result.cookie });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Keep the browser open so the user can navigate and retry.
|
|
83
|
+
setNote(result.error ?? 'No session cookie found.');
|
|
84
|
+
setPhase('awaiting');
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: method === 'oauth2' ? t('OAuth2 login') : t('Session cookie login') }) }), method === 'oauth2' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { children: [" ", t('Waiting for you to finish login in the browser…')] })] }), authUrl && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: t("If the browser didn't open, visit:") }), _jsx(Text, { children: authUrl })] }))] })) : (_jsxs(Box, { flexDirection: "column", children: [phase === 'starting' && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { children: [" ", t('Opening browser…')] })] })), phase === 'awaiting' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: t('A Chrome window is open at:') }), _jsx(Text, { color: "cyan", children: loginUrl }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('1. Log in to the site there, single sign-on included.') }), _jsx(Text, { children: t('2. Wait until the site itself has finished loading.') }), _jsx(Text, { children: t('3. Come back here and press Enter.') })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('Leave the browser window open; it closes once the session is captured.') }) })] })), phase === 'capturing' && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { children: [" ", t('Capturing session…')] })] })), note && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: note }) }))] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('Press Esc to cancel.') }) })] }));
|
|
90
|
+
}
|
|
@@ -3,8 +3,9 @@ interface Props {
|
|
|
3
3
|
projectRoot: string;
|
|
4
4
|
initialProperties?: DevProperties;
|
|
5
5
|
packageJson: PackageJson;
|
|
6
|
+
authOnly?: boolean;
|
|
6
7
|
onComplete: () => void;
|
|
7
8
|
onCancel: () => void;
|
|
8
9
|
}
|
|
9
|
-
export declare function DevPropertiesForm({ projectRoot, initialProperties, packageJson, onComplete, onCancel, }: Props): import("react").JSX.Element;
|
|
10
|
+
export declare function DevPropertiesForm({ projectRoot, initialProperties, packageJson, authOnly, onComplete, onCancel, }: Props): import("react").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -1,67 +1,232 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
4
|
import { TextInput } from './TextInput.js';
|
|
5
5
|
import { writeDevProperties } from '../utils/project-detection.js';
|
|
6
|
-
import { setDeployPassword, deleteDeployPassword } from '../utils/keychain.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
import { setDeployPassword, deleteDeployPassword, setOAuth2ClientSecret, } from '../utils/keychain.js';
|
|
7
|
+
import { DEFAULT_REDIRECT_PORT, discoverOAuth2Config, } from '../utils/oauth2-auth.js';
|
|
8
|
+
const LABELS = {
|
|
9
|
+
domain: 'Domain',
|
|
10
|
+
siteName: 'Site Name',
|
|
11
|
+
addonName: 'Addon Name',
|
|
12
|
+
username: 'Username',
|
|
13
|
+
authMethod: 'Auth Method',
|
|
14
|
+
password: 'Password',
|
|
15
|
+
oauthClientId: 'Client ID',
|
|
16
|
+
oauthAuthEndpoint: 'Authorization Endpoint',
|
|
17
|
+
oauthTokenEndpoint: 'Token Endpoint',
|
|
18
|
+
oauthScopes: 'Scopes',
|
|
19
|
+
oauthClientSecret: 'Client Secret',
|
|
20
|
+
sessionLoginUrl: 'Login URL',
|
|
21
|
+
useHTTP: 'Use HTTP',
|
|
22
|
+
};
|
|
23
|
+
const AUTH_METHODS = [
|
|
24
|
+
{ value: 'basic', label: 'Basic auth (username + password)' },
|
|
25
|
+
{ value: 'oauth2', label: 'OAuth2 bearer token (PKCE)' },
|
|
26
|
+
{ value: 'cookie', label: 'Session cookie (SAML / SSO login)' },
|
|
14
27
|
];
|
|
15
|
-
|
|
28
|
+
function parseScopes(raw) {
|
|
29
|
+
const scopes = raw
|
|
30
|
+
.split(/[\s,]+/)
|
|
31
|
+
.map(s => s.trim())
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
return scopes.length > 0 ? scopes : undefined;
|
|
34
|
+
}
|
|
35
|
+
export function DevPropertiesForm({ projectRoot, initialProperties, packageJson, authOnly, onComplete, onCancel, }) {
|
|
16
36
|
const [stepIndex, setStepIndex] = useState(0);
|
|
17
37
|
const [properties, setProperties] = useState(() => {
|
|
18
38
|
const defaults = {
|
|
19
39
|
domain: packageJson.developmentDomain || '',
|
|
20
40
|
addonName: packageJson.addonName || '',
|
|
21
41
|
siteName: packageJson.siteName || '',
|
|
42
|
+
authMethod: 'basic',
|
|
22
43
|
};
|
|
23
44
|
return { ...defaults, ...initialProperties };
|
|
24
45
|
});
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
const [oauth, setOauth] = useState(() => ({
|
|
47
|
+
authorizationEndpoint: initialProperties?.oauth2?.authorizationEndpoint ?? '',
|
|
48
|
+
tokenEndpoint: initialProperties?.oauth2?.tokenEndpoint ?? '',
|
|
49
|
+
clientId: initialProperties?.oauth2?.clientId ?? '',
|
|
50
|
+
scopes: initialProperties?.oauth2?.scopes?.join(' ') ?? '',
|
|
51
|
+
clientSecret: '',
|
|
52
|
+
}));
|
|
53
|
+
const [discoveryNote, setDiscoveryNote] = useState('');
|
|
54
|
+
const method = properties.authMethod ?? 'basic';
|
|
55
|
+
const isOAuth = method === 'oauth2';
|
|
56
|
+
// When OAuth2 is chosen, auto-fill the endpoints from the site's OpenID
|
|
57
|
+
// configuration (unauthenticated) so the user doesn't type them in.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (method !== 'oauth2' || !properties.domain)
|
|
60
|
+
return;
|
|
61
|
+
if (oauth.authorizationEndpoint && oauth.tokenEndpoint)
|
|
62
|
+
return;
|
|
63
|
+
let cancelled = false;
|
|
64
|
+
setDiscoveryNote('Looking up OAuth2 endpoints…');
|
|
65
|
+
void discoverOAuth2Config(properties.domain, properties.useHTTPForDevDeploy).then(discovered => {
|
|
66
|
+
if (cancelled)
|
|
67
|
+
return;
|
|
68
|
+
if (discovered) {
|
|
69
|
+
// Endpoints only — do NOT pre-fill scopes. `scopes_supported` is the
|
|
70
|
+
// provider's list, not what this client is granted (and casing may
|
|
71
|
+
// differ, e.g. advertised `all` vs client `ALL`), so requesting them
|
|
72
|
+
// causes `invalid_scope`. Empty scopes → the client's default scopes.
|
|
73
|
+
setOauth(previous => ({
|
|
74
|
+
...previous,
|
|
75
|
+
authorizationEndpoint: previous.authorizationEndpoint || discovered.authorizationEndpoint,
|
|
76
|
+
tokenEndpoint: previous.tokenEndpoint || discovered.tokenEndpoint,
|
|
77
|
+
}));
|
|
78
|
+
setDiscoveryNote('Endpoints auto-filled from the site OpenID config.');
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
setDiscoveryNote('Could not auto-discover endpoints — enter them below.');
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return () => {
|
|
85
|
+
cancelled = true;
|
|
86
|
+
};
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
}, [method, properties.domain]);
|
|
89
|
+
const methodSteps = method === 'oauth2'
|
|
90
|
+
? [
|
|
91
|
+
'oauthClientId',
|
|
92
|
+
'oauthAuthEndpoint',
|
|
93
|
+
'oauthTokenEndpoint',
|
|
94
|
+
'oauthScopes',
|
|
95
|
+
'oauthClientSecret',
|
|
96
|
+
]
|
|
97
|
+
: method === 'cookie'
|
|
98
|
+
? ['sessionLoginUrl']
|
|
99
|
+
: ['password'];
|
|
100
|
+
const steps = authOnly
|
|
101
|
+
? ['authMethod', ...methodSteps]
|
|
102
|
+
: [
|
|
103
|
+
'domain',
|
|
104
|
+
'siteName',
|
|
105
|
+
'addonName',
|
|
106
|
+
'username',
|
|
107
|
+
'authMethod',
|
|
108
|
+
...methodSteps,
|
|
109
|
+
'useHTTP',
|
|
110
|
+
];
|
|
111
|
+
const currentStep = steps[stepIndex];
|
|
112
|
+
const redirectPort = initialProperties?.oauth2?.redirectPort ?? DEFAULT_REDIRECT_PORT;
|
|
113
|
+
const advance = () => {
|
|
114
|
+
if (stepIndex < steps.length - 1) {
|
|
30
115
|
setStepIndex(stepIndex + 1);
|
|
31
116
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
117
|
+
};
|
|
118
|
+
const finalize = (props, fields) => {
|
|
119
|
+
const authMethod = props.authMethod ?? 'basic';
|
|
120
|
+
const domain = props.domain ?? '';
|
|
121
|
+
const username = props.username ?? '';
|
|
122
|
+
const finalProps = {
|
|
123
|
+
domain,
|
|
124
|
+
siteName: props.siteName ?? '',
|
|
125
|
+
addonName: props.addonName ?? '',
|
|
126
|
+
username,
|
|
127
|
+
authMethod,
|
|
128
|
+
useHTTPForDevDeploy: props.useHTTPForDevDeploy ?? false,
|
|
129
|
+
};
|
|
130
|
+
if (authMethod === 'oauth2') {
|
|
131
|
+
finalProps.oauth2 = {
|
|
132
|
+
authorizationEndpoint: fields.authorizationEndpoint,
|
|
133
|
+
tokenEndpoint: fields.tokenEndpoint,
|
|
134
|
+
clientId: fields.clientId,
|
|
135
|
+
scopes: parseScopes(fields.scopes),
|
|
136
|
+
...(initialProperties?.oauth2?.redirectPort && {
|
|
137
|
+
redirectPort: initialProperties.oauth2.redirectPort,
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
if (fields.clientSecret && domain && fields.clientId) {
|
|
141
|
+
setOAuth2ClientSecret(domain, fields.clientId, fields.clientSecret);
|
|
37
142
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
143
|
+
}
|
|
144
|
+
else if (authMethod === 'cookie') {
|
|
145
|
+
if (props.sessionLoginUrl) {
|
|
146
|
+
finalProps.sessionLoginUrl = props.sessionLoginUrl;
|
|
41
147
|
}
|
|
42
|
-
|
|
43
|
-
|
|
148
|
+
}
|
|
149
|
+
else if (props.password && domain && username) {
|
|
150
|
+
setDeployPassword(domain, username, props.password);
|
|
151
|
+
}
|
|
152
|
+
else if (domain && username) {
|
|
153
|
+
// Empty password — clear any stale keychain entry so deploy prompts.
|
|
154
|
+
deleteDeployPassword(domain, username);
|
|
155
|
+
}
|
|
156
|
+
writeDevProperties(projectRoot, finalProps);
|
|
157
|
+
onComplete();
|
|
158
|
+
};
|
|
159
|
+
// Update a top-level DevProperties field, then advance or finalize.
|
|
160
|
+
const submitProperty = (key, value) => {
|
|
161
|
+
const next = { ...properties, [key]: value };
|
|
162
|
+
setProperties(next);
|
|
163
|
+
if (steps[stepIndex] === steps[steps.length - 1]) {
|
|
164
|
+
finalize(next, oauth);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
advance();
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
// Update an OAuth field, then advance or finalize.
|
|
171
|
+
const submitOAuth = (key, value) => {
|
|
172
|
+
const next = { ...oauth, [key]: value };
|
|
173
|
+
setOauth(next);
|
|
174
|
+
if (steps[stepIndex] === steps[steps.length - 1]) {
|
|
175
|
+
finalize(properties, next);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
advance();
|
|
44
179
|
}
|
|
45
180
|
};
|
|
46
181
|
const renderInput = () => {
|
|
47
|
-
switch (currentStep
|
|
182
|
+
switch (currentStep) {
|
|
48
183
|
case 'domain':
|
|
49
|
-
return (_jsx(TextInput, { label: "Development Domain (e.g. www.sitevision.se)", defaultValue: properties.domain, placeholder: "sitevision.se", onSubmit:
|
|
184
|
+
return (_jsx(TextInput, { label: "Development Domain (e.g. www.sitevision.se)", defaultValue: properties.domain, placeholder: "sitevision.se", onSubmit: value => submitProperty('domain', value), onCancel: onCancel }, "domain"));
|
|
50
185
|
case 'siteName':
|
|
51
|
-
return (_jsx(TextInput, { label: "Site Name (Root node name)", defaultValue: properties.siteName, onSubmit:
|
|
186
|
+
return (_jsx(TextInput, { label: "Site Name (Root node name)", defaultValue: properties.siteName, onSubmit: value => submitProperty('siteName', value), onCancel: onCancel }, "siteName"));
|
|
52
187
|
case 'addonName':
|
|
53
|
-
return (_jsx(TextInput, { label: "Addon Name", defaultValue: properties.addonName, onSubmit:
|
|
188
|
+
return (_jsx(TextInput, { label: "Addon Name", defaultValue: properties.addonName, onSubmit: value => submitProperty('addonName', value), onCancel: onCancel }, "addonName"));
|
|
54
189
|
case 'username':
|
|
55
|
-
return (_jsx(TextInput, { label: "Username (usually your Sitevision Cloud email)", defaultValue: properties.username, onSubmit:
|
|
190
|
+
return (_jsx(TextInput, { label: "Username (usually your Sitevision Cloud email)", defaultValue: properties.username, onSubmit: value => submitProperty('username', value), onCancel: onCancel }, "username"));
|
|
191
|
+
case 'authMethod':
|
|
192
|
+
return (_jsx(MethodSelect, { defaultValue: method, onSubmit: value => submitProperty('authMethod', value) }, "authMethod"));
|
|
56
193
|
case 'password':
|
|
57
|
-
return (_jsx(TextInput, { label: "Password (saved in OS keychain \u2014 leave empty to prompt on each run)", type: "password", defaultValue: properties.password, onSubmit:
|
|
194
|
+
return (_jsx(TextInput, { label: "Password (saved in OS keychain \u2014 leave empty to prompt on each run)", type: "password", defaultValue: properties.password, onSubmit: value => submitProperty('password', value), onCancel: onCancel }, "password"));
|
|
195
|
+
case 'oauthClientId':
|
|
196
|
+
return (_jsx(TextInput, { label: "OAuth2 Client ID", defaultValue: oauth.clientId, onSubmit: value => submitOAuth('clientId', value), onCancel: onCancel }, "oauthClientId"));
|
|
197
|
+
case 'oauthAuthEndpoint':
|
|
198
|
+
return (_jsx(TextInput, { label: "Authorization Endpoint URL", defaultValue: oauth.authorizationEndpoint, onSubmit: value => submitOAuth('authorizationEndpoint', value), onCancel: onCancel }, "oauthAuthEndpoint"));
|
|
199
|
+
case 'oauthTokenEndpoint':
|
|
200
|
+
return (_jsx(TextInput, { label: "Token Endpoint URL", defaultValue: oauth.tokenEndpoint, onSubmit: value => submitOAuth('tokenEndpoint', value), onCancel: onCancel }, "oauthTokenEndpoint"));
|
|
201
|
+
case 'oauthScopes':
|
|
202
|
+
return (_jsx(TextInput, { label: "Scopes (space-separated \u2014 leave empty to use the client's default scopes; add offline_access, matching your client's casing, for a refresh token)", defaultValue: oauth.scopes, onSubmit: value => submitOAuth('scopes', value), onCancel: onCancel }, "oauthScopes"));
|
|
203
|
+
case 'oauthClientSecret':
|
|
204
|
+
return (_jsx(TextInput, { label: "Client Secret (OS keychain \u2014 required if your Sitevision client has a secret; leave empty only for a public client)", type: "password", defaultValue: oauth.clientSecret, onSubmit: value => submitOAuth('clientSecret', value), onCancel: onCancel }, "oauthClientSecret"));
|
|
205
|
+
case 'sessionLoginUrl':
|
|
206
|
+
return (_jsx(TextInput, { label: "Login URL (opened in a browser; blank = site root)", defaultValue: properties.sessionLoginUrl ??
|
|
207
|
+
(properties.domain ? `https://${properties.domain}/` : ''), onSubmit: value => submitProperty('sessionLoginUrl', value), onCancel: onCancel }, "sessionLoginUrl"));
|
|
58
208
|
case 'useHTTP':
|
|
59
|
-
return (_jsx(BooleanInput, { label: "Use HTTP for deployment? (y/n)", defaultValue: properties.useHTTPForDevDeploy ?? false, onSubmit:
|
|
209
|
+
return (_jsx(BooleanInput, { label: "Use HTTP for deployment? (y/n)", defaultValue: properties.useHTTPForDevDeploy ?? false, onSubmit: value => submitProperty('useHTTPForDevDeploy', value) }, "useHTTP"));
|
|
60
210
|
default:
|
|
61
211
|
return null;
|
|
62
212
|
}
|
|
63
213
|
};
|
|
64
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Setup Development Properties" }), _jsxs(Text, { children: [' ', "Step ", stepIndex + 1, " of ",
|
|
214
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Setup Development Properties" }), _jsxs(Text, { children: [' ', "Step ", stepIndex + 1, " of ", steps.length, ":", ' ', currentStep ? LABELS[currentStep] : ''] })] }), isOAuth && (_jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Whitelist this redirect URI on the OAuth2 client: http://127.0.0.1:", redirectPort, "/callback"] }), discoveryNote && _jsx(Text, { color: "yellow", children: discoveryNote })] })), _jsx(Box, { marginBottom: 1, children: steps.map((s, i) => (_jsx(Box, { marginRight: 1, children: _jsx(Text, { color: i <= stepIndex ? 'green' : 'gray', children: i < stepIndex ? '✓' : i === stepIndex ? '●' : '○' }) }, s))) }), _jsx(Box, { borderStyle: "single", borderColor: "gray", padding: 1, children: renderInput() })] }));
|
|
215
|
+
}
|
|
216
|
+
function MethodSelect({ defaultValue, onSubmit, }) {
|
|
217
|
+
const [index, setIndex] = useState(() => Math.max(0, AUTH_METHODS.findIndex(m => m.value === defaultValue)));
|
|
218
|
+
useInput((_input, key) => {
|
|
219
|
+
if (key.upArrow) {
|
|
220
|
+
setIndex(p => (p === 0 ? AUTH_METHODS.length - 1 : p - 1));
|
|
221
|
+
}
|
|
222
|
+
else if (key.downArrow) {
|
|
223
|
+
setIndex(p => (p === AUTH_METHODS.length - 1 ? 0 : p + 1));
|
|
224
|
+
}
|
|
225
|
+
else if (key.return) {
|
|
226
|
+
onSubmit(AUTH_METHODS[index].value);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Authentication method" }) }), AUTH_METHODS.map((m, i) => (_jsxs(Text, { color: i === index ? 'green' : undefined, children: [i === index ? '❯ ' : ' ', m.label] }, m.value))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move, Enter to select" }) })] }));
|
|
65
230
|
}
|
|
66
231
|
function BooleanInput({ label, defaultValue, onSubmit, }) {
|
|
67
232
|
useInput(input => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text, useInput } from 'ink';
|
|
3
|
-
import { getAppType } from '../utils/project-detection.js';
|
|
3
|
+
import { getAppType, localizedText, } from '../utils/project-detection.js';
|
|
4
4
|
import { checkSitevisionScriptsCompatibility } from '../utils/sitevision-scripts-runner.js';
|
|
5
5
|
export function InfoScreen({ project, onBack }) {
|
|
6
6
|
const appType = getAppType(project.manifest);
|
|
@@ -10,5 +10,5 @@ export function InfoScreen({ project, onBack }) {
|
|
|
10
10
|
onBack();
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: project.manifest.name })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), _jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Build Tooling" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "sitevision-scripts: " }), _jsx(Text, { children: scriptsCompat.installed ?? 'not installed' }), _jsxs(Text, { dimColor: true, children: [" (supported ", scriptsCompat.supportedRange, ")"] })] }), scriptsCompat.warning && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 ", scriptsCompat.warning] }) }))] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), !project.hasDevProperties && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "\u26A0 No dev properties found. Run setup-dev-properties to configure." }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { bold: true, children: "Project Root: " }), _jsx(Text, { dimColor: true, children: project.root })] }), _jsx(Box, { marginTop: 2, children: _jsx(Text, { dimColor: true, children: "Press Enter or ESC to return to menu" }) })] }));
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: localizedText(project.manifest.name) })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), _jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Build Tooling" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "sitevision-scripts: " }), _jsx(Text, { children: scriptsCompat.installed ?? 'not installed' }), _jsxs(Text, { dimColor: true, children: [" (supported ", scriptsCompat.supportedRange, ")"] })] }), scriptsCompat.warning && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 ", scriptsCompat.warning] }) }))] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), !project.hasDevProperties && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "\u26A0 No dev properties found. Run setup-dev-properties to configure." }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { bold: true, children: "Project Root: " }), _jsx(Text, { dimColor: true, children: project.root })] }), _jsx(Box, { marginTop: 2, children: _jsx(Text, { dimColor: true, children: "Press Enter or ESC to return to menu" }) })] }));
|
|
14
14
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
|
-
import { getAppType } from '../utils/project-detection.js';
|
|
4
|
+
import { getAppType, localizedText } from '../utils/project-detection.js';
|
|
5
5
|
export function MainMenu({ project, onSelect }) {
|
|
6
6
|
const appType = getAppType(project.manifest);
|
|
7
7
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
@@ -51,6 +51,11 @@ export function MainMenu({ project, onSelect }) {
|
|
|
51
51
|
value: 'deploy-production',
|
|
52
52
|
description: 'Deploy to production server',
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
label: '🔑 Auth Method',
|
|
56
|
+
value: 'change-auth',
|
|
57
|
+
description: 'Change the deploy authentication method',
|
|
58
|
+
},
|
|
54
59
|
{
|
|
55
60
|
label: 'ℹ️ Info',
|
|
56
61
|
value: 'info',
|
|
@@ -79,5 +84,5 @@ export function MainMenu({ project, onSelect }) {
|
|
|
79
84
|
onSelect(selectedItem.value);
|
|
80
85
|
}
|
|
81
86
|
});
|
|
82
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: project.manifest.name })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), project.hasSigningProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Signing Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Signing User: " }), _jsx(Text, { children: project.devProperties.signingUsername })] }), project.devProperties.certificateName && (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Certificate: " }), _jsx(Text, { children: project.devProperties.certificateName })] }))] })] })), !project.hasDevProperties && (_jsx(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "yellow", children: _jsx(Text, { color: "yellow", children: "\u26A0 No dev properties found. Some commands may not work." }) })), project.hasDevProperties && !project.hasSigningProperties && (_jsx(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "yellow", children: _jsx(Text, { color: "yellow", children: "\u26A0 No signing credentials configured. Run svc setup-signing to configure." }) })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Select a command:" }) }), _jsx(Box, { flexDirection: "column", children: items.map((item, index) => (_jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: index === selectedIndex ? 'cyan' : undefined, bold: index === selectedIndex, children: [index === selectedIndex ? '▶ ' : ' ', item.label, item.description && _jsxs(Text, { dimColor: true, children: [" - ", item.description] })] }) }, item.value))) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 arrows to navigate, Enter to select" }) })] }));
|
|
87
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: localizedText(project.manifest.name) })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), project.hasSigningProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Signing Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Signing User: " }), _jsx(Text, { children: project.devProperties.signingUsername })] }), project.devProperties.certificateName && (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Certificate: " }), _jsx(Text, { children: project.devProperties.certificateName })] }))] })] })), !project.hasDevProperties && (_jsx(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "yellow", children: _jsx(Text, { color: "yellow", children: "\u26A0 No dev properties found. Some commands may not work." }) })), project.hasDevProperties && !project.hasSigningProperties && (_jsx(Box, { marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "yellow", children: _jsx(Text, { color: "yellow", children: "\u26A0 No signing credentials configured. Run svc setup-signing to configure." }) })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Select a command:" }) }), _jsx(Box, { flexDirection: "column", children: items.map((item, index) => (_jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: index === selectedIndex ? 'cyan' : undefined, bold: index === selectedIndex, children: [index === selectedIndex ? '▶ ' : ' ', item.label, item.description && _jsxs(Text, { dimColor: true, children: [" - ", item.description] })] }) }, item.value))) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 arrows to navigate, Enter to select" }) })] }));
|
|
83
88
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import { t } from '../utils/i18n.js';
|
|
4
5
|
export function PasswordInput({ label = 'Enter Signing Password', showRememberOption = false, defaultRemember = false, rememberLabel = 'Save to OS keychain: ', onSubmit, onCancel, }) {
|
|
5
6
|
const [password, setPassword] = useState('');
|
|
6
7
|
const [remember, setRemember] = useState(defaultRemember);
|
|
@@ -26,5 +27,5 @@ export function PasswordInput({ label = 'Enter Signing Password', showRememberOp
|
|
|
26
27
|
setPassword(prev => prev + input);
|
|
27
28
|
}
|
|
28
29
|
});
|
|
29
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: label }) }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, children: _jsx(Text, { children: '*'.repeat(password.length) }) }), showRememberOption && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: rememberLabel }), _jsxs(Text, { color: remember ? 'green' : 'gray', children: ["[", remember ? 'x' : ' ', "]"] }),
|
|
30
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: label }) }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, children: _jsx(Text, { children: '*'.repeat(password.length) }) }), showRememberOption && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: rememberLabel }), _jsxs(Text, { color: remember ? 'green' : 'gray', children: ["[", remember ? 'x' : ' ', "]"] }), _jsxs(Text, { dimColor: true, children: [" ", t('(Tab to toggle)')] })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('Press Enter to submit, Esc to cancel') }) })] }));
|
|
30
31
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ProjectInfo } from '../utils/project-detection.js';
|
|
2
2
|
interface Props {
|
|
3
3
|
project: ProjectInfo;
|
|
4
|
+
onReload: () => void;
|
|
4
5
|
onComplete: () => void;
|
|
5
6
|
}
|
|
6
|
-
export declare function SetupFlow({ project, onComplete }: Props): import("react").JSX.Element | null;
|
|
7
|
+
export declare function SetupFlow({ project, onReload, onComplete }: Props): import("react").JSX.Element | null;
|
|
7
8
|
export {};
|