@shopify/cli-kit 4.9.4 → 5.0.0
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/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.d.ts +5 -0
- package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.js +22 -0
- package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.js.map +1 -1
- package/dist/private/node/api/graphql.d.ts +2 -1
- package/dist/private/node/api/graphql.js +12 -1
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api.d.ts +2 -0
- package/dist/private/node/api.js +49 -22
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/command-json-schema.js +1 -0
- package/dist/private/node/command-json-schema.js.map +1 -1
- package/dist/private/node/constants.d.ts +1 -0
- package/dist/private/node/constants.js +1 -0
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/dev-instance-output.d.ts +47 -0
- package/dist/private/node/dev-instance-output.js +143 -0
- package/dist/private/node/dev-instance-output.js.map +1 -0
- package/dist/private/node/json-error.d.ts +1 -15
- package/dist/private/node/json-error.js +4 -98
- package/dist/private/node/json-error.js.map +1 -1
- package/dist/private/node/output-context.d.ts +8 -0
- package/dist/private/node/output-context.js +10 -0
- package/dist/private/node/output-context.js.map +1 -0
- package/dist/private/node/output.test.js +4 -4
- package/dist/private/node/output.test.js.map +1 -1
- package/dist/private/node/session/automation-token.d.ts +50 -0
- package/dist/private/node/session/automation-token.js +77 -0
- package/dist/private/node/session/automation-token.js.map +1 -0
- package/dist/private/node/session/exchange.d.ts +2 -1
- package/dist/private/node/session/exchange.js +5 -3
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/session/permanent-store-domain.d.ts +21 -0
- package/dist/private/node/session/permanent-store-domain.js +72 -0
- package/dist/private/node/session/permanent-store-domain.js.map +1 -0
- package/dist/private/node/session.d.ts +3 -2
- package/dist/private/node/session.js +12 -3
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/themes/trust-challenge.d.ts +31 -0
- package/dist/private/node/themes/trust-challenge.js +143 -0
- package/dist/private/node/themes/trust-challenge.js.map +1 -0
- package/dist/private/node/ui/alert.js +1 -1
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +2 -7
- package/dist/private/node/ui/components/ConcurrentOutput.js +4 -8
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.js +9 -15
- package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.test.js +45 -107
- package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
- package/dist/private/node/ui/components/LoadingIndicator.d.ts +7 -0
- package/dist/private/node/ui/components/LoadingIndicator.js +22 -0
- package/dist/private/node/ui/components/LoadingIndicator.js.map +1 -0
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/api/admin.js +13 -0
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/graphql.js +38 -7
- package/dist/public/node/api/graphql.js.map +1 -1
- package/dist/public/node/archiver.js +13 -6
- package/dist/public/node/archiver.js.map +1 -1
- package/dist/public/node/base-command.d.ts +6 -0
- package/dist/public/node/base-command.js +97 -16
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/dev-instance.d.ts +138 -0
- package/dist/public/node/dev-instance.js +365 -0
- package/dist/public/node/dev-instance.js.map +1 -0
- package/dist/public/node/environment.d.ts +6 -3
- package/dist/public/node/environment.js +11 -4
- package/dist/public/node/environment.js.map +1 -1
- package/dist/public/node/error/index.js +2 -1
- package/dist/public/node/error/index.js.map +1 -1
- package/dist/public/node/error/schema.d.ts +24 -24
- package/dist/public/node/error/serialization.d.ts +8 -0
- package/dist/public/node/error/serialization.js +103 -0
- package/dist/public/node/error/serialization.js.map +1 -0
- package/dist/public/node/graphiql/server.js +18 -2
- package/dist/public/node/graphiql/server.js.map +1 -1
- package/dist/public/node/is-global.js +2 -1
- package/dist/public/node/is-global.js.map +1 -1
- package/dist/public/node/notifications-system.d.ts +6 -6
- package/dist/public/node/path.d.ts +19 -3
- package/dist/public/node/path.js +21 -3
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/session.d.ts +36 -2
- package/dist/public/node/session.js +48 -4
- package/dist/public/node/session.js.map +1 -1
- package/dist/public/node/system.d.ts +4 -0
- package/dist/public/node/system.js +39 -9
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/themes/api.d.ts +9 -0
- package/dist/public/node/themes/api.js +50 -22
- package/dist/public/node/themes/api.js.map +1 -1
- package/dist/public/node/themes/theme-manager.d.ts +8 -1
- package/dist/public/node/themes/theme-manager.js +1 -1
- package/dist/public/node/themes/theme-manager.js.map +1 -1
- package/dist/public/node/tree-kill.js +12 -2
- package/dist/public/node/tree-kill.js.map +1 -1
- package/dist/public/node/ui/components.d.ts +1 -0
- package/dist/public/node/ui/components.js +1 -0
- package/dist/public/node/ui/components.js.map +1 -1
- package/dist/public/node/ui.d.ts +24 -4
- package/dist/public/node/ui.js +41 -18
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/upgrade/output.d.ts +17 -0
- package/dist/public/node/upgrade/output.js +51 -0
- package/dist/public/node/upgrade/output.js.map +1 -0
- package/dist/public/node/upgrade/result.d.ts +8 -0
- package/dist/public/node/upgrade/result.js +21 -0
- package/dist/public/node/upgrade/result.js.map +1 -0
- package/dist/public/node/upgrade/types.d.ts +61 -0
- package/dist/public/node/upgrade/types.js +46 -0
- package/dist/public/node/upgrade/types.js.map +1 -0
- package/dist/public/node/upgrade.d.ts +8 -0
- package/dist/public/node/upgrade.js +57 -22
- package/dist/public/node/upgrade.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/private/node/ui/components/TextAnimation.d.ts +0 -10
- package/dist/private/node/ui/components/TextAnimation.js +0 -56
- package/dist/private/node/ui/components/TextAnimation.js.map +0 -1
- package/dist/private/node/ui/components/TextAnimation.test.d.ts +0 -1
- package/dist/private/node/ui/components/TextAnimation.test.js +0 -73
- package/dist/private/node/ui/components/TextAnimation.test.js.map +0 -1
|
@@ -12,7 +12,7 @@ const typeToLogLevel = {
|
|
|
12
12
|
};
|
|
13
13
|
export function alert(options) {
|
|
14
14
|
const { type, headline, body, nextSteps, reference, link, customSections, orderedNextSteps = false, renderOptions, } = options;
|
|
15
|
-
if ((type === 'info' || type === 'warning') && commandEventOutputMode() === 'json') {
|
|
15
|
+
if ((type === 'info' || type === 'warning' || type === 'success') && commandEventOutputMode() === 'json') {
|
|
16
16
|
const message = alertMessage(options);
|
|
17
17
|
if (type === 'warning')
|
|
18
18
|
outputWarn(message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../../src/private/node/ui/alert.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAa,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,qBAAqB,EAAC,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAC,UAAU,EAAC,MAAM,UAAU,CAAA;AACnC,OAAO,EAAC,sBAAsB,EAAC,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAW,UAAU,EAAE,UAAU,EAAC,MAAM,gCAAgC,CAAA;AAC/E,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,MAAM,cAAc,GAAyC;IAC3D,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,OAAO;CACf,CAAA;AAMD,MAAM,UAAU,KAAK,CAAC,OAAqB;IACzC,MAAM,EACJ,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,SAAS,EACT,IAAI,EACJ,cAAc,EACd,gBAAgB,GAAG,KAAK,EACxB,aAAa,GACd,GAAG,OAAO,CAAA;IAEX,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,SAAS,CAAC,IAAI,sBAAsB,EAAE,KAAK,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../../src/private/node/ui/alert.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Alert, AlertProps} from './components/Alert.js'\nimport {tokenItemToJsonString} from './components/token-item.js'\nimport {renderOnce} from '../ui.js'\nimport {commandEventOutputMode} from '../command-event-context.js'\nimport {LogLevel, outputInfo, outputWarn} from '../../../public/node/output.js'\nimport React from 'react'\n\nimport {RenderOptions} from 'ink'\n\nconst typeToLogLevel: Record<AlertProps['type'], LogLevel> = {\n info: 'info',\n warning: 'warn',\n success: 'info',\n error: 'error',\n}\n\nexport interface AlertOptions extends AlertProps {\n renderOptions?: RenderOptions\n}\n\nexport function alert(options: AlertOptions) {\n const {\n type,\n headline,\n body,\n nextSteps,\n reference,\n link,\n customSections,\n orderedNextSteps = false,\n renderOptions,\n } = options\n\n if ((type === 'info' || type === 'warning' || type === 'success') && commandEventOutputMode() === 'json') {\n const message = alertMessage(options)\n if (type === 'warning') outputWarn(message)\n else outputInfo(message)\n return message\n }\n\n return renderOnce(\n <Alert\n type={type}\n headline={headline}\n body={body}\n nextSteps={nextSteps}\n reference={reference}\n link={link}\n orderedNextSteps={orderedNextSteps}\n customSections={customSections}\n />,\n {logLevel: typeToLogLevel[type], renderOptions},\n )\n}\n\nfunction alertMessage({headline, body, nextSteps, reference, link, customSections}: AlertProps): string {\n const sections = [\n headline ? tokenItemToJsonString(headline) : undefined,\n body ? tokenItemToJsonString(body) : undefined,\n nextSteps?.length ? `Next steps:\\n${nextSteps.map(tokenItemToJsonString).join('\\n')}` : undefined,\n reference?.length ? `Reference:\\n${reference.map(tokenItemToJsonString).join('\\n')}` : undefined,\n link ? tokenItemToJsonString({link}) : undefined,\n ...(customSections ?? []).map((section) => {\n const content =\n typeof section.body === 'object' && 'tabularData' in section.body\n ? section.body.tabularData.map((row) => row.map(tokenItemToJsonString).join('\\t')).join('\\n')\n : tokenItemToJsonString(section.body)\n return section.title ? `${section.title}:\\n${content}` : content\n }),\n ]\n return sections.filter((section): section is string => section !== undefined).join('\\n\\n')\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext } from '../../output-context.js';
|
|
1
2
|
import { type OutputProcess } from '../../../../public/node/output.js';
|
|
2
3
|
import { AbortSignal } from '../../../../public/node/abort.js';
|
|
3
4
|
import { FunctionComponent } from 'react';
|
|
@@ -13,12 +14,6 @@ export interface ConcurrentOutputProps {
|
|
|
13
14
|
keepRunningAfterProcessesResolve?: boolean;
|
|
14
15
|
useAlternativeColorPalette?: boolean;
|
|
15
16
|
}
|
|
16
|
-
interface ConcurrentOutputContext {
|
|
17
|
-
outputPrefix?: string;
|
|
18
|
-
/** Controls ANSI stripping for terminal output. JSON diagnostics are always unstyled. */
|
|
19
|
-
stripAnsi?: boolean;
|
|
20
|
-
}
|
|
21
|
-
declare function useConcurrentOutputContext<T>(context: ConcurrentOutputContext, callback: () => T): T;
|
|
22
17
|
/** Runs finite processes concurrently and routes their output through the shared diagnostic context. */
|
|
23
18
|
export declare function runConcurrentProcessesForJson({ processes, abortSignal, }: Pick<ConcurrentOutputProps, 'processes' | 'abortSignal'>): Promise<void>;
|
|
24
19
|
/**
|
|
@@ -55,4 +50,4 @@ export declare function runConcurrentProcessesForJson({ processes, abortSignal,
|
|
|
55
50
|
* ```
|
|
56
51
|
*/
|
|
57
52
|
declare const ConcurrentOutput: FunctionComponent<ConcurrentOutputProps>;
|
|
58
|
-
export { ConcurrentOutput, ConcurrentOutputContext, useConcurrentOutputContext };
|
|
53
|
+
export { ConcurrentOutput, ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getConcurrentOutputContext, useConcurrentOutputContext } from '../../output-context.js';
|
|
1
2
|
import { outputInfo } from '../../../../public/node/output.js';
|
|
2
3
|
import { useComplete } from '../../ui.js';
|
|
3
4
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
@@ -5,7 +6,6 @@ import { Box, Static, Text } from 'ink';
|
|
|
5
6
|
import figures from 'figures';
|
|
6
7
|
import stripAnsi from 'strip-ansi';
|
|
7
8
|
import { Writable } from 'stream';
|
|
8
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
9
9
|
import { StringDecoder } from 'node:string_decoder';
|
|
10
10
|
function addLeadingZero(number) {
|
|
11
11
|
if (number < 10) {
|
|
@@ -22,10 +22,6 @@ function currentTime() {
|
|
|
22
22
|
const seconds = addLeadingZero(currentDateTime.getSeconds());
|
|
23
23
|
return `${hours}:${minutes}:${seconds}`;
|
|
24
24
|
}
|
|
25
|
-
const outputContextStore = new AsyncLocalStorage();
|
|
26
|
-
function useConcurrentOutputContext(context, callback) {
|
|
27
|
-
return outputContextStore.run(context, callback);
|
|
28
|
-
}
|
|
29
25
|
/** Runs finite processes concurrently and routes their output through the shared diagnostic context. */
|
|
30
26
|
export async function runConcurrentProcessesForJson({ processes, abortSignal, }) {
|
|
31
27
|
await Promise.all(processes.map(async (process) => {
|
|
@@ -45,7 +41,7 @@ export async function runConcurrentProcessesForJson({ processes, abortSignal, })
|
|
|
45
41
|
next();
|
|
46
42
|
return;
|
|
47
43
|
}
|
|
48
|
-
const currentPrefix =
|
|
44
|
+
const currentPrefix = getConcurrentOutputContext()?.outputPrefix ?? process.prefix;
|
|
49
45
|
if (!hasPendingLine)
|
|
50
46
|
prefix = currentPrefix;
|
|
51
47
|
const lines = (pending + decoder.write(chunk)).split(/\r?\n/);
|
|
@@ -141,7 +137,7 @@ const ConcurrentOutput = ({ processes, prefixColumnSize, abortSignal, showTimest
|
|
|
141
137
|
const writableStream = useCallback((process, prefixes) => {
|
|
142
138
|
return new Writable({
|
|
143
139
|
write(chunk, _encoding, next) {
|
|
144
|
-
const context =
|
|
140
|
+
const context = getConcurrentOutputContext();
|
|
145
141
|
const prefix = context?.outputPrefix ?? process.prefix;
|
|
146
142
|
const shouldStripAnsi = context?.stripAnsi ?? true;
|
|
147
143
|
const log = chunk.toString('utf8').replace(/(\n)$/, '');
|
|
@@ -211,5 +207,5 @@ const ConcurrentOutput = ({ processes, prefixColumnSize, abortSignal, showTimest
|
|
|
211
207
|
line)))))));
|
|
212
208
|
}));
|
|
213
209
|
};
|
|
214
|
-
export { ConcurrentOutput, useConcurrentOutputContext };
|
|
210
|
+
export { ConcurrentOutput, getConcurrentOutputContext, useConcurrentOutputContext };
|
|
215
211
|
//# sourceMappingURL=ConcurrentOutput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {outputInfo, type OutputProcess} from '../../../../public/node/output.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react'\nimport {Box, Static, Text, TextProps} from 'ink'\nimport figures from 'figures'\nimport stripAnsi from 'strip-ansi'\n\nimport {Writable} from 'stream'\nimport {AsyncLocalStorage} from 'node:async_hooks'\nimport {StringDecoder} from 'node:string_decoder'\n\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n prefixColumnSize?: number\n abortSignal: AbortSignal\n showTimestamps?: boolean\n /**\n * Keeps terminal UI running after all processes finish. Defaults to false.\n * In JSON mode, false uses finite progress/diagnostic events; true retains streaming terminal UI.\n */\n keepRunningAfterProcessesResolve?: boolean\n useAlternativeColorPalette?: boolean\n}\n\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nfunction addLeadingZero(number: number) {\n if (number < 10) {\n return `0${number}`\n } else {\n return number.toString()\n }\n}\n\nfunction currentTime() {\n const currentDateTime = new Date()\n const hours = addLeadingZero(currentDateTime.getHours())\n const minutes = addLeadingZero(currentDateTime.getMinutes())\n const seconds = addLeadingZero(currentDateTime.getSeconds())\n return `${hours}:${minutes}:${seconds}`\n}\n\ninterface ConcurrentOutputContext {\n outputPrefix?: string\n /** Controls ANSI stripping for terminal output. JSON diagnostics are always unstyled. */\n stripAnsi?: boolean\n}\n\nconst outputContextStore = new AsyncLocalStorage<ConcurrentOutputContext>()\n\nfunction useConcurrentOutputContext<T>(context: ConcurrentOutputContext, callback: () => T): T {\n return outputContextStore.run(context, callback)\n}\n\n/** Runs finite processes concurrently and routes their output through the shared diagnostic context. */\nexport async function runConcurrentProcessesForJson({\n processes,\n abortSignal,\n}: Pick<ConcurrentOutputProps, 'processes' | 'abortSignal'>): Promise<void> {\n await Promise.all(\n processes.map(async (process) => {\n const createStream = () => {\n const decoder = new StringDecoder('utf8')\n let pending = ''\n let hasPendingLine = false\n let prefix = process.prefix\n const emitLine = (line: string) => {\n const message = stripAnsi(line)\n if (message.trim().length > 0) outputInfo(`${prefix}: ${message}`)\n }\n const stream = new Writable({\n write(chunk, _encoding, next) {\n if (chunk.length === 0) {\n next()\n return\n }\n const currentPrefix = outputContextStore.getStore()?.outputPrefix ?? process.prefix\n if (!hasPendingLine) prefix = currentPrefix\n const lines = (pending + decoder.write(chunk)).split(/\\r?\\n/)\n pending = lines.pop() ?? ''\n for (const line of lines) {\n emitLine(line)\n prefix = currentPrefix\n }\n hasPendingLine = chunk[chunk.length - 1] !== 10\n next()\n },\n })\n return {\n stream,\n flush: () => {\n emitLine((pending + decoder.end()).replace(/\\r$/, ''))\n pending = ''\n hasPendingLine = false\n },\n }\n }\n const stdout = createStream()\n const stderr = createStream()\n try {\n await process.action(stdout.stream, stderr.stream, abortSignal)\n } finally {\n stdout.flush()\n stderr.flush()\n }\n }),\n )\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n prefixColumnSize,\n abortSignal,\n showTimestamps = true,\n keepRunningAfterProcessesResolve = false,\n useAlternativeColorPalette = false,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const [completionResult, setCompletionResult] = useState<{error?: Error} | null>(null)\n const complete = useComplete()\n const concurrentColors: TextProps['color'][] = useMemo(\n () =>\n useAlternativeColorPalette\n ? ['#b994c3', '#e69e19', '#d17a73', 'cyan', 'magenta', 'blue']\n : ['yellow', 'cyan', 'magenta', 'green', 'blue'],\n [useAlternativeColorPalette],\n )\n\n const calculatedPrefixColumnSize = useMemo(() => {\n const maxColumnSize = 25\n\n // If the prefixColumnSize is not provided, we calculate it based on the longest process prefix\n const columnSize =\n prefixColumnSize ??\n processes.reduce((maxPrefixLength, process) => Math.max(maxPrefixLength, process.prefix.length), 0)\n\n // Apply overall limit to the prefix column size\n return Math.min(columnSize, maxColumnSize)\n }, [processes, prefixColumnSize])\n\n const addPrefix = (prefix: string, prefixes: string[]) => {\n const index = prefixes.indexOf(prefix)\n if (index !== -1) {\n return index\n }\n prefixes.push(prefix)\n return prefixes.length - 1\n }\n\n const lineColor = useCallback(\n (index: number) => {\n const colorIndex = index % concurrentColors.length\n return concurrentColors[colorIndex]\n },\n [concurrentColors],\n )\n\n const writableStream = useCallback(\n (process: OutputProcess, prefixes: string[]) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const context = outputContextStore.getStore()\n const prefix = context?.outputPrefix ?? process.prefix\n const shouldStripAnsi = context?.stripAnsi ?? true\n const log = chunk.toString('utf8').replace(/(\\n)$/, '')\n\n const index = addPrefix(prefix, prefixes)\n\n const lines = shouldStripAnsi ? stripAnsi(log).split(/\\n/) : log.split(/\\n/)\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix,\n lines,\n },\n ])\n next()\n },\n })\n },\n [lineColor],\n )\n\n const formatPrefix = (prefix: string) => {\n // Truncate prefix if needed\n if (prefix.length > calculatedPrefixColumnSize) {\n return prefix.substring(0, calculatedPrefixColumnSize)\n }\n\n return `${' '.repeat(calculatedPrefixColumnSize - prefix.length)}${prefix}`\n }\n\n useEffect(() => {\n const runProcesses = async () => {\n const prefixes: string[] = []\n\n try {\n await Promise.all(\n processes.map(async (process) => {\n const stdout = writableStream(process, prefixes)\n const stderr = writableStream(process, prefixes)\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({})\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error: unknown) {\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({error: error as Error})\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n runProcesses()\n }, [abortSignal, processes, writableStream, keepRunningAfterProcessesResolve])\n\n useEffect(() => {\n if (completionResult !== null) {\n complete(completionResult.error)\n }\n }, [completionResult, complete])\n\n const {lineVertical} = figures\n\n return (\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n <Text>\n {showTimestamps ? (\n <Text>\n {currentTime()} {lineVertical}{' '}\n </Text>\n ) : null}\n <Text color={chunk.color}>{formatPrefix(chunk.prefix)}</Text>\n <Text>\n {' '}\n {lineVertical} {line}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n )\n}\nexport {ConcurrentOutput, ConcurrentOutputContext, useConcurrentOutputContext}\n"]}
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext} from '../../output-context.js'\nimport {outputInfo, type OutputProcess} from '../../../../public/node/output.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react'\nimport {Box, Static, Text, TextProps} from 'ink'\nimport figures from 'figures'\nimport stripAnsi from 'strip-ansi'\n\nimport {Writable} from 'stream'\nimport {StringDecoder} from 'node:string_decoder'\n\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n prefixColumnSize?: number\n abortSignal: AbortSignal\n showTimestamps?: boolean\n /**\n * Keeps terminal UI running after all processes finish. Defaults to false.\n * In JSON mode, false uses finite progress/diagnostic events; true retains streaming terminal UI.\n */\n keepRunningAfterProcessesResolve?: boolean\n useAlternativeColorPalette?: boolean\n}\n\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nfunction addLeadingZero(number: number) {\n if (number < 10) {\n return `0${number}`\n } else {\n return number.toString()\n }\n}\n\nfunction currentTime() {\n const currentDateTime = new Date()\n const hours = addLeadingZero(currentDateTime.getHours())\n const minutes = addLeadingZero(currentDateTime.getMinutes())\n const seconds = addLeadingZero(currentDateTime.getSeconds())\n return `${hours}:${minutes}:${seconds}`\n}\n\n/** Runs finite processes concurrently and routes their output through the shared diagnostic context. */\nexport async function runConcurrentProcessesForJson({\n processes,\n abortSignal,\n}: Pick<ConcurrentOutputProps, 'processes' | 'abortSignal'>): Promise<void> {\n await Promise.all(\n processes.map(async (process) => {\n const createStream = () => {\n const decoder = new StringDecoder('utf8')\n let pending = ''\n let hasPendingLine = false\n let prefix = process.prefix\n const emitLine = (line: string) => {\n const message = stripAnsi(line)\n if (message.trim().length > 0) outputInfo(`${prefix}: ${message}`)\n }\n const stream = new Writable({\n write(chunk, _encoding, next) {\n if (chunk.length === 0) {\n next()\n return\n }\n const currentPrefix = getConcurrentOutputContext()?.outputPrefix ?? process.prefix\n if (!hasPendingLine) prefix = currentPrefix\n const lines = (pending + decoder.write(chunk)).split(/\\r?\\n/)\n pending = lines.pop() ?? ''\n for (const line of lines) {\n emitLine(line)\n prefix = currentPrefix\n }\n hasPendingLine = chunk[chunk.length - 1] !== 10\n next()\n },\n })\n return {\n stream,\n flush: () => {\n emitLine((pending + decoder.end()).replace(/\\r$/, ''))\n pending = ''\n hasPendingLine = false\n },\n }\n }\n const stdout = createStream()\n const stderr = createStream()\n try {\n await process.action(stdout.stream, stderr.stream, abortSignal)\n } finally {\n stdout.flush()\n stderr.flush()\n }\n }),\n )\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n prefixColumnSize,\n abortSignal,\n showTimestamps = true,\n keepRunningAfterProcessesResolve = false,\n useAlternativeColorPalette = false,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const [completionResult, setCompletionResult] = useState<{error?: Error} | null>(null)\n const complete = useComplete()\n const concurrentColors: TextProps['color'][] = useMemo(\n () =>\n useAlternativeColorPalette\n ? ['#b994c3', '#e69e19', '#d17a73', 'cyan', 'magenta', 'blue']\n : ['yellow', 'cyan', 'magenta', 'green', 'blue'],\n [useAlternativeColorPalette],\n )\n\n const calculatedPrefixColumnSize = useMemo(() => {\n const maxColumnSize = 25\n\n // If the prefixColumnSize is not provided, we calculate it based on the longest process prefix\n const columnSize =\n prefixColumnSize ??\n processes.reduce((maxPrefixLength, process) => Math.max(maxPrefixLength, process.prefix.length), 0)\n\n // Apply overall limit to the prefix column size\n return Math.min(columnSize, maxColumnSize)\n }, [processes, prefixColumnSize])\n\n const addPrefix = (prefix: string, prefixes: string[]) => {\n const index = prefixes.indexOf(prefix)\n if (index !== -1) {\n return index\n }\n prefixes.push(prefix)\n return prefixes.length - 1\n }\n\n const lineColor = useCallback(\n (index: number) => {\n const colorIndex = index % concurrentColors.length\n return concurrentColors[colorIndex]\n },\n [concurrentColors],\n )\n\n const writableStream = useCallback(\n (process: OutputProcess, prefixes: string[]) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const context = getConcurrentOutputContext()\n const prefix = context?.outputPrefix ?? process.prefix\n const shouldStripAnsi = context?.stripAnsi ?? true\n const log = chunk.toString('utf8').replace(/(\\n)$/, '')\n\n const index = addPrefix(prefix, prefixes)\n\n const lines = shouldStripAnsi ? stripAnsi(log).split(/\\n/) : log.split(/\\n/)\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix,\n lines,\n },\n ])\n next()\n },\n })\n },\n [lineColor],\n )\n\n const formatPrefix = (prefix: string) => {\n // Truncate prefix if needed\n if (prefix.length > calculatedPrefixColumnSize) {\n return prefix.substring(0, calculatedPrefixColumnSize)\n }\n\n return `${' '.repeat(calculatedPrefixColumnSize - prefix.length)}${prefix}`\n }\n\n useEffect(() => {\n const runProcesses = async () => {\n const prefixes: string[] = []\n\n try {\n await Promise.all(\n processes.map(async (process) => {\n const stdout = writableStream(process, prefixes)\n const stderr = writableStream(process, prefixes)\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({})\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error: unknown) {\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({error: error as Error})\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n runProcesses()\n }, [abortSignal, processes, writableStream, keepRunningAfterProcessesResolve])\n\n useEffect(() => {\n if (completionResult !== null) {\n complete(completionResult.error)\n }\n }, [completionResult, complete])\n\n const {lineVertical} = figures\n\n return (\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n <Text>\n {showTimestamps ? (\n <Text>\n {currentTime()} {lineVertical}{' '}\n </Text>\n ) : null}\n <Text color={chunk.color}>{formatPrefix(chunk.prefix)}</Text>\n <Text>\n {' '}\n {lineVertical} {line}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n )\n}\nexport {ConcurrentOutput, ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext}\n"]}
|
|
@@ -1,28 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import useLayout from '../hooks/use-layout.js';
|
|
1
|
+
import { LoadingIndicator } from './LoadingIndicator.js';
|
|
3
2
|
import { shouldDisplayColors } from '../../../../public/node/output.js';
|
|
4
3
|
import React from 'react';
|
|
5
|
-
import {
|
|
6
|
-
const loadingBarChar = '▀';
|
|
7
|
-
const hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁';
|
|
4
|
+
import { Text, useStdout } from 'ink';
|
|
8
5
|
const LoadingBar = ({ title, noColor, noProgressBar }) => {
|
|
9
|
-
const { twoThirds } = useLayout();
|
|
10
6
|
const { stdout } = useStdout();
|
|
11
7
|
// On real Node streams, isTTY is only present as an own property when the
|
|
12
8
|
// stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents
|
|
13
|
-
// capturing stderr via 2>&1), the animated
|
|
9
|
+
// capturing stderr via 2>&1), the animated loading indicator can't overwrite
|
|
14
10
|
// previous frames and would flood the output. Show only the static title
|
|
15
11
|
// in that case.
|
|
16
12
|
const isTTY = Boolean(stdout.isTTY);
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
return (React.createElement(Box, { flexDirection: "column" },
|
|
22
|
-
isTTY && !noProgressBar && React.createElement(TextAnimation, { text: loadingBar, maxWidth: twoThirds }),
|
|
23
|
-
React.createElement(Text, null,
|
|
13
|
+
const colorsDisabled = noColor ?? !shouldDisplayColors();
|
|
14
|
+
if (!isTTY || noProgressBar) {
|
|
15
|
+
return React.createElement(Text, null,
|
|
24
16
|
title,
|
|
25
|
-
" ...")
|
|
17
|
+
" ...");
|
|
18
|
+
}
|
|
19
|
+
return React.createElement(LoadingIndicator, { title: title, noColor: colorsDisabled });
|
|
26
20
|
};
|
|
27
21
|
export { LoadingBar };
|
|
28
22
|
//# sourceMappingURL=LoadingBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AAQnC,MAAM,UAAU,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAA2C,EAAE,EAAE;IAC/F,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAE5B,0EAA0E;IAC1E,0EAA0E;IAC1E,6EAA6E;IAC7E,0EAA0E;IAC1E,gBAAgB;IAChB,MAAM,KAAK,GAAG,OAAO,CAAE,MAA6C,CAAC,KAAK,CAAC,CAAA;IAC3E,MAAM,cAAc,GAAG,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAA;IAExD,IAAI,CAAC,KAAK,IAAI,aAAa,EAAE,CAAC;QAC5B,OAAO,oBAAC,IAAI;YAAE,KAAK;mBAAY,CAAA;IACjC,CAAC;IAED,OAAO,oBAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,GAAI,CAAA;AACpE,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingIndicator} from './LoadingIndicator.js'\nimport {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React from 'react'\n\nimport {Text, useStdout} from 'ink'\n\ninterface LoadingBarProps {\n title: string\n noColor?: boolean\n noProgressBar?: boolean\n}\n\nconst LoadingBar = ({title, noColor, noProgressBar}: React.PropsWithChildren<LoadingBarProps>) => {\n const {stdout} = useStdout()\n\n // On real Node streams, isTTY is only present as an own property when the\n // stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents\n // capturing stderr via 2>&1), the animated loading indicator can't overwrite\n // previous frames and would flood the output. Show only the static title\n // in that case.\n const isTTY = Boolean((stdout as unknown as Record<string, unknown>).isTTY)\n const colorsDisabled = noColor ?? !shouldDisplayColors()\n\n if (!isTTY || noProgressBar) {\n return <Text>{title} ...</Text>\n }\n\n return <LoadingIndicator title={title} noColor={colorsDisabled} />\n}\n\nexport {LoadingBar}\n"]}
|
|
@@ -2,10 +2,9 @@ import { LoadingBar } from './LoadingBar.js';
|
|
|
2
2
|
import { Stdout } from '../../ui.js';
|
|
3
3
|
import { render } from '../../testing/ui.js';
|
|
4
4
|
import { shouldDisplayColors, unstyled } from '../../../../public/node/output.js';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import React, { act } from 'react';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
7
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
8
|
-
vi.mock('../hooks/use-layout.js');
|
|
9
8
|
vi.mock('../../../../public/node/output.js', async () => {
|
|
10
9
|
const original = await vi.importActual('../../../../public/node/output.js');
|
|
11
10
|
return {
|
|
@@ -14,130 +13,69 @@ vi.mock('../../../../public/node/output.js', async () => {
|
|
|
14
13
|
};
|
|
15
14
|
});
|
|
16
15
|
beforeEach(() => {
|
|
17
|
-
vi.mocked(useLayout).mockReturnValue({
|
|
18
|
-
twoThirds: 53,
|
|
19
|
-
oneThird: 27,
|
|
20
|
-
fullWidth: 80,
|
|
21
|
-
});
|
|
22
16
|
vi.mocked(shouldDisplayColors).mockReturnValue(true);
|
|
23
17
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* On real Node streams, isTTY is only present as an own property when the
|
|
27
|
-
* stream IS a TTY.
|
|
28
|
-
*/
|
|
29
|
-
function createTTYStdout(columns = 100) {
|
|
30
|
-
const stdout = new Stdout({ columns });
|
|
18
|
+
function createTTYStdout() {
|
|
19
|
+
const stdout = new Stdout({ columns: 100 });
|
|
31
20
|
stdout.isTTY = true;
|
|
32
21
|
return stdout;
|
|
33
22
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Renders LoadingBar with a TTY stdout so the animated progress bar renders.
|
|
36
|
-
*/
|
|
37
23
|
function renderWithTTY(element) {
|
|
38
24
|
const stdout = createTTYStdout();
|
|
39
25
|
const instance = render(element, { stdout });
|
|
40
26
|
return { lastFrame: stdout.lastFrame, unmount: instance.unmount };
|
|
41
27
|
}
|
|
42
28
|
describe('LoadingBar', () => {
|
|
43
|
-
test('renders
|
|
44
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Loading content" }));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Processing files", noColor: true }));
|
|
52
|
-
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
53
|
-
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
|
|
54
|
-
Processing files ..."
|
|
55
|
-
`);
|
|
56
|
-
});
|
|
57
|
-
test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {
|
|
58
|
-
vi.mocked(shouldDisplayColors).mockReturnValue(false);
|
|
59
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Downloading packages" }));
|
|
60
|
-
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
61
|
-
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
|
|
62
|
-
Downloading packages ..."
|
|
63
|
-
`);
|
|
64
|
-
});
|
|
65
|
-
test('handles narrow terminal width correctly', async () => {
|
|
66
|
-
vi.mocked(useLayout).mockReturnValue({ twoThirds: 20, oneThird: 10, fullWidth: 30 });
|
|
67
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Building app" }));
|
|
68
|
-
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
69
|
-
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
70
|
-
Building app ..."
|
|
71
|
-
`);
|
|
29
|
+
test('renders the Shopify loading indicator', async () => {
|
|
30
|
+
const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Loading content" }));
|
|
31
|
+
const frame = lastFrame();
|
|
32
|
+
expect(unstyled(frame)).toBe('S> Loading content ...');
|
|
33
|
+
expect(frame).toContain('\u001B[1m');
|
|
34
|
+
expect(frame).toContain('\u001B[3m');
|
|
35
|
+
expect(frame).toContain(chalk.hex('#96BF48')('>'));
|
|
36
|
+
unmount();
|
|
72
37
|
});
|
|
73
|
-
test('
|
|
74
|
-
vi.
|
|
75
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
38
|
+
test('blinks the chevron without shifting the title', async () => {
|
|
39
|
+
vi.useFakeTimers();
|
|
40
|
+
const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Uploading theme" }));
|
|
41
|
+
try {
|
|
42
|
+
await act(async () => {
|
|
43
|
+
await vi.advanceTimersByTimeAsync(350);
|
|
44
|
+
});
|
|
45
|
+
expect(unstyled(lastFrame())).toBe('S Uploading theme ...');
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
unmount();
|
|
49
|
+
vi.useRealTimers();
|
|
50
|
+
}
|
|
80
51
|
});
|
|
81
|
-
test('
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
expect(unstyled(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`);
|
|
52
|
+
test('renders the chevron without color when noColor is true', async () => {
|
|
53
|
+
const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Processing files", noColor: true }));
|
|
54
|
+
const frame = lastFrame();
|
|
55
|
+
expect(unstyled(frame)).toBe('S> Processing files ...');
|
|
56
|
+
expect(frame).not.toContain(chalk.hex('#96BF48')('>'));
|
|
57
|
+
unmount();
|
|
88
58
|
});
|
|
89
|
-
test('
|
|
90
|
-
vi.mocked(
|
|
91
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
});
|
|
97
|
-
test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {
|
|
98
|
-
vi.mocked(useLayout).mockReturnValue({ twoThirds: 90, oneThird: 45, fullWidth: 135 });
|
|
99
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Analyzing dependencies", noColor: true }));
|
|
100
|
-
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
101
|
-
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁
|
|
102
|
-
Analyzing dependencies ..."
|
|
103
|
-
`);
|
|
104
|
-
});
|
|
105
|
-
test('renders correctly with empty title', async () => {
|
|
106
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "" }));
|
|
107
|
-
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
108
|
-
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
109
|
-
..."
|
|
110
|
-
`);
|
|
111
|
-
});
|
|
112
|
-
test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {
|
|
113
|
-
vi.mocked(shouldDisplayColors).mockReturnValue(true);
|
|
114
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Testing override", noColor: true }));
|
|
115
|
-
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
116
|
-
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
|
|
117
|
-
Testing override ..."
|
|
118
|
-
`);
|
|
59
|
+
test('renders the chevron without color when colors are disabled', async () => {
|
|
60
|
+
vi.mocked(shouldDisplayColors).mockReturnValue(false);
|
|
61
|
+
const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Downloading packages" }));
|
|
62
|
+
const frame = lastFrame();
|
|
63
|
+
expect(unstyled(frame)).toBe('S> Downloading packages ...');
|
|
64
|
+
expect(frame).not.toContain(chalk.hex('#96BF48')('>'));
|
|
65
|
+
unmount();
|
|
119
66
|
});
|
|
120
|
-
test('renders
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
expect(frame1()).toBe(frame2());
|
|
67
|
+
test('renders correctly with an empty title', async () => {
|
|
68
|
+
const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "" }));
|
|
69
|
+
expect(unstyled(lastFrame())).toBe('S> ...');
|
|
70
|
+
unmount();
|
|
125
71
|
});
|
|
126
|
-
test('hides
|
|
127
|
-
vi.mocked(shouldDisplayColors).mockReturnValue(true);
|
|
72
|
+
test('hides the loading indicator when noProgressBar is true', async () => {
|
|
128
73
|
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "task 1", noProgressBar: true }));
|
|
129
|
-
expect(unstyled(lastFrame())).
|
|
74
|
+
expect(unstyled(lastFrame())).toBe('task 1 ...');
|
|
130
75
|
});
|
|
131
76
|
test('shows only static title text when output stream is not a TTY', async () => {
|
|
132
|
-
// Default test Stdout has no isTTY property, simulating a non-TTY stream
|
|
133
77
|
const { lastFrame } = render(React.createElement(LoadingBar, { title: "Installing dependencies" }));
|
|
134
|
-
expect(unstyled(lastFrame())).
|
|
135
|
-
});
|
|
136
|
-
test('shows animated progress bar when output stream is a TTY', async () => {
|
|
137
|
-
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Uploading theme" }));
|
|
138
|
-
const frame = unstyled(lastFrame());
|
|
139
|
-
expect(frame).toContain('▀');
|
|
140
|
-
expect(frame).toContain('Uploading theme ...');
|
|
78
|
+
expect(unstyled(lastFrame())).toBe('Installing dependencies ...');
|
|
141
79
|
});
|
|
142
80
|
});
|
|
143
81
|
//# sourceMappingURL=LoadingBar.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingBar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {Stdout} from '../../ui.js'\nimport {render} from '../../testing/ui.js'\nimport {shouldDisplayColors, unstyled} from '../../../../public/node/output.js'\nimport useLayout from '../hooks/use-layout.js'\nimport React from 'react'\n\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\n\nvi.mock('../hooks/use-layout.js')\nvi.mock('../../../../public/node/output.js', async () => {\n const original: any = await vi.importActual('../../../../public/node/output.js')\n return {\n ...original,\n shouldDisplayColors: vi.fn(),\n }\n})\n\nbeforeEach(() => {\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 53,\n oneThird: 27,\n fullWidth: 80,\n })\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\n/**\n * Creates a Stdout test double simulating a TTY stream.\n * On real Node streams, isTTY is only present as an own property when the\n * stream IS a TTY.\n */\nfunction createTTYStdout(columns = 100) {\n const stdout = new Stdout({columns}) as Stdout & {isTTY: boolean}\n stdout.isTTY = true\n return stdout\n}\n\n/**\n * Renders LoadingBar with a TTY stdout so the animated progress bar renders.\n */\nfunction renderWithTTY(element: React.ReactElement) {\n const stdout = createTTYStdout()\n const instance = render(element, {stdout})\n return {lastFrame: stdout.lastFrame, unmount: instance.unmount}\n}\n\ndescribe('LoadingBar', () => {\n test('renders loading bar with default colored characters', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Loading content\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Loading content ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when noColor prop is true', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Processing files\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Processing files ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Downloading packages\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Downloading packages ...\"\n `)\n })\n\n test('handles narrow terminal width correctly', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 20, oneThird: 10, fullWidth: 30})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Building app\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Building app ...\"\n `)\n })\n\n test('handles narrow terminal width correctly in no-color mode', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 15, oneThird: 8, fullWidth: 23})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Installing\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇\n Installing ...\"\n `)\n })\n\n test('handles very narrow terminal width in no-color mode', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 5, oneThird: 3, fullWidth: 8})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Wait\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂\n Wait ...\"\n `)\n })\n\n test('handles wide terminal width correctly', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 100, oneThird: 50, fullWidth: 150})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Synchronizing data\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Synchronizing data ...\"\n `)\n })\n\n test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 90, oneThird: 45, fullWidth: 135})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Analyzing dependencies\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁\n Analyzing dependencies ...\"\n `)\n })\n\n test('renders correctly with empty title', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n ...\"\n `)\n })\n\n test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Testing override\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Testing override ...\"\n `)\n })\n\n test('renders consistently with same props', async () => {\n const props = {title: 'Consistent test', noColor: false}\n const {lastFrame: frame1} = renderWithTTY(<LoadingBar {...props} />)\n const {lastFrame: frame2} = renderWithTTY(<LoadingBar {...props} />)\n\n expect(frame1()).toBe(frame2())\n })\n\n test('hides progress bar when noProgressBar is true', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"task 1\" noProgressBar />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"task 1 ...\"`)\n })\n\n test('shows only static title text when output stream is not a TTY', async () => {\n // Default test Stdout has no isTTY property, simulating a non-TTY stream\n const {lastFrame} = render(<LoadingBar title=\"Installing dependencies\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"Installing dependencies ...\"`)\n })\n\n test('shows animated progress bar when output stream is a TTY', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Uploading theme\" />)\n\n const frame = unstyled(lastFrame()!)\n expect(frame).toContain('▀')\n expect(frame).toContain('Uploading theme ...')\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"LoadingBar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {Stdout} from '../../ui.js'\nimport {render} from '../../testing/ui.js'\nimport {shouldDisplayColors, unstyled} from '../../../../public/node/output.js'\nimport React, {act} from 'react'\nimport chalk from 'chalk'\n\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\n\nvi.mock('../../../../public/node/output.js', async () => {\n const original: any = await vi.importActual('../../../../public/node/output.js')\n return {\n ...original,\n shouldDisplayColors: vi.fn(),\n }\n})\n\nbeforeEach(() => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\nfunction createTTYStdout() {\n const stdout = new Stdout({columns: 100}) as Stdout & {isTTY: boolean}\n stdout.isTTY = true\n return stdout\n}\n\nfunction renderWithTTY(element: React.ReactElement) {\n const stdout = createTTYStdout()\n const instance = render(element, {stdout})\n return {lastFrame: stdout.lastFrame, unmount: instance.unmount}\n}\n\ndescribe('LoadingBar', () => {\n test('renders the Shopify loading indicator', async () => {\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Loading content\" />)\n const frame = lastFrame()!\n\n expect(unstyled(frame)).toBe('S> Loading content ...')\n expect(frame).toContain('\\u001B[1m')\n expect(frame).toContain('\\u001B[3m')\n expect(frame).toContain(chalk.hex('#96BF48')('>'))\n\n unmount()\n })\n\n test('blinks the chevron without shifting the title', async () => {\n vi.useFakeTimers()\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Uploading theme\" />)\n\n try {\n await act(async () => {\n await vi.advanceTimersByTimeAsync(350)\n })\n\n expect(unstyled(lastFrame()!)).toBe('S Uploading theme ...')\n } finally {\n unmount()\n vi.useRealTimers()\n }\n })\n\n test('renders the chevron without color when noColor is true', async () => {\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Processing files\" noColor />)\n const frame = lastFrame()!\n\n expect(unstyled(frame)).toBe('S> Processing files ...')\n expect(frame).not.toContain(chalk.hex('#96BF48')('>'))\n\n unmount()\n })\n\n test('renders the chevron without color when colors are disabled', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Downloading packages\" />)\n const frame = lastFrame()!\n\n expect(unstyled(frame)).toBe('S> Downloading packages ...')\n expect(frame).not.toContain(chalk.hex('#96BF48')('>'))\n\n unmount()\n })\n\n test('renders correctly with an empty title', async () => {\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"\" />)\n\n expect(unstyled(lastFrame()!)).toBe('S> ...')\n\n unmount()\n })\n\n test('hides the loading indicator when noProgressBar is true', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"task 1\" noProgressBar />)\n\n expect(unstyled(lastFrame()!)).toBe('task 1 ...')\n })\n\n test('shows only static title text when output stream is not a TTY', async () => {\n const {lastFrame} = render(<LoadingBar title=\"Installing dependencies\" />)\n\n expect(unstyled(lastFrame()!)).toBe('Installing dependencies ...')\n })\n})\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { shouldDisplayColors } from '../../../../public/node/output.js';
|
|
2
|
+
import React, { useLayoutEffect, useState } from 'react';
|
|
3
|
+
import { Text } from 'ink';
|
|
4
|
+
const SHOPIFY_GREEN = '#96BF48';
|
|
5
|
+
const CHEVRON_BLINK_INTERVAL_MS = 350;
|
|
6
|
+
const LoadingIndicator = ({ title, noColor = !shouldDisplayColors() }) => {
|
|
7
|
+
const [isChevronVisible, setIsChevronVisible] = useState(true);
|
|
8
|
+
useLayoutEffect(() => {
|
|
9
|
+
const interval = setInterval(() => {
|
|
10
|
+
setIsChevronVisible((isVisible) => !isVisible);
|
|
11
|
+
}, CHEVRON_BLINK_INTERVAL_MS);
|
|
12
|
+
return () => {
|
|
13
|
+
clearInterval(interval);
|
|
14
|
+
};
|
|
15
|
+
}, []);
|
|
16
|
+
return (React.createElement(Text, null,
|
|
17
|
+
React.createElement(Text, { bold: true, italic: true }, "S"),
|
|
18
|
+
React.createElement(Text, { bold: true, color: noColor ? undefined : SHOPIFY_GREEN }, isChevronVisible ? '>' : ' '),
|
|
19
|
+
` ${title} ...`));
|
|
20
|
+
};
|
|
21
|
+
export { LoadingIndicator };
|
|
22
|
+
//# sourceMappingURL=LoadingIndicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingIndicator.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingIndicator.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,EAAE,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACtD,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AAExB,MAAM,aAAa,GAAG,SAAS,CAAA;AAC/B,MAAM,yBAAyB,GAAG,GAAG,CAAA;AAOrC,MAAM,gBAAgB,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,GAAG,CAAC,mBAAmB,EAAE,EAAwB,EAAE,EAAE;IAC5F,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAE9D,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,mBAAmB,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAA;QAChD,CAAC,EAAE,yBAAyB,CAAC,CAAA;QAE7B,OAAO,GAAG,EAAE;YACV,aAAa,CAAC,QAAQ,CAAC,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,oBAAC,IAAI;QACH,oBAAC,IAAI,IAAC,IAAI,QAAC,MAAM,cAEV;QACP,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,IAClD,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CACxB;QACN,IAAI,KAAK,MAAM,CACX,CACR,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,gBAAgB,EAAC,CAAA","sourcesContent":["import {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React, {useLayoutEffect, useState} from 'react'\nimport {Text} from 'ink'\n\nconst SHOPIFY_GREEN = '#96BF48'\nconst CHEVRON_BLINK_INTERVAL_MS = 350\n\ninterface LoadingIndicatorProps {\n title: string\n noColor?: boolean\n}\n\nconst LoadingIndicator = ({title, noColor = !shouldDisplayColors()}: LoadingIndicatorProps) => {\n const [isChevronVisible, setIsChevronVisible] = useState(true)\n\n useLayoutEffect(() => {\n const interval = setInterval(() => {\n setIsChevronVisible((isVisible) => !isVisible)\n }, CHEVRON_BLINK_INTERVAL_MS)\n\n return () => {\n clearInterval(interval)\n }\n }, [])\n\n return (\n <Text>\n <Text bold italic>\n S\n </Text>\n <Text bold color={noColor ? undefined : SHOPIFY_GREEN}>\n {isChevronVisible ? '>' : ' '}\n </Text>\n {` ${title} ...`}\n </Text>\n )\n}\n\nexport {LoadingIndicator}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_KIT_VERSION = "
|
|
1
|
+
export declare const CLI_KIT_VERSION = "5.0.0";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const CLI_KIT_VERSION = '
|
|
1
|
+
export const CLI_KIT_VERSION = '5.0.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '5.0.0'\n"]}
|
|
@@ -123,6 +123,19 @@ export async function fetchApiVersions(session, preferredBehaviour) {
|
|
|
123
123
|
const storeName = session.storeFqdn.replace('.myshopify.com', '');
|
|
124
124
|
throw new AbortError(outputContent `Looks like you don't have access to this dev store: (${outputToken.link(storeName, `https://${session.storeFqdn}`)})`, outputContent `If you're not the owner, create a dev store staff account for yourself`);
|
|
125
125
|
}
|
|
126
|
+
if (error instanceof ClientError && error.response.status === 401 && isThemeAccessSession(session)) {
|
|
127
|
+
throw new AbortError(`The Theme Access password was rejected for the store ${session.storeFqdn}.`, 'Theme Access passwords only work on the store they were generated for, and only with its permanent .myshopify.com domain.', [
|
|
128
|
+
'Check that the password was created in the Theme Access app on this store and has not been deleted.',
|
|
129
|
+
[
|
|
130
|
+
'Pass the permanent domain to',
|
|
131
|
+
{ command: '--store' },
|
|
132
|
+
{ char: '.' },
|
|
133
|
+
'It is the .myshopify.com domain listed in the Shopify admin under',
|
|
134
|
+
{ subdued: 'Settings > Domains' },
|
|
135
|
+
{ char: '.' },
|
|
136
|
+
],
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
126
139
|
if (error instanceof ClientError && (error.response.status === 401 || error.response.status === 404)) {
|
|
127
140
|
throw new AbortError(`Error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`);
|
|
128
141
|
}
|