@shopify/cli-kit 3.93.2 → 3.94.1
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/private/node/analytics.d.ts +2 -0
- package/dist/private/node/analytics.js +10 -1
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/urls.js +19 -5
- package/dist/private/node/api/urls.js.map +1 -1
- package/dist/private/node/content-tokens.js +6 -2
- package/dist/private/node/content-tokens.js.map +1 -1
- package/dist/private/node/session/exchange.js +11 -3
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/session.d.ts +7 -7
- package/dist/private/node/session.js +11 -9
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/temp-dir.d.ts +1 -0
- package/dist/private/node/temp-dir.js +8 -0
- package/dist/private/node/temp-dir.js.map +1 -0
- package/dist/private/node/testing/ui.js +4 -3
- package/dist/private/node/testing/ui.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js +5 -4
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js +12 -10
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +27 -4
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +2 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js +12 -7
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.js +9 -2
- package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.test.js +49 -88
- package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.js +4 -4
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SingleTask.js +12 -6
- package/dist/private/node/ui/components/SingleTask.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.js +5 -5
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/hooks/use-abort-signal.js +10 -15
- package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
- package/dist/private/node/ui/hooks/use-async-and-unmount.js +11 -5
- package/dist/private/node/ui/hooks/use-async-and-unmount.js.map +1 -1
- package/dist/private/node/ui.d.ts +17 -1
- package/dist/private/node/ui.js +35 -4
- package/dist/private/node/ui.js.map +1 -1
- 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/context/local.js +1 -2
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/error-handler.js +4 -0
- package/dist/public/node/error-handler.js.map +1 -1
- package/dist/public/node/error.js +2 -0
- package/dist/public/node/error.js.map +1 -1
- package/dist/public/node/fs.js +10 -4
- package/dist/public/node/fs.js.map +1 -1
- package/dist/public/node/hooks/postrun.js +9 -10
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/metadata.d.ts +1 -1
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/monorail.d.ts +10 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +12 -0
- package/dist/public/node/node-package-manager.js +62 -30
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/path.d.ts +8 -0
- package/dist/public/node/path.js +17 -2
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/system.d.ts +6 -0
- package/dist/public/node/system.js +9 -0
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/tcp.js +32 -8
- package/dist/public/node/tcp.js.map +1 -1
- package/dist/public/node/ui.d.ts +1 -3
- package/dist/public/node/ui.js +16 -14
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/upgrade.d.ts +7 -2
- package/dist/public/node/upgrade.js +20 -7
- package/dist/public/node/upgrade.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2024.js +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultMeterProvider.js +1 -2
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultMeterProvider.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DangerousConfirmationPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/DangerousConfirmationPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAyB,aAAa,EAAC,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAC,SAAS,EAAiB,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,sBAAsB,EAAC,MAAM,iBAAiB,CAAA;AAEtD,OAAO,cAAc,MAAM,8BAA8B,CAAA;AACzD,OAAO,SAAS,EAAE,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAoB,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAChF,OAAO,EAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC/C,OAAO,OAAO,MAAM,SAAS,CAAA;AAU7B,MAAM,2BAA2B,GAAwD,CAAC,EACxF,OAAO,EACP,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,WAAW,GACZ,EAAE,EAAE;IACH,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,KAAa,EAAsC,EAAE;QACpD,OAAO,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,uBAAuB,EAAE,EAAC,SAAS,EAAE,YAAY,EAAC,CAAC,CAAA;IAClG,CAAC,EACD,CAAC,YAAY,CAAC,CACf,CAAA;IAED,MAAM,EAAC,QAAQ,EAAE,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IACzC,MAAM,EAAC,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAC,GAAG,SAAS,CAAS;QACzE,aAAa,EAAE,EAAE;KAClB,CAAC,CAAA;IACF,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqC,SAAS,CAAC,CAAA;IACjF,MAAM,KAAK,GAAG,WAAW,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAA;IAChE,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACnD,MAAM,EAAC,SAAS,EAAC,GAAG,cAAc,CAAC,WAAW,CAAC,CAAA;IAE/C,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAEvB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;YACrC,QAAQ,CAAC,SAAS,CAAC,CAAA;QACrB,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;YAEpC,IAAI,KAAK,EAAE,CAAC;gBACV,cAAc,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;gBACjC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,CAAA;YACd,UAAU,EAAE,CAAA;QACd,CAAC;aAAM,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;YACjD,QAAQ,CAAC,KAAK,CAAC,CAAA;YACf,UAAU,EAAE,CAAA;QACd,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;IAEvC,MAAM,SAAS,GAAG,WAAW,KAAK,WAAW,CAAC,SAAS,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,CAAA;IAEhG,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS;QAC3D,oBAAC,GAAG;YACF,oBAAC,GAAG,IAAC,WAAW,EAAE,CAAC;gBACjB,oBAAC,IAAI,YAAS,CACV;YACN,oBAAC,aAAa,IAAC,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,GAAI,CACpD;QACL,SAAS,CAAC,CAAC,CAAC,CACX,oBAAC,eAAe,IAAM,SAAS,EAAE,WAAW,KAAK,WAAW,CAAC,SAAS,GAAK,CAC5E,CAAC,CAAC,CAAC,CACF;YACE,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBAC5D,SAAS,CAAC,CAAC,CAAC,CACX,oBAAC,GAAG,IACF,WAAW,EAAE,CAAC,EACd,WAAW,EAAC,MAAM,EAClB,UAAU,QACV,WAAW,EAAE,KAAK,EAClB,SAAS,EAAE,KAAK,EAChB,YAAY,EAAE,KAAK,EACnB,aAAa,EAAC,QAAQ,EACtB,GAAG,EAAE,CAAC;oBAEN,oBAAC,SAAS,IAAC,KAAK,EAAE,SAAS,GAAI,CAC3B,CACP,CAAC,CAAC,CAAC,IAAI;gBACR,oBAAC,GAAG;oBACF,oBAAC,aAAa,IAAC,IAAI,EAAE,CAAC,MAAM,EAAE,EAAC,SAAS,EAAE,YAAY,EAAC,EAAE,wCAAwC,CAAC,GAAI,CAClG,CACF;YACN,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,QAAQ;gBACzC,oBAAC,GAAG;oBACF,oBAAC,GAAG,IAAC,WAAW,EAAE,CAAC;wBACjB,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,GAAG,CAAQ,CAC5B;oBACN,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC;wBACd,oBAAC,SAAS,IACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gCACnB,SAAS,CAAC,MAAM,CAAC,CAAA;gCACjB,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;4BAClC,CAAC,EACD,YAAY,EAAC,EAAE,EACf,KAAK,EAAE,KAAK,GACZ,CACE,CACF;gBACN,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;oBAChB,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,SAAS,CAAQ,CAClC;gBACL,WAAW,KAAK,WAAW,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAC5C,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;oBAChB,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK;wBAChB,oBAAC,aAAa,IAAC,IAAI,EAAE,KAAK,GAAI,CACzB,CACH,CACP,CAAC,CAAC,CAAC,IAAI,CACJ,CACL,CACJ,CACG,CACP,CAAA;AACH,CAAC,CAAA;AAMD,MAAM,eAAe,GAA4C,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE,CAAC,CAChF,oBAAC,GAAG;IACF,oBAAC,GAAG,IAAC,KAAK,EAAE,CAAC,IACV,SAAS,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK,IAAE,OAAO,CAAC,KAAK,CAAQ,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,OAAO,CAAC,IAAI,CAAQ,CAC5F;IAEN,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,IAAG,SAAS,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK,gBAAiB,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,gBAAiB,CAAO,CAC1G,CACP,CAAA;AAED,OAAO,EAAC,2BAA2B,EAAC,CAAA","sourcesContent":["import {TextInput} from './TextInput.js'\nimport {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {handleCtrlC} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\nimport {Box, useApp, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface DangerousConfirmationPromptProps {\n message: string\n confirmation: string\n infoTable?: InfoTableProps['table']\n onSubmit: (value: boolean) => void\n abortSignal?: AbortSignal\n}\n\nconst DangerousConfirmationPrompt: FunctionComponent<DangerousConfirmationPromptProps> = ({\n message,\n confirmation,\n infoTable,\n onSubmit,\n abortSignal,\n}) => {\n const validateAnswer = useCallback(\n (value: string): TokenItem<InlineToken> | undefined => {\n return value === confirmation ? undefined : ['Value must be exactly', {userInput: confirmation}]\n },\n [confirmation],\n )\n\n const {oneThird, twoThirds} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer: '',\n })\n const {exit: unmountInk} = useApp()\n const [error, setError] = useState<TokenItem<InlineToken> | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.escape) {\n setPromptState(PromptState.Cancelled)\n setError(undefined)\n }\n\n if (key.return) {\n const error = validateAnswer(answer)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(true)\n unmountInk()\n } else if (promptState === PromptState.Cancelled) {\n onSubmit(false)\n unmountInk()\n }\n }, [onSubmit, promptState, unmountInk])\n\n const completed = promptState === PromptState.Submitted || promptState === PromptState.Cancelled\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={twoThirds}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {completed ? (\n <CompletedPrompt {...{cancelled: promptState === PromptState.Cancelled}} />\n ) : (\n <>\n <Box flexDirection=\"column\" gap={1} marginTop={1} marginLeft={3}>\n {infoTable ? (\n <Box\n paddingLeft={2}\n borderStyle=\"bold\"\n borderLeft\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n flexDirection=\"column\"\n gap={1}\n >\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n <Box>\n <TokenizedText item={['Type', {userInput: confirmation}, 'to confirm, or press Escape to cancel.']} />\n </Box>\n </Box>\n <Box flexDirection=\"column\" width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue=\"\"\n color={color}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error && error ? (\n <Box marginLeft={3}>\n <Text color={color}>\n <TokenizedText item={error} />\n </Text>\n </Box>\n ) : null}\n </Box>\n </>\n )}\n </Box>\n )\n}\n\ninterface CompletedPromptProps {\n cancelled: boolean\n}\n\nconst CompletedPrompt: FunctionComponent<CompletedPromptProps> = ({cancelled}) => (\n <Box>\n <Box width={3}>\n {cancelled ? <Text color=\"red\">{figures.cross}</Text> : <Text color=\"cyan\">{figures.tick}</Text>}\n </Box>\n\n <Box flexGrow={1}>{cancelled ? <Text color=\"red\">Cancelled</Text> : <Text color=\"cyan\">Confirmed</Text>}</Box>\n </Box>\n)\n\nexport {DangerousConfirmationPrompt}\n"]}
|
|
1
|
+
{"version":3,"file":"DangerousConfirmationPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/DangerousConfirmationPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {TextInput} from './TextInput.js'\nimport {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {handleCtrlC, useComplete} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\nimport {Box, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface DangerousConfirmationPromptProps {\n message: string\n confirmation: string\n infoTable?: InfoTableProps['table']\n warningItem?: TokenItem<InlineToken>\n onSubmit: (value: boolean) => void\n abortSignal?: AbortSignal\n}\n\nconst DangerousConfirmationPrompt: FunctionComponent<DangerousConfirmationPromptProps> = ({\n message,\n confirmation,\n infoTable,\n warningItem,\n onSubmit,\n abortSignal,\n}) => {\n const validateAnswer = useCallback(\n (value: string): TokenItem<InlineToken> | undefined => {\n return value === confirmation ? undefined : ['Value must be exactly', {userInput: confirmation}]\n },\n [confirmation],\n )\n\n const {oneThird, twoThirds} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer: '',\n })\n const complete = useComplete()\n const [error, setError] = useState<TokenItem<InlineToken> | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.escape) {\n setPromptState(PromptState.Cancelled)\n setError(undefined)\n }\n\n if (key.return) {\n const error = validateAnswer(answer)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(true)\n complete()\n } else if (promptState === PromptState.Cancelled) {\n onSubmit(false)\n complete()\n }\n }, [onSubmit, promptState, complete])\n\n const completed = promptState === PromptState.Submitted || promptState === PromptState.Cancelled\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={twoThirds}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {completed ? (\n <CompletedPrompt {...{cancelled: promptState === PromptState.Cancelled}} />\n ) : (\n <>\n <Box flexDirection=\"column\" gap={1} marginTop={1} marginLeft={3}>\n {infoTable ? (\n <Box\n paddingLeft={2}\n borderStyle=\"bold\"\n borderLeft\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n flexDirection=\"column\"\n gap={1}\n >\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n {warningItem ? (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{figures.warning} WARNING</Text>\n <TokenizedText item={warningItem} />\n </Box>\n ) : null}\n <Box>\n <TokenizedText item={['Type', {userInput: confirmation}, 'to confirm, or press Escape to cancel.']} />\n </Box>\n </Box>\n <Box flexDirection=\"column\" width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue=\"\"\n color={color}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error && error ? (\n <Box marginLeft={3}>\n <Text color={color}>\n <TokenizedText item={error} />\n </Text>\n </Box>\n ) : null}\n </Box>\n </>\n )}\n </Box>\n )\n}\n\ninterface CompletedPromptProps {\n cancelled: boolean\n}\n\nconst CompletedPrompt: FunctionComponent<CompletedPromptProps> = ({cancelled}) => (\n <Box>\n <Box width={3}>\n {cancelled ? <Text color=\"red\">{figures.cross}</Text> : <Text color=\"cyan\">{figures.tick}</Text>}\n </Box>\n\n <Box flexGrow={1}>{cancelled ? <Text color=\"red\">Cancelled</Text> : <Text color=\"cyan\">Confirmed</Text>}</Box>\n </Box>\n)\n\nexport {DangerousConfirmationPrompt}\n"]}
|
|
@@ -2,17 +2,24 @@ import { TextAnimation } from './TextAnimation.js';
|
|
|
2
2
|
import useLayout from '../hooks/use-layout.js';
|
|
3
3
|
import { shouldDisplayColors } from '../../../../public/node/output.js';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
import { Box, Text } from 'ink';
|
|
5
|
+
import { Box, Text, useStdout } from 'ink';
|
|
6
6
|
const loadingBarChar = '▀';
|
|
7
7
|
const hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁';
|
|
8
8
|
const LoadingBar = ({ title, noColor, noProgressBar }) => {
|
|
9
9
|
const { twoThirds } = useLayout();
|
|
10
|
+
const { stdout } = useStdout();
|
|
11
|
+
// On real Node streams, isTTY is only present as an own property when the
|
|
12
|
+
// 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 progress bar can't overwrite
|
|
14
|
+
// previous frames and would flood the output. Show only the static title
|
|
15
|
+
// in that case.
|
|
16
|
+
const isTTY = Boolean(stdout.isTTY);
|
|
10
17
|
let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('');
|
|
11
18
|
if (noColor ?? !shouldDisplayColors()) {
|
|
12
19
|
loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length));
|
|
13
20
|
}
|
|
14
21
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
15
|
-
!noProgressBar && React.createElement(TextAnimation, { text: loadingBar, maxWidth: twoThirds }),
|
|
22
|
+
isTTY && !noProgressBar && React.createElement(TextAnimation, { text: loadingBar, maxWidth: twoThirds }),
|
|
16
23
|
React.createElement(Text, null,
|
|
17
24
|
title,
|
|
18
25
|
" ...")));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AAExC,MAAM,cAAc,GAAG,GAAG,CAAA;AAC1B,MAAM,UAAU,GAAG,gCAAgC,CAAA;AAQnD,MAAM,UAAU,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAA2C,EAAE,EAAE;IAC/F,MAAM,EAAC,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IAC/B,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAE5B,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,0EAA0E;IAC1E,gBAAgB;IAChB,MAAM,KAAK,GAAG,OAAO,CAAE,MAA6C,CAAC,KAAK,CAAC,CAAA;IAE3E,IAAI,UAAU,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnE,IAAI,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QACtC,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,KAAK,IAAI,CAAC,aAAa,IAAI,oBAAC,aAAa,IAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,GAAI;QACpF,oBAAC,IAAI;YAAE,KAAK;mBAAY,CACpB,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {TextAnimation} from './TextAnimation.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React from 'react'\n\nimport {Box, Text, useStdout} from 'ink'\n\nconst loadingBarChar = '▀'\nconst hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁'\n\ninterface LoadingBarProps {\n title: string\n noColor?: boolean\n noProgressBar?: boolean\n}\n\nconst LoadingBar = ({title, noColor, noProgressBar}: React.PropsWithChildren<LoadingBarProps>) => {\n const {twoThirds} = useLayout()\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 progress bar 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\n let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('')\n if (noColor ?? !shouldDisplayColors()) {\n loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length))\n }\n\n return (\n <Box flexDirection=\"column\">\n {isTTY && !noProgressBar && <TextAnimation text={loadingBar} maxWidth={twoThirds} />}\n <Text>{title} ...</Text>\n </Box>\n )\n}\n\nexport {LoadingBar}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LoadingBar } from './LoadingBar.js';
|
|
2
|
+
import { Stdout } from '../../ui.js';
|
|
2
3
|
import { render } from '../../testing/ui.js';
|
|
3
4
|
import { shouldDisplayColors, unstyled } from '../../../../public/node/output.js';
|
|
4
5
|
import useLayout from '../hooks/use-layout.js';
|
|
@@ -13,7 +14,6 @@ vi.mock('../../../../public/node/output.js', async () => {
|
|
|
13
14
|
};
|
|
14
15
|
});
|
|
15
16
|
beforeEach(() => {
|
|
16
|
-
// Default terminal width
|
|
17
17
|
vi.mocked(useLayout).mockReturnValue({
|
|
18
18
|
twoThirds: 53,
|
|
19
19
|
oneThird: 27,
|
|
@@ -21,162 +21,123 @@ beforeEach(() => {
|
|
|
21
21
|
});
|
|
22
22
|
vi.mocked(shouldDisplayColors).mockReturnValue(true);
|
|
23
23
|
});
|
|
24
|
+
/**
|
|
25
|
+
* Creates a Stdout test double simulating a TTY stream.
|
|
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 });
|
|
31
|
+
stdout.isTTY = true;
|
|
32
|
+
return stdout;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Renders LoadingBar with a TTY stdout so the animated progress bar renders.
|
|
36
|
+
*/
|
|
37
|
+
function renderWithTTY(element) {
|
|
38
|
+
const stdout = createTTYStdout();
|
|
39
|
+
const instance = render(element, { stdout });
|
|
40
|
+
return { lastFrame: stdout.lastFrame, unmount: instance.unmount };
|
|
41
|
+
}
|
|
24
42
|
describe('LoadingBar', () => {
|
|
25
43
|
test('renders loading bar with default colored characters', async () => {
|
|
26
|
-
|
|
27
|
-
const title = 'Loading content';
|
|
28
|
-
// When
|
|
29
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
|
|
30
|
-
// Then
|
|
44
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Loading content" }));
|
|
31
45
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
32
46
|
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
33
47
|
Loading content ..."
|
|
34
48
|
`);
|
|
35
49
|
});
|
|
36
50
|
test('renders loading bar with hill pattern when noColor prop is true', async () => {
|
|
37
|
-
|
|
38
|
-
const title = 'Processing files';
|
|
39
|
-
// When
|
|
40
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
|
|
41
|
-
// Then
|
|
51
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Processing files", noColor: true }));
|
|
42
52
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
43
53
|
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
|
|
44
54
|
Processing files ..."
|
|
45
55
|
`);
|
|
46
56
|
});
|
|
47
57
|
test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {
|
|
48
|
-
// Given
|
|
49
58
|
vi.mocked(shouldDisplayColors).mockReturnValue(false);
|
|
50
|
-
const
|
|
51
|
-
// When
|
|
52
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
|
|
53
|
-
// Then
|
|
59
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Downloading packages" }));
|
|
54
60
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
55
61
|
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
|
|
56
62
|
Downloading packages ..."
|
|
57
63
|
`);
|
|
58
64
|
});
|
|
59
65
|
test('handles narrow terminal width correctly', async () => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
twoThirds: 20,
|
|
63
|
-
oneThird: 10,
|
|
64
|
-
fullWidth: 30,
|
|
65
|
-
});
|
|
66
|
-
const title = 'Building app';
|
|
67
|
-
// When
|
|
68
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
|
|
69
|
-
// Then
|
|
66
|
+
vi.mocked(useLayout).mockReturnValue({ twoThirds: 20, oneThird: 10, fullWidth: 30 });
|
|
67
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Building app" }));
|
|
70
68
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
71
69
|
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
72
70
|
Building app ..."
|
|
73
71
|
`);
|
|
74
72
|
});
|
|
75
73
|
test('handles narrow terminal width correctly in no-color mode', async () => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
twoThirds: 15,
|
|
79
|
-
oneThird: 8,
|
|
80
|
-
fullWidth: 23,
|
|
81
|
-
});
|
|
82
|
-
const title = 'Installing';
|
|
83
|
-
// When
|
|
84
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
|
|
85
|
-
// Then
|
|
74
|
+
vi.mocked(useLayout).mockReturnValue({ twoThirds: 15, oneThird: 8, fullWidth: 23 });
|
|
75
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Installing", noColor: true }));
|
|
86
76
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
87
77
|
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇
|
|
88
78
|
Installing ..."
|
|
89
79
|
`);
|
|
90
80
|
});
|
|
91
81
|
test('handles very narrow terminal width in no-color mode', async () => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
twoThirds: 5,
|
|
95
|
-
oneThird: 3,
|
|
96
|
-
fullWidth: 8,
|
|
97
|
-
});
|
|
98
|
-
const title = 'Wait';
|
|
99
|
-
// When
|
|
100
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
|
|
101
|
-
// Then
|
|
82
|
+
vi.mocked(useLayout).mockReturnValue({ twoThirds: 5, oneThird: 3, fullWidth: 8 });
|
|
83
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Wait", noColor: true }));
|
|
102
84
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
103
85
|
"▁▁▁▂▂
|
|
104
86
|
Wait ..."
|
|
105
87
|
`);
|
|
106
88
|
});
|
|
107
89
|
test('handles wide terminal width correctly', async () => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
twoThirds: 100,
|
|
111
|
-
oneThird: 50,
|
|
112
|
-
fullWidth: 150,
|
|
113
|
-
});
|
|
114
|
-
const title = 'Synchronizing data';
|
|
115
|
-
// When
|
|
116
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
|
|
117
|
-
// Then
|
|
90
|
+
vi.mocked(useLayout).mockReturnValue({ twoThirds: 100, oneThird: 50, fullWidth: 150 });
|
|
91
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Synchronizing data" }));
|
|
118
92
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
119
93
|
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
120
94
|
Synchronizing data ..."
|
|
121
95
|
`);
|
|
122
96
|
});
|
|
123
97
|
test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
twoThirds: 90,
|
|
127
|
-
oneThird: 45,
|
|
128
|
-
fullWidth: 135,
|
|
129
|
-
});
|
|
130
|
-
const title = 'Analyzing dependencies';
|
|
131
|
-
// When
|
|
132
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
|
|
133
|
-
// Then
|
|
98
|
+
vi.mocked(useLayout).mockReturnValue({ twoThirds: 90, oneThird: 45, fullWidth: 135 });
|
|
99
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Analyzing dependencies", noColor: true }));
|
|
134
100
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
135
101
|
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁
|
|
136
102
|
Analyzing dependencies ..."
|
|
137
103
|
`);
|
|
138
104
|
});
|
|
139
105
|
test('renders correctly with empty title', async () => {
|
|
140
|
-
|
|
141
|
-
const title = '';
|
|
142
|
-
// When
|
|
143
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title }));
|
|
144
|
-
// Then
|
|
106
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "" }));
|
|
145
107
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
146
108
|
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
147
109
|
..."
|
|
148
110
|
`);
|
|
149
111
|
});
|
|
150
112
|
test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {
|
|
151
|
-
// Given
|
|
152
113
|
vi.mocked(shouldDisplayColors).mockReturnValue(true);
|
|
153
|
-
const
|
|
154
|
-
// When
|
|
155
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noColor: true }));
|
|
156
|
-
// Then
|
|
114
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Testing override", noColor: true }));
|
|
157
115
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
158
116
|
"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
|
|
159
117
|
Testing override ..."
|
|
160
118
|
`);
|
|
161
119
|
});
|
|
162
120
|
test('renders consistently with same props', async () => {
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
// When
|
|
167
|
-
const { lastFrame: frame1 } = render(React.createElement(LoadingBar, { ...props }));
|
|
168
|
-
const { lastFrame: frame2 } = render(React.createElement(LoadingBar, { ...props }));
|
|
169
|
-
// Then
|
|
121
|
+
const props = { title: 'Consistent test', noColor: false };
|
|
122
|
+
const { lastFrame: frame1 } = renderWithTTY(React.createElement(LoadingBar, { ...props }));
|
|
123
|
+
const { lastFrame: frame2 } = renderWithTTY(React.createElement(LoadingBar, { ...props }));
|
|
170
124
|
expect(frame1()).toBe(frame2());
|
|
171
125
|
});
|
|
172
126
|
test('hides progress bar when noProgressBar is true', async () => {
|
|
173
|
-
// Given
|
|
174
127
|
vi.mocked(shouldDisplayColors).mockReturnValue(true);
|
|
175
|
-
const
|
|
176
|
-
// When
|
|
177
|
-
const { lastFrame } = render(React.createElement(LoadingBar, { title: title, noProgressBar: true }));
|
|
178
|
-
// Then
|
|
128
|
+
const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "task 1", noProgressBar: true }));
|
|
179
129
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`"task 1 ..."`);
|
|
180
130
|
});
|
|
131
|
+
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
|
+
const { lastFrame } = render(React.createElement(LoadingBar, { title: "Installing dependencies" }));
|
|
134
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`"Installing dependencies ..."`);
|
|
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 ...');
|
|
141
|
+
});
|
|
181
142
|
});
|
|
182
143
|
//# 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 {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 // Default terminal width\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 53,\n oneThird: 27,\n fullWidth: 80,\n })\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\ndescribe('LoadingBar', () => {\n test('renders loading bar with default colored characters', async () => {\n // Given\n const title = 'Loading content'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\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 // Given\n const title = 'Processing files'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\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 // Given\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const title = 'Downloading packages'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Downloading packages ...\"\n `)\n })\n\n test('handles narrow terminal width correctly', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 20,\n oneThird: 10,\n fullWidth: 30,\n })\n const title = 'Building app'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\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 // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 15,\n oneThird: 8,\n fullWidth: 23,\n })\n const title = 'Installing'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇\n Installing ...\"\n `)\n })\n\n test('handles very narrow terminal width in no-color mode', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 5,\n oneThird: 3,\n fullWidth: 8,\n })\n const title = 'Wait'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂\n Wait ...\"\n `)\n })\n\n test('handles wide terminal width correctly', async () => {\n // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 100,\n oneThird: 50,\n fullWidth: 150,\n })\n const title = 'Synchronizing data'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\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 // Given\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 90,\n oneThird: 45,\n fullWidth: 135,\n })\n const title = 'Analyzing dependencies'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁\n Analyzing dependencies ...\"\n `)\n })\n\n test('renders correctly with empty title', async () => {\n // Given\n const title = ''\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n ...\"\n `)\n })\n\n test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {\n // Given\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const title = 'Testing override'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noColor />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Testing override ...\"\n `)\n })\n\n test('renders consistently with same props', async () => {\n // Given\n const title = 'Consistent test'\n const props = {title, noColor: false}\n\n // When\n const {lastFrame: frame1} = render(<LoadingBar {...props} />)\n const {lastFrame: frame2} = render(<LoadingBar {...props} />)\n\n // Then\n expect(frame1()).toBe(frame2())\n })\n\n test('hides progress bar when noProgressBar is true', async () => {\n // Given\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const title = 'task 1'\n\n // When\n const {lastFrame} = render(<LoadingBar title={title} noProgressBar />)\n\n // Then\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"task 1 ...\"`)\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 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,13 +1,13 @@
|
|
|
1
1
|
import { SelectInput } from './SelectInput.js';
|
|
2
2
|
import { PromptLayout } from './Prompts/PromptLayout.js';
|
|
3
|
+
import { useComplete } from '../../ui.js';
|
|
3
4
|
import usePrompt, { PromptState } from '../hooks/use-prompt.js';
|
|
4
5
|
import React, { useCallback, useEffect } from 'react';
|
|
5
|
-
import { useApp } from 'ink';
|
|
6
6
|
function SelectPrompt({ message, choices, infoTable, infoMessage, onSubmit, defaultValue, abortSignal, groupOrder, }) {
|
|
7
7
|
if (choices.length === 0) {
|
|
8
8
|
throw new Error('SelectPrompt requires at least one choice');
|
|
9
9
|
}
|
|
10
|
-
const
|
|
10
|
+
const complete = useComplete();
|
|
11
11
|
const { promptState, setPromptState, answer, setAnswer } = usePrompt({
|
|
12
12
|
initialAnswer: undefined,
|
|
13
13
|
});
|
|
@@ -17,10 +17,10 @@ function SelectPrompt({ message, choices, infoTable, infoMessage, onSubmit, defa
|
|
|
17
17
|
}, [setAnswer, setPromptState]);
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
if (promptState === PromptState.Submitted && answer) {
|
|
20
|
-
unmountInk();
|
|
21
20
|
onSubmit(answer.value);
|
|
21
|
+
complete();
|
|
22
22
|
}
|
|
23
|
-
}, [answer, onSubmit, promptState,
|
|
23
|
+
}, [answer, onSubmit, promptState, complete]);
|
|
24
24
|
return (React.createElement(PromptLayout, { message: message, state: promptState, submittedAnswerLabel: answer?.label, infoTable: infoTable, infoMessage: infoMessage, abortSignal: abortSignal, input: React.createElement(SelectInput, { defaultValue: defaultValue, items: choices, onSubmit: submitAnswer, groupOrder: groupOrder }) }));
|
|
25
25
|
}
|
|
26
26
|
export { SelectPrompt };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAuC,MAAM,kBAAkB,CAAA;AAGlF,OAAO,EAAU,YAAY,EAAC,MAAM,2BAA2B,CAAA;AAE/D,OAAO,SAAS,EAAE,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAe,WAAW,EAAE,SAAS,EAAC,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAuC,MAAM,kBAAkB,CAAA;AAGlF,OAAO,EAAU,YAAY,EAAC,MAAM,2BAA2B,CAAA;AAE/D,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,SAAS,EAAE,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAe,WAAW,EAAE,SAAS,EAAC,MAAM,OAAO,CAAA;AAajE,SAAS,YAAY,CAAI,EACvB,OAAO,EACP,OAAO,EACP,SAAS,EACT,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,UAAU,GACoC;IAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,EAAC,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAC,GAAG,SAAS,CAA4B;QAC5F,aAAa,EAAE,SAAS;KACzB,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAAqB,EAAE,EAAE;QACxB,SAAS,CAAC,MAAM,CAAC,CAAA;QACjB,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC,EACD,CAAC,SAAS,EAAE,cAAc,CAAC,CAC5B,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,KAAK,WAAW,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;YACpD,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACtB,QAAQ,EAAE,CAAA;QACZ,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE7C,OAAO,CACL,oBAAC,YAAY,IACX,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,WAAW,EAClB,oBAAoB,EAAE,MAAM,EAAE,KAAK,EACnC,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,KAAK,EACH,oBAAC,WAAW,IAAC,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAI,GAE7G,CACH,CAAA;AACH,CAAC;AAED,OAAO,EAAC,YAAY,EAAC,CAAA","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTableProps} from './Prompts/InfoTable.js'\nimport {InfoMessageProps} from './Prompts/InfoMessage.js'\nimport {Message, PromptLayout} from './Prompts/PromptLayout.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\n\nimport React, {ReactElement, useCallback, useEffect} from 'react'\n\nexport interface SelectPromptProps<T> {\n message: Message\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n defaultValue?: T\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n groupOrder?: string[]\n}\n\nfunction SelectPrompt<T>({\n message,\n choices,\n infoTable,\n infoMessage,\n onSubmit,\n defaultValue,\n abortSignal,\n groupOrder,\n}: React.PropsWithChildren<SelectPromptProps<T>>): ReactElement | null {\n if (choices.length === 0) {\n throw new Error('SelectPrompt requires at least one choice')\n }\n const complete = useComplete()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<SelectItem<T> | undefined>({\n initialAnswer: undefined,\n })\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n },\n [setAnswer, setPromptState],\n )\n\n useEffect(() => {\n if (promptState === PromptState.Submitted && answer) {\n onSubmit(answer.value)\n complete()\n }\n }, [answer, onSubmit, promptState, complete])\n\n return (\n <PromptLayout\n message={message}\n state={promptState}\n submittedAnswerLabel={answer?.label}\n infoTable={infoTable}\n infoMessage={infoMessage}\n abortSignal={abortSignal}\n input={\n <SelectInput defaultValue={defaultValue} items={choices} onSubmit={submitAnswer} groupOrder={groupOrder} />\n }\n />\n )\n}\n\nexport {SelectPrompt}\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { LoadingBar } from './LoadingBar.js';
|
|
2
|
-
import { handleCtrlC } from '../../ui.js';
|
|
2
|
+
import { handleCtrlC, useComplete } from '../../ui.js';
|
|
3
3
|
import React, { useEffect, useState } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { useInput, useStdin } from 'ink';
|
|
5
5
|
const SingleTask = ({ task, title, onComplete, onAbort, noColor }) => {
|
|
6
6
|
const [status, setStatus] = useState(title);
|
|
7
7
|
const [isDone, setIsDone] = useState(false);
|
|
8
|
-
const
|
|
8
|
+
const [taskResult, setTaskResult] = useState(null);
|
|
9
|
+
const complete = useComplete();
|
|
9
10
|
const { isRawModeSupported } = useStdin();
|
|
10
11
|
useInput((input, key) => {
|
|
11
12
|
if (onAbort) {
|
|
@@ -20,13 +21,18 @@ const SingleTask = ({ task, title, onComplete, onAbort, noColor }) => {
|
|
|
20
21
|
.then((result) => {
|
|
21
22
|
setIsDone(true);
|
|
22
23
|
onComplete?.(result);
|
|
23
|
-
|
|
24
|
+
setTaskResult({});
|
|
24
25
|
})
|
|
25
26
|
.catch((error) => {
|
|
26
27
|
setIsDone(true);
|
|
27
|
-
|
|
28
|
+
setTaskResult({ error });
|
|
28
29
|
});
|
|
29
|
-
}, [task,
|
|
30
|
+
}, [task, onComplete]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (taskResult !== null) {
|
|
33
|
+
complete(taskResult.error);
|
|
34
|
+
}
|
|
35
|
+
}, [taskResult, complete]);
|
|
30
36
|
if (isDone) {
|
|
31
37
|
// clear things once done
|
|
32
38
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SingleTask.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"SingleTask.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,WAAW,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAEpD,OAAO,KAAK,EAAE,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAC,QAAQ,EAAE,QAAQ,EAAC,MAAM,KAAK,CAAA;AAUtC,MAAM,UAAU,GAAG,CAAK,EAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAqB,EAAE,EAAE;IACzF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAA;IAC1E,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,EAAC,kBAAkB,EAAC,GAAG,QAAQ,EAAE,CAAA;IAEvC,QAAQ,CACN,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACb,IAAI,OAAO,EAAE,CAAC;YACZ,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;QAClC,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACzB,CAAC;IACH,CAAC,EACD,EAAC,QAAQ,EAAE,OAAO,CAAC,kBAAkB,CAAC,EAAC,CACxC,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,CAAC;aACZ,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,EAAE,CAAC,MAAM,CAAC,CAAA;YACpB,aAAa,CAAC,EAAE,CAAC,CAAA;QACnB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,aAAa,CAAC,EAAC,KAAK,EAAC,CAAC,CAAA;QACxB,CAAC,CAAC,CAAA;IACN,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAA;IAEtB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE1B,IAAI,MAAM,EAAE,CAAC;QACX,yBAAyB;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CAAA;AAC9D,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {handleCtrlC, useComplete} from '../../ui.js'\nimport {TokenizedString} from '../../../../public/node/output.js'\nimport React, {useEffect, useState} from 'react'\n\nimport {useInput, useStdin} from 'ink'\n\ninterface SingleTaskProps<T> {\n title: TokenizedString\n task: (updateStatus: (status: TokenizedString) => void) => Promise<T>\n onComplete?: (result: T) => void\n onAbort?: () => void\n noColor?: boolean\n}\n\nconst SingleTask = <T,>({task, title, onComplete, onAbort, noColor}: SingleTaskProps<T>) => {\n const [status, setStatus] = useState(title)\n const [isDone, setIsDone] = useState(false)\n const [taskResult, setTaskResult] = useState<{error?: Error} | null>(null)\n const complete = useComplete()\n const {isRawModeSupported} = useStdin()\n\n useInput(\n (input, key) => {\n if (onAbort) {\n handleCtrlC(input, key, onAbort)\n } else {\n handleCtrlC(input, key)\n }\n },\n {isActive: Boolean(isRawModeSupported)},\n )\n\n useEffect(() => {\n task(setStatus)\n .then((result) => {\n setIsDone(true)\n onComplete?.(result)\n setTaskResult({})\n })\n .catch((error) => {\n setIsDone(true)\n setTaskResult({error})\n })\n }, [task, onComplete])\n\n useEffect(() => {\n if (taskResult !== null) {\n complete(taskResult.error)\n }\n }, [taskResult, complete])\n\n if (isDone) {\n // clear things once done\n return null\n }\n\n return <LoadingBar title={status.value} noColor={noColor} />\n}\n\nexport {SingleTask}\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { TokenizedText } from './TokenizedText.js';
|
|
2
2
|
import { TextInput } from './TextInput.js';
|
|
3
|
-
import { handleCtrlC } from '../../ui.js';
|
|
3
|
+
import { handleCtrlC, useComplete } from '../../ui.js';
|
|
4
4
|
import useLayout from '../hooks/use-layout.js';
|
|
5
5
|
import { messageWithPunctuation } from '../utilities.js';
|
|
6
6
|
import useAbortSignal from '../hooks/use-abort-signal.js';
|
|
7
7
|
import usePrompt, { PromptState } from '../hooks/use-prompt.js';
|
|
8
8
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
9
|
-
import { Box,
|
|
9
|
+
import { Box, useInput, Text } from 'ink';
|
|
10
10
|
import figures from 'figures';
|
|
11
11
|
const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password = false, allowEmpty = false, emptyDisplayedValue = '(empty)', abortSignal, preview, initialAnswer = '', }) => {
|
|
12
12
|
if (password && defaultValue) {
|
|
@@ -27,7 +27,7 @@ const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password =
|
|
|
27
27
|
const answerOrDefault = answer.length > 0 ? answer : defaultValue;
|
|
28
28
|
const displayEmptyValue = answerOrDefault === '';
|
|
29
29
|
const displayedAnswer = displayEmptyValue ? emptyDisplayedValue : answerOrDefault;
|
|
30
|
-
const
|
|
30
|
+
const complete = useComplete();
|
|
31
31
|
const [error, setError] = useState(undefined);
|
|
32
32
|
const color = promptState === PromptState.Error ? 'red' : 'cyan';
|
|
33
33
|
const underline = new Array(oneThird - 3).fill('▔');
|
|
@@ -48,9 +48,9 @@ const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password =
|
|
|
48
48
|
useEffect(() => {
|
|
49
49
|
if (promptState === PromptState.Submitted) {
|
|
50
50
|
onSubmit(answerOrDefault);
|
|
51
|
-
|
|
51
|
+
complete();
|
|
52
52
|
}
|
|
53
|
-
}, [answerOrDefault, onSubmit, promptState,
|
|
53
|
+
}, [answerOrDefault, onSubmit, promptState, complete]);
|
|
54
54
|
return isAborted ? null : (React.createElement(Box, { flexDirection: "column", marginBottom: 1, width: oneThird },
|
|
55
55
|
React.createElement(Box, null,
|
|
56
56
|
React.createElement(Box, { marginRight: 2 },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,aAAa,EAAC,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"TextPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {TextInput} from './TextInput.js'\nimport {handleCtrlC, useComplete} from '../../ui.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\nimport React, {FunctionComponent, useCallback, useEffect, useState} from 'react'\n\nimport {Box, useInput, Text} from 'ink'\nimport figures from 'figures'\n\nexport interface TextPromptProps {\n message: TokenItem\n onSubmit: (value: string) => void\n defaultValue?: string\n password?: boolean\n validate?: (value: string) => string | undefined\n allowEmpty?: boolean\n emptyDisplayedValue?: string\n abortSignal?: AbortSignal\n preview?: (value: string) => TokenItem<InlineToken>\n initialAnswer?: string\n}\n\nconst TextPrompt: FunctionComponent<TextPromptProps> = ({\n message,\n onSubmit,\n validate,\n defaultValue = '',\n password = false,\n allowEmpty = false,\n emptyDisplayedValue = '(empty)',\n abortSignal,\n preview,\n initialAnswer = '',\n}) => {\n if (password && defaultValue) {\n throw new Error(\"Can't use defaultValue with password\")\n }\n\n const validateAnswer = useCallback(\n (value: string): string | undefined => {\n if (validate) {\n return validate(value)\n }\n\n if (value.length === 0 && !allowEmpty) return 'Type an answer to the prompt.'\n\n return undefined\n },\n [allowEmpty, validate],\n )\n\n const {oneThird} = useLayout()\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<string>({\n initialAnswer,\n })\n const answerOrDefault = answer.length > 0 ? answer : defaultValue\n const displayEmptyValue = answerOrDefault === ''\n const displayedAnswer = displayEmptyValue ? emptyDisplayedValue : answerOrDefault\n const complete = useComplete()\n const [error, setError] = useState<string | undefined>(undefined)\n const color = promptState === PromptState.Error ? 'red' : 'cyan'\n const underline = new Array(oneThird - 3).fill('▔')\n const {isAborted} = useAbortSignal(abortSignal)\n\n useInput((input, key) => {\n handleCtrlC(input, key)\n\n if (key.return) {\n const error = validateAnswer(answerOrDefault)\n\n if (error) {\n setPromptState(PromptState.Error)\n setError(error)\n } else {\n setPromptState(PromptState.Submitted)\n }\n }\n })\n\n useEffect(() => {\n if (promptState === PromptState.Submitted) {\n onSubmit(answerOrDefault)\n complete()\n }\n }, [answerOrDefault, onSubmit, promptState, complete])\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} width={oneThird}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n </Box>\n {promptState === PromptState.Submitted ? (\n <Box>\n <Box width={3}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Box flexGrow={1}>\n <Text color=\"cyan\" dimColor={displayEmptyValue}>\n {password ? '*'.repeat(answer.length) : displayedAnswer}\n </Text>\n </Box>\n </Box>\n ) : (\n <Box flexDirection=\"column\">\n <Box>\n <Box marginRight={2}>\n <Text color={color}>{`>`}</Text>\n </Box>\n <Box flexGrow={1}>\n <TextInput\n value={answer}\n onChange={(answer) => {\n setAnswer(answer)\n setPromptState(PromptState.Idle)\n }}\n defaultValue={defaultValue}\n color={color}\n password={password}\n />\n </Box>\n </Box>\n <Box marginLeft={3}>\n <Text color={color}>{underline}</Text>\n </Box>\n {promptState === PromptState.Error ? (\n <Box marginLeft={3}>\n <Text color={color}>{error}</Text>\n </Box>\n ) : null}\n {promptState !== PromptState.Error && preview ? (\n <Box marginLeft={3}>\n <TokenizedText item={preview(answerOrDefault)} />\n </Box>\n ) : null}\n </Box>\n )}\n </Box>\n )\n}\n\nexport {TextPrompt}\n"]}
|
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useLayoutEffect, useState } from 'react';
|
|
1
|
+
import { useComplete } from '../../ui.js';
|
|
2
|
+
import { useEffect, useLayoutEffect, useState } from 'react';
|
|
3
3
|
const noop = () => Promise.resolve();
|
|
4
4
|
export default function useAbortSignal(abortSignal, onAbort = noop) {
|
|
5
|
-
const
|
|
5
|
+
const complete = useComplete();
|
|
6
6
|
const [isAborted, setIsAborted] = useState(false);
|
|
7
7
|
useLayoutEffect(() => {
|
|
8
8
|
abortSignal?.addEventListener('abort', () => {
|
|
9
9
|
const abortWithError = abortSignal.reason.message === 'AbortError' ? undefined : abortSignal.reason;
|
|
10
10
|
onAbort(abortWithError)
|
|
11
|
-
.then(() =>
|
|
12
|
-
setIsAborted(true);
|
|
13
|
-
// Defer unmounting to the next setImmediate so React 19 can flush
|
|
14
|
-
// batched state updates before the tree is torn down. React 19's
|
|
15
|
-
// scheduler also uses setImmediate in Node.js (check phase), and
|
|
16
|
-
// since it was queued first (by setIsAborted above), it renders
|
|
17
|
-
// before this callback fires (FIFO within the check phase).
|
|
18
|
-
// NOTE: setTimeout(fn, 0) is NOT safe here because its timers-phase
|
|
19
|
-
// fires BEFORE the check phase on slow CI machines where >1 ms has
|
|
20
|
-
// elapsed, causing unmount to race ahead of the render.
|
|
21
|
-
setImmediate(() => unmountInk(abortWithError));
|
|
22
|
-
})
|
|
11
|
+
.then(() => setIsAborted(true))
|
|
23
12
|
.catch(() => { });
|
|
24
13
|
});
|
|
25
14
|
}, []);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (isAborted) {
|
|
17
|
+
const abortWithError = abortSignal?.reason?.message === 'AbortError' ? undefined : abortSignal?.reason;
|
|
18
|
+
complete(abortWithError);
|
|
19
|
+
}
|
|
20
|
+
}, [isAborted]);
|
|
26
21
|
return { isAborted };
|
|
27
22
|
}
|
|
28
23
|
//# sourceMappingURL=use-abort-signal.js.map
|