@shopify/cli-kit 3.47.4 → 3.48.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/assets/cli-ruby/lib/project_types/extension/messages/messages.rb +18 -1
- package/assets/cli-ruby/lib/shopify_cli/constants.rb +1 -0
- package/assets/cli-ruby/lib/shopify_cli/environment.rb +7 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +8 -2
- package/dist/private/node/ui/alert.js +3 -1
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/Alert.d.ts +1 -1
- package/dist/private/node/ui/components/Alert.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.d.ts +7 -2
- package/dist/private/node/ui/components/AutocompletePrompt.js +28 -91
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +317 -257
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +1 -0
- package/dist/private/node/ui/components/ConcurrentOutput.js +59 -32
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +62 -22
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +12 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js +77 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js +101 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js.map +1 -0
- package/dist/private/node/ui/components/List.d.ts +1 -0
- package/dist/private/node/ui/components/List.js +2 -2
- package/dist/private/node/ui/components/List.js.map +1 -1
- package/dist/private/node/ui/components/{GitDiff.d.ts → Prompts/GitDiff.d.ts} +4 -2
- package/dist/private/node/ui/components/{GitDiff.js → Prompts/GitDiff.js} +3 -2
- package/dist/private/node/ui/components/Prompts/GitDiff.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/GitDiff.test.d.ts +1 -0
- package/dist/private/node/ui/components/{GitDiff.test.js → Prompts/GitDiff.test.js} +50 -28
- package/dist/private/node/ui/components/Prompts/GitDiff.test.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.d.ts +14 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.js +11 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.test.d.ts +1 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.test.js +21 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.test.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -0
- package/dist/private/node/ui/components/Prompts/InfoTable.js +11 -7
- package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.test.js +6 -4
- package/dist/private/node/ui/components/Prompts/InfoTable.test.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +21 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.js +73 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.d.ts +1 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js +129 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js.map +1 -0
- package/dist/private/node/ui/components/Scrollbar.d.ts +10 -0
- package/dist/private/node/ui/components/Scrollbar.js +44 -0
- package/dist/private/node/ui/components/Scrollbar.js.map +1 -0
- package/dist/private/node/ui/components/Scrollbar.test.d.ts +1 -0
- package/dist/private/node/ui/components/Scrollbar.test.js +96 -0
- package/dist/private/node/ui/components/Scrollbar.test.js.map +1 -0
- package/dist/private/node/ui/components/SelectInput.d.ts +3 -6
- package/dist/private/node/ui/components/SelectInput.js +57 -41
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js +120 -192
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.d.ts +7 -6
- package/dist/private/node/ui/components/SelectPrompt.js +11 -68
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +135 -65
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Table/Row.js +2 -1
- package/dist/private/node/ui/components/Table/Row.js.map +1 -1
- package/dist/private/node/ui/components/Table/Table.js +2 -1
- package/dist/private/node/ui/components/Table/Table.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.js +1 -8
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.d.ts +1 -0
- package/dist/private/node/ui/components/TextInput.js +10 -4
- package/dist/private/node/ui/components/TextInput.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.test.js +27 -18
- package/dist/private/node/ui/components/TextInput.test.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.d.ts +2 -3
- package/dist/private/node/ui/components/TextPrompt.js +18 -16
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.test.js +25 -11
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
- package/dist/private/node/ui/hooks/use-prompt.d.ts +18 -0
- package/dist/private/node/ui/hooks/use-prompt.js +20 -0
- package/dist/private/node/ui/hooks/use-prompt.js.map +1 -0
- package/dist/private/node/ui/hooks/use-select-state.d.ts +4 -4
- package/dist/private/node/ui/hooks/use-select-state.js +9 -9
- package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
- package/dist/public/common/object.d.ts +16 -0
- package/dist/public/common/object.js +26 -0
- package/dist/public/common/object.js.map +1 -1
- package/dist/public/common/string.d.ts +16 -0
- package/dist/public/common/string.js +30 -0
- package/dist/public/common/string.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/analytics.js +3 -1
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/base-command.d.ts +1 -0
- package/dist/public/node/base-command.js +21 -1
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/figures.d.ts +2 -0
- package/dist/public/node/figures.js +3 -0
- package/dist/public/node/figures.js.map +1 -0
- package/dist/public/node/metadata.d.ts +2 -1
- package/dist/public/node/metadata.js +5 -2
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/monorail.d.ts +22 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/output.d.ts +1 -1
- package/dist/public/node/output.js +1 -1
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/ruby.d.ts +1 -0
- package/dist/public/node/ruby.js +1 -0
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/system.js +2 -2
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/themes/models/theme.d.ts +2 -1
- package/dist/public/node/themes/models/theme.js +2 -1
- package/dist/public/node/themes/models/theme.js.map +1 -1
- package/dist/public/node/themes/theme-urls.d.ts +1 -0
- package/dist/public/node/themes/theme-urls.js +4 -0
- package/dist/public/node/themes/theme-urls.js.map +1 -1
- package/dist/public/node/themes/themes-api.d.ts +9 -1
- package/dist/public/node/themes/themes-api.js +14 -3
- package/dist/public/node/themes/themes-api.js.map +1 -1
- package/dist/public/node/toml.d.ts +3 -2
- package/dist/public/node/toml.js +5 -2
- package/dist/public/node/toml.js.map +1 -1
- package/dist/public/node/ui.d.ts +82 -27
- package/dist/public/node/ui.js +97 -32
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -14
- package/dist/private/node/ui/components/GitDiff.js.map +0 -1
- package/dist/private/node/ui/components/GitDiff.test.js.map +0 -1
- /package/dist/private/node/ui/components/{GitDiff.test.d.ts → DangerousConfirmationPrompt.test.d.ts} +0 -0
|
@@ -128,7 +128,7 @@ module Extension
|
|
|
128
128
|
PREVIEW_MESSAGE
|
|
129
129
|
preview_message_1p: <<~PREVIEW_MESSAGE,
|
|
130
130
|
Access Shopify Organization:
|
|
131
|
-
|
|
131
|
+
{{green:%s}}
|
|
132
132
|
|
|
133
133
|
Enable your theme app extension:
|
|
134
134
|
{{green:%s}}
|
|
@@ -136,6 +136,23 @@ module Extension
|
|
|
136
136
|
Setup your theme app extension in the host theme:
|
|
137
137
|
{{green:%s}}
|
|
138
138
|
|
|
139
|
+
Preview your theme app extension:
|
|
140
|
+
{{green:%s}}
|
|
141
|
+
PREVIEW_MESSAGE
|
|
142
|
+
preview_message_unified: <<~PREVIEW_MESSAGE,
|
|
143
|
+
Setup your theme app extension in the host theme:
|
|
144
|
+
{{green:%s}}
|
|
145
|
+
|
|
146
|
+
Preview your theme app extension:
|
|
147
|
+
{{green:%s}}
|
|
148
|
+
PREVIEW_MESSAGE
|
|
149
|
+
preview_message_1p_unified: <<~PREVIEW_MESSAGE,
|
|
150
|
+
Access Shopify Organization:
|
|
151
|
+
{{green:%s}}
|
|
152
|
+
|
|
153
|
+
Setup your theme app extension in the host theme:
|
|
154
|
+
{{green:%s}}
|
|
155
|
+
|
|
139
156
|
Preview your theme app extension:
|
|
140
157
|
{{green:%s}}
|
|
141
158
|
PREVIEW_MESSAGE
|
|
@@ -33,6 +33,7 @@ module ShopifyCLI
|
|
|
33
33
|
TTY = "SHOPIFY_CLI_TTY"
|
|
34
34
|
RUN_AS_SUBPROCESS = "SHOPIFY_CLI_RUN_AS_SUBPROCESS"
|
|
35
35
|
RUBY_BIN = "SHOPIFY_CLI_RUBY_BIN"
|
|
36
|
+
UNIFIED_DEPLOYMENT = "SHOPIFY_CLI_UNIFIED_DEPLOYMENT"
|
|
36
37
|
|
|
37
38
|
# When true the CLI points to a local instance of
|
|
38
39
|
# the partners dashboard and identity.
|
|
@@ -199,5 +199,12 @@ module ShopifyCLI
|
|
|
199
199
|
def self.theme_access_password?
|
|
200
200
|
admin_auth_token&.start_with?(THEME_ACCESS_PASSWORD_PREFIX)
|
|
201
201
|
end
|
|
202
|
+
|
|
203
|
+
def self.unified_deployment?(env_variables: ENV)
|
|
204
|
+
env_variable_truthy?(
|
|
205
|
+
Constants::EnvironmentVariables::UNIFIED_DEPLOYMENT,
|
|
206
|
+
env_variables: env_variables
|
|
207
|
+
)
|
|
208
|
+
end
|
|
202
209
|
end
|
|
203
210
|
end
|
|
@@ -159,9 +159,15 @@ module ShopifyCLI
|
|
|
159
159
|
|
|
160
160
|
def preview_message
|
|
161
161
|
if Shopifolk.acting_as_shopify_organization?
|
|
162
|
-
parsed_uri = URI.parse(extension.
|
|
162
|
+
parsed_uri = URI.parse(extension.preview_message)
|
|
163
163
|
shopify_org_url = "#{parsed_uri.scheme}://#{parsed_uri.host}/9082/impersonate"
|
|
164
|
-
|
|
164
|
+
if ShopifyCLI::Environment.unified_deployment?
|
|
165
|
+
ctx.message("serve.preview_message_1p_unified", shopify_org_url, theme.editor_url, address)
|
|
166
|
+
else
|
|
167
|
+
ctx.message("serve.preview_message_1p", shopify_org_url, extension.location, theme.editor_url, address)
|
|
168
|
+
end
|
|
169
|
+
elsif ShopifyCLI::Environment.unified_deployment?
|
|
170
|
+
ctx.message("serve.preview_message_unified", theme.editor_url, address)
|
|
165
171
|
else
|
|
166
172
|
ctx.message("serve.preview_message", extension.location, theme.editor_url, address)
|
|
167
173
|
end
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { Alert } from './components/Alert.js';
|
|
2
2
|
import { renderOnce } from '../ui.js';
|
|
3
|
-
import { consoleLog, consoleWarn } from '../../../public/node/output.js';
|
|
3
|
+
import { consoleError, consoleLog, consoleWarn } from '../../../public/node/output.js';
|
|
4
4
|
import { recordUIEvent } from '../demo-recorder.js';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
const typeToLogLevel = {
|
|
7
7
|
info: 'info',
|
|
8
8
|
warning: 'warn',
|
|
9
9
|
success: 'info',
|
|
10
|
+
error: 'error',
|
|
10
11
|
};
|
|
11
12
|
const typeToLogger = {
|
|
12
13
|
info: consoleLog,
|
|
13
14
|
warning: consoleWarn,
|
|
14
15
|
success: consoleLog,
|
|
16
|
+
error: consoleError,
|
|
15
17
|
};
|
|
16
18
|
export function alert({ type, headline, body, nextSteps, reference, link, customSections, orderedNextSteps = false, renderOptions, }) {
|
|
17
19
|
// eslint-disable-next-line prefer-rest-params
|
|
@@ -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,UAAU,EAAC,MAAM,UAAU,CAAA;AACnC,OAAO,EAAC,UAAU,EAAE,WAAW,EAAmB,MAAM,gCAAgC,CAAA;
|
|
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,UAAU,EAAC,MAAM,UAAU,CAAA;AACnC,OAAO,EAAC,YAAY,EAAE,UAAU,EAAE,WAAW,EAAmB,MAAM,gCAAgC,CAAA;AACtG,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,cAAc,GAA4C;IAC9D,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,OAAO;CACf,CAAA;AAED,MAAM,YAAY,GAA0C;IAC1D,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,WAAW;IACpB,OAAO,EAAE,UAAU;IACnB,KAAK,EAAE,YAAY;CACpB,CAAA;AAMD,MAAM,UAAU,KAAK,CAAC,EACpB,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,SAAS,EACT,IAAI,EACJ,cAAc,EACd,gBAAgB,GAAG,KAAK,EACxB,aAAa,GACA;IACb,8CAA8C;IAC9C,MAAM,EAAC,IAAI,EAAE,SAAS,EAAE,GAAG,UAAU,EAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IACrD,aAAa,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAC,CAAC,CAAA;IAE7C,OAAO,UAAU,CACf,oBAAC,KAAK,IACJ,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,EACV,gBAAgB,EAAE,gBAAgB,EAClC,cAAc,EAAE,cAAc,GAC9B,EACF,EAAC,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,aAAa,EAAC,CAC5E,CAAA;AACH,CAAC","sourcesContent":["import {Alert, AlertProps} from './components/Alert.js'\nimport {renderOnce} from '../ui.js'\nimport {consoleError, consoleLog, consoleWarn, Logger, LogLevel} from '../../../public/node/output.js'\nimport {recordUIEvent} from '../demo-recorder.js'\nimport React from 'react'\nimport {RenderOptions} from 'ink'\n\nconst typeToLogLevel: {[key in AlertProps['type']]: LogLevel} = {\n info: 'info',\n warning: 'warn',\n success: 'info',\n error: 'error',\n}\n\nconst typeToLogger: {[key in AlertProps['type']]: Logger} = {\n info: consoleLog,\n warning: consoleWarn,\n success: consoleLog,\n error: consoleError,\n}\n\nexport interface AlertOptions extends AlertProps {\n renderOptions?: RenderOptions\n}\n\nexport function alert({\n type,\n headline,\n body,\n nextSteps,\n reference,\n link,\n customSections,\n orderedNextSteps = false,\n renderOptions,\n}: AlertOptions) {\n // eslint-disable-next-line prefer-rest-params\n const {type: alertType, ...eventProps} = arguments[0]\n recordUIEvent({type, properties: eventProps})\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], logger: typeToLogger[type], renderOptions},\n )\n}\n"]}
|
|
@@ -6,7 +6,7 @@ export interface CustomSection {
|
|
|
6
6
|
body: TokenItem;
|
|
7
7
|
}
|
|
8
8
|
export interface AlertProps {
|
|
9
|
-
type: Exclude<BannerType, '
|
|
9
|
+
type: Exclude<BannerType, 'external_error'>;
|
|
10
10
|
headline?: TokenItem<Exclude<InlineToken, LinkToken | BoldToken>>;
|
|
11
11
|
body?: TokenItem;
|
|
12
12
|
nextSteps?: TokenItem<InlineToken>[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Alert.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAa,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAA+C,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAC9F,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC7B,OAAO,KAA0B,MAAM,OAAO,CAAA;AAqB9C,MAAM,KAAK,GAAkC,CAAC,EAC5C,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,SAAS,EACT,IAAI,EACJ,cAAc,EACd,gBAAgB,GAAG,KAAK,GACzB,EAAE,EAAE;IACH,OAAO,CACL,oBAAC,MAAM,IAAC,IAAI,EAAE,IAAI;QACf,QAAQ,CAAC,CAAC,CAAC,CACV,oBAAC,IAAI,IAAC,IAAI;YACR,oBAAC,aAAa,IAAC,IAAI,EAAE,QAAQ,GAAI,CAC5B,CACR,CAAC,CAAC,CAAC,IAAI;QAEP,IAAI,CAAC,CAAC,CAAC,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CAAC,CAAC,CAAC,IAAI;QAE3C,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACnC,oBAAC,IAAI,IAAC,KAAK,EAAC,YAAY,EAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,GAAI,CACzE,CAAC,CAAC,CAAC,IAAI;QAEP,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,WAAW,EAAC,KAAK,EAAE,SAAS,GAAI,CAAC,CAAC,CAAC,IAAI;QAEvF,IAAI,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAI,CAAC,CAAC,CAAC,IAAI;QAExD,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC7C,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,IAC/B,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CACtC,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,aAAa,EAAC,QAAQ;YACpC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,IAAI,UAAE,OAAO,CAAC,KAAK,CAAQ,CAAC,CAAC,CAAC,IAAI;YACzD,oBAAC,aAAa,IAAC,IAAI,EAAE,OAAO,CAAC,IAAI,GAAI,CACjC,CACP,CAAC,CACE,CACP,CAAC,CAAC,CAAC,IAAI,CACD,CACV,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,KAAK,EAAC,CAAA","sourcesContent":["import {Banner, BannerType} from './Banner.js'\nimport {Link} from './Link.js'\nimport {List} from './List.js'\nimport {BoldToken, InlineToken, LinkToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {Box, Text} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\nexport interface CustomSection {\n title?: string\n body: TokenItem\n}\n\nexport interface AlertProps {\n type: Exclude<BannerType, '
|
|
1
|
+
{"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Alert.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAa,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAA+C,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAC9F,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC7B,OAAO,KAA0B,MAAM,OAAO,CAAA;AAqB9C,MAAM,KAAK,GAAkC,CAAC,EAC5C,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,SAAS,EACT,IAAI,EACJ,cAAc,EACd,gBAAgB,GAAG,KAAK,GACzB,EAAE,EAAE;IACH,OAAO,CACL,oBAAC,MAAM,IAAC,IAAI,EAAE,IAAI;QACf,QAAQ,CAAC,CAAC,CAAC,CACV,oBAAC,IAAI,IAAC,IAAI;YACR,oBAAC,aAAa,IAAC,IAAI,EAAE,QAAQ,GAAI,CAC5B,CACR,CAAC,CAAC,CAAC,IAAI;QAEP,IAAI,CAAC,CAAC,CAAC,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CAAC,CAAC,CAAC,IAAI;QAE3C,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACnC,oBAAC,IAAI,IAAC,KAAK,EAAC,YAAY,EAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,GAAI,CACzE,CAAC,CAAC,CAAC,IAAI;QAEP,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,WAAW,EAAC,KAAK,EAAE,SAAS,GAAI,CAAC,CAAC,CAAC,IAAI;QAEvF,IAAI,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAI,CAAC,CAAC,CAAC,IAAI;QAExD,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC7C,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,IAC/B,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CACtC,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,aAAa,EAAC,QAAQ;YACpC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,IAAI,UAAE,OAAO,CAAC,KAAK,CAAQ,CAAC,CAAC,CAAC,IAAI;YACzD,oBAAC,aAAa,IAAC,IAAI,EAAE,OAAO,CAAC,IAAI,GAAI,CACjC,CACP,CAAC,CACE,CACP,CAAC,CAAC,CAAC,IAAI,CACD,CACV,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,KAAK,EAAC,CAAA","sourcesContent":["import {Banner, BannerType} from './Banner.js'\nimport {Link} from './Link.js'\nimport {List} from './List.js'\nimport {BoldToken, InlineToken, LinkToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {Box, Text} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\nexport interface CustomSection {\n title?: string\n body: TokenItem\n}\n\nexport interface AlertProps {\n type: Exclude<BannerType, 'external_error'>\n headline?: TokenItem<Exclude<InlineToken, LinkToken | BoldToken>>\n body?: TokenItem\n nextSteps?: TokenItem<InlineToken>[]\n reference?: TokenItem<InlineToken>[]\n link?: {\n label: string\n url: string\n }\n orderedNextSteps?: boolean\n customSections?: CustomSection[]\n}\n\nconst Alert: FunctionComponent<AlertProps> = ({\n type,\n headline,\n body,\n nextSteps,\n reference,\n link,\n customSections,\n orderedNextSteps = false,\n}) => {\n return (\n <Banner type={type}>\n {headline ? (\n <Text bold>\n <TokenizedText item={headline} />\n </Text>\n ) : null}\n\n {body ? <TokenizedText item={body} /> : null}\n\n {nextSteps && nextSteps.length > 0 ? (\n <List title=\"Next steps\" items={nextSteps} ordered={orderedNextSteps} />\n ) : null}\n\n {reference && reference.length > 0 ? <List title=\"Reference\" items={reference} /> : null}\n\n {link ? <Link url={link.url} label={link.label} /> : null}\n\n {customSections && customSections.length > 0 ? (\n <Box flexDirection=\"column\" gap={1}>\n {customSections.map((section, index) => (\n <Box key={index} flexDirection=\"column\">\n {section.title ? <Text bold>{section.title}</Text> : null}\n <TokenizedText item={section.body} />\n </Box>\n ))}\n </Box>\n ) : null}\n </Banner>\n )\n}\n\nexport {Alert}\n"]}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { SelectInputProps, Item as SelectItem } from './SelectInput.js';
|
|
2
2
|
import { InfoTableProps } from './Prompts/InfoTable.js';
|
|
3
|
+
import { InfoMessageProps } from './Prompts/InfoMessage.js';
|
|
4
|
+
import { GitDiffProps } from './Prompts/GitDiff.js';
|
|
5
|
+
import { Message } from './Prompts/PromptLayout.js';
|
|
3
6
|
import { AbortSignal } from '../../../../public/node/abort.js';
|
|
4
7
|
import React, { ReactElement } from 'react';
|
|
5
8
|
export interface SearchResults<T> {
|
|
@@ -9,13 +12,15 @@ export interface SearchResults<T> {
|
|
|
9
12
|
};
|
|
10
13
|
}
|
|
11
14
|
export interface AutocompletePromptProps<T> {
|
|
12
|
-
message:
|
|
15
|
+
message: Message;
|
|
13
16
|
choices: SelectInputProps<T>['items'];
|
|
14
17
|
onSubmit: (value: T) => void;
|
|
15
18
|
infoTable?: InfoTableProps['table'];
|
|
16
19
|
hasMorePages?: boolean;
|
|
17
20
|
search: (term: string) => Promise<SearchResults<T>>;
|
|
18
21
|
abortSignal?: AbortSignal;
|
|
22
|
+
infoMessage?: InfoMessageProps['message'];
|
|
23
|
+
gitDiff?: GitDiffProps['gitDiff'];
|
|
19
24
|
}
|
|
20
|
-
declare function AutocompletePrompt<T>({ message, choices
|
|
25
|
+
declare function AutocompletePrompt<T>({ message, choices, infoTable, onSubmit, search, hasMorePages: initialHasMorePages, abortSignal, infoMessage, gitDiff, }: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null;
|
|
21
26
|
export { AutocompletePrompt };
|
|
@@ -1,85 +1,34 @@
|
|
|
1
1
|
import { SelectInput } from './SelectInput.js';
|
|
2
|
-
import { InfoTable } from './Prompts/InfoTable.js';
|
|
3
2
|
import { TextInput } from './TextInput.js';
|
|
4
|
-
import {
|
|
5
|
-
import { messageWithPunctuation } from '../utilities.js';
|
|
3
|
+
import { PromptLayout } from './Prompts/PromptLayout.js';
|
|
6
4
|
import { debounce } from '../../../../public/common/function.js';
|
|
7
|
-
import
|
|
8
|
-
import React, { useCallback,
|
|
9
|
-
import { Box,
|
|
10
|
-
|
|
11
|
-
import ansiEscapes from 'ansi-escapes';
|
|
12
|
-
import { uniqBy } from '@shopify/cli-kit/common/array';
|
|
13
|
-
var PromptState;
|
|
14
|
-
(function (PromptState) {
|
|
15
|
-
PromptState["Idle"] = "idle";
|
|
16
|
-
PromptState["Loading"] = "loading";
|
|
17
|
-
PromptState["Submitted"] = "submitted";
|
|
18
|
-
PromptState["Error"] = "error";
|
|
19
|
-
})(PromptState || (PromptState = {}));
|
|
20
|
-
const PAGE_SIZE = 25;
|
|
5
|
+
import usePrompt, { PromptState } from '../hooks/use-prompt.js';
|
|
6
|
+
import React, { useCallback, useRef, useState } from 'react';
|
|
7
|
+
import { Box, useApp } from 'ink';
|
|
8
|
+
const MIN_NUMBER_OF_ITEMS_FOR_SEARCH = 5;
|
|
21
9
|
// eslint-disable-next-line react/function-component-definition
|
|
22
|
-
function AutocompletePrompt({ message, choices
|
|
23
|
-
const paginatedInitialChoices = initialChoices.slice(0, PAGE_SIZE);
|
|
24
|
-
const [answer, setAnswer] = useState(paginatedInitialChoices[0]);
|
|
10
|
+
function AutocompletePrompt({ message, choices, infoTable, onSubmit, search, hasMorePages: initialHasMorePages = false, abortSignal, infoMessage, gitDiff, }) {
|
|
25
11
|
const { exit: unmountInk } = useApp();
|
|
26
|
-
const [promptState, setPromptState] = useState(PromptState.Idle);
|
|
27
12
|
const [searchTerm, setSearchTerm] = useState('');
|
|
28
|
-
const [searchResults, setSearchResults] = useState(
|
|
29
|
-
const
|
|
30
|
-
const canSearch = initialChoices.length >= PAGE_SIZE;
|
|
13
|
+
const [searchResults, setSearchResults] = useState(choices);
|
|
14
|
+
const canSearch = choices.length > MIN_NUMBER_OF_ITEMS_FOR_SEARCH;
|
|
31
15
|
const [hasMorePages, setHasMorePages] = useState(initialHasMorePages);
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const numberOfGroups = uniqBy(searchResults.filter((choice) => choice.group), 'group').length;
|
|
16
|
+
const { promptState, setPromptState, answer, setAnswer } = usePrompt({
|
|
17
|
+
initialAnswer: undefined,
|
|
18
|
+
});
|
|
36
19
|
const paginatedSearch = useCallback(async (term) => {
|
|
37
20
|
const results = await search(term);
|
|
38
|
-
results.data = results.data.slice(0, PAGE_SIZE);
|
|
39
21
|
return results;
|
|
40
22
|
}, [search]);
|
|
41
|
-
const wrapperRef = useCallback((node) => {
|
|
42
|
-
if (node !== null) {
|
|
43
|
-
const { height } = measureElement(node);
|
|
44
|
-
setWrapperHeight(height);
|
|
45
|
-
}
|
|
46
|
-
}, []);
|
|
47
|
-
const inputRef = useCallback((node) => {
|
|
48
|
-
if (node !== null) {
|
|
49
|
-
const { height } = measureElement(node);
|
|
50
|
-
setSelectInputHeight(height);
|
|
51
|
-
}
|
|
52
|
-
}, []);
|
|
53
|
-
useLayoutEffect(() => {
|
|
54
|
-
function onResize() {
|
|
55
|
-
const availableSpace = stdout.rows - (wrapperHeight - selectInputHeight);
|
|
56
|
-
// rough estimate of the limit needed based on the space available
|
|
57
|
-
const newLimit = Math.max(2, availableSpace - numberOfGroups * 2 - 4);
|
|
58
|
-
if (newLimit < limit) {
|
|
59
|
-
stdout.write(ansiEscapes.clearTerminal);
|
|
60
|
-
}
|
|
61
|
-
setLimit(Math.min(newLimit, searchResults.length));
|
|
62
|
-
}
|
|
63
|
-
onResize();
|
|
64
|
-
stdout.on('resize', onResize);
|
|
65
|
-
return () => {
|
|
66
|
-
stdout.off('resize', onResize);
|
|
67
|
-
};
|
|
68
|
-
}, [wrapperHeight, selectInputHeight, searchResults.length, stdout, limit, numberOfGroups]);
|
|
69
|
-
const { isAborted } = useAbortSignal(abortSignal);
|
|
70
23
|
const submitAnswer = useCallback((answer) => {
|
|
71
24
|
if (promptState === PromptState.Idle) {
|
|
72
|
-
// -1 is for the last row with the terminal cursor
|
|
73
|
-
if (stdout && wrapperHeight >= stdout.rows - 1) {
|
|
74
|
-
stdout.write(ansiEscapes.clearTerminal);
|
|
75
|
-
}
|
|
76
25
|
setAnswer(answer);
|
|
77
26
|
setPromptState(PromptState.Submitted);
|
|
78
27
|
setSearchTerm('');
|
|
79
28
|
unmountInk();
|
|
80
29
|
onSubmit(answer.value);
|
|
81
30
|
}
|
|
82
|
-
}, [promptState,
|
|
31
|
+
}, [promptState, setAnswer, setPromptState, unmountInk, onSubmit]);
|
|
83
32
|
const setLoadingWhenSlow = useRef();
|
|
84
33
|
// we want to set it each time so that searchTermRef always tracks searchTerm,
|
|
85
34
|
// this is NOT the same as writing useRef(searchTerm)
|
|
@@ -97,7 +46,7 @@ function AutocompletePrompt({ message, choices: initialChoices, infoTable, onSub
|
|
|
97
46
|
// has emptied the search term, so we want to show the default
|
|
98
47
|
// choices instead
|
|
99
48
|
if (searchTermRef.current.length === 0) {
|
|
100
|
-
setSearchResults(
|
|
49
|
+
setSearchResults(choices);
|
|
101
50
|
setHasMorePages(initialHasMorePages);
|
|
102
51
|
}
|
|
103
52
|
else {
|
|
@@ -112,33 +61,21 @@ function AutocompletePrompt({ message, choices: initialChoices, infoTable, onSub
|
|
|
112
61
|
.finally(() => {
|
|
113
62
|
clearTimeout(setLoadingWhenSlow.current);
|
|
114
63
|
});
|
|
115
|
-
}, 300), [initialHasMorePages,
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
setSearchResults(paginatedInitialChoices);
|
|
131
|
-
}
|
|
132
|
-
}, placeholder: "Type to search..." }))) : null),
|
|
133
|
-
infoTable && promptState !== PromptState.Submitted ? (React.createElement(Box, { marginLeft: 7, marginTop: 1 },
|
|
134
|
-
React.createElement(InfoTable, { table: infoTable }))) : null,
|
|
135
|
-
promptState === PromptState.Submitted ? (React.createElement(Box, null,
|
|
136
|
-
React.createElement(Box, { marginRight: 2 },
|
|
137
|
-
React.createElement(Text, { color: "cyan" }, figures.tick)),
|
|
138
|
-
React.createElement(Text, { color: "cyan" }, answer.label))) : (React.createElement(Box, { marginTop: 1 },
|
|
139
|
-
React.createElement(SelectInput, { items: searchResults, enableShortcuts: false, emptyMessage: "No results found.", highlightedTerm: searchTerm, loading: promptState === PromptState.Loading, errorMessage: promptState === PromptState.Error
|
|
140
|
-
? 'There has been an error while searching. Please try again later.'
|
|
141
|
-
: undefined, hasMorePages: hasMorePages, morePagesMessage: "Find what you're looking for by typing its name.", ref: inputRef, limit: limit, onSubmit: submitAnswer })))));
|
|
64
|
+
}, 300), [initialHasMorePages, choices, paginatedSearch, searchResults]);
|
|
65
|
+
return (React.createElement(PromptLayout, { message: message, state: promptState, infoTable: infoTable, infoMessage: infoMessage, gitDiff: gitDiff, abortSignal: abortSignal, header: promptState !== PromptState.Submitted && canSearch ? (React.createElement(Box, { marginLeft: 3 },
|
|
66
|
+
React.createElement(TextInput, { value: searchTerm, onChange: (term) => {
|
|
67
|
+
setSearchTerm(term);
|
|
68
|
+
if (term.length > 0) {
|
|
69
|
+
debounceSearch(term);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
debounceSearch.cancel();
|
|
73
|
+
setPromptState(PromptState.Idle);
|
|
74
|
+
setSearchResults(choices);
|
|
75
|
+
}
|
|
76
|
+
}, placeholder: "Type to search..." }))) : null, submittedAnswerLabel: answer?.label, input: React.createElement(SelectInput, { items: searchResults, initialItems: choices, enableShortcuts: false, emptyMessage: "No results found.", highlightedTerm: searchTerm, loading: promptState === PromptState.Loading, errorMessage: promptState === PromptState.Error
|
|
77
|
+
? 'There has been an error while searching. Please try again later.'
|
|
78
|
+
: undefined, hasMorePages: hasMorePages, morePagesMessage: "Find what you're looking for by typing its name.", onSubmit: submitAnswer }) }));
|
|
142
79
|
}
|
|
143
80
|
export { AutocompletePrompt };
|
|
144
81
|
//# sourceMappingURL=AutocompletePrompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutocompletePrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/AutocompletePrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTable, InfoTableProps} from './Prompts/InfoTable.js'\nimport {TextInput} from './TextInput.js'\nimport {TokenizedText} from './TokenizedText.js'\nimport {messageWithPunctuation} from '../utilities.js'\nimport {debounce} from '../../../../public/common/function.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport React, {ReactElement, useCallback, useLayoutEffect, useRef, useState} from 'react'\nimport {Box, measureElement, Text, useApp, useStdout} from 'ink'\nimport figures from 'figures'\nimport ansiEscapes from 'ansi-escapes'\nimport {uniqBy} from '@shopify/cli-kit/common/array'\n\nexport interface SearchResults<T> {\n data: SelectItem<T>[]\n meta?: {\n hasNextPage: boolean\n }\n}\n\nexport interface AutocompletePromptProps<T> {\n message: string\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n hasMorePages?: boolean\n search: (term: string) => Promise<SearchResults<T>>\n abortSignal?: AbortSignal\n}\n\nenum PromptState {\n Idle = 'idle',\n Loading = 'loading',\n Submitted = 'submitted',\n Error = 'error',\n}\n\nconst PAGE_SIZE = 25\n\n// eslint-disable-next-line react/function-component-definition\nfunction AutocompletePrompt<T>({\n message,\n choices: initialChoices,\n infoTable,\n onSubmit,\n search,\n hasMorePages: initialHasMorePages = false,\n abortSignal,\n}: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null {\n const paginatedInitialChoices = initialChoices.slice(0, PAGE_SIZE)\n const [answer, setAnswer] = useState<SelectItem<T> | undefined>(paginatedInitialChoices[0])\n const {exit: unmountInk} = useApp()\n const [promptState, setPromptState] = useState<PromptState>(PromptState.Idle)\n const [searchTerm, setSearchTerm] = useState('')\n const [searchResults, setSearchResults] = useState<SelectItem<T>[]>(paginatedInitialChoices.slice(0, PAGE_SIZE))\n const {stdout} = useStdout()\n const canSearch = initialChoices.length >= PAGE_SIZE\n const [hasMorePages, setHasMorePages] = useState(initialHasMorePages)\n const [wrapperHeight, setWrapperHeight] = useState(0)\n const [selectInputHeight, setSelectInputHeight] = useState(0)\n const [limit, setLimit] = useState(searchResults.length)\n const numberOfGroups = uniqBy(\n searchResults.filter((choice) => choice.group),\n 'group',\n ).length\n\n const paginatedSearch = useCallback(\n async (term: string) => {\n const results = await search(term)\n results.data = results.data.slice(0, PAGE_SIZE)\n return results\n },\n [search],\n )\n\n const wrapperRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setWrapperHeight(height)\n }\n }, [])\n\n const inputRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setSelectInputHeight(height)\n }\n }, [])\n\n useLayoutEffect(() => {\n function onResize() {\n const availableSpace = stdout.rows - (wrapperHeight - selectInputHeight)\n // rough estimate of the limit needed based on the space available\n const newLimit = Math.max(2, availableSpace - numberOfGroups * 2 - 4)\n\n if (newLimit < limit) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n\n setLimit(Math.min(newLimit, searchResults.length))\n }\n\n onResize()\n\n stdout.on('resize', onResize)\n return () => {\n stdout.off('resize', onResize)\n }\n }, [wrapperHeight, selectInputHeight, searchResults.length, stdout, limit, numberOfGroups])\n\n const {isAborted} = useAbortSignal(abortSignal)\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n if (promptState === PromptState.Idle) {\n // -1 is for the last row with the terminal cursor\n if (stdout && wrapperHeight >= stdout.rows - 1) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n setSearchTerm('')\n unmountInk()\n onSubmit(answer.value)\n }\n },\n [promptState, stdout, wrapperHeight, onSubmit, unmountInk],\n )\n\n const setLoadingWhenSlow = useRef<NodeJS.Timeout>()\n\n // we want to set it each time so that searchTermRef always tracks searchTerm,\n // this is NOT the same as writing useRef(searchTerm)\n const searchTermRef = useRef('')\n searchTermRef.current = searchTerm\n\n // disable exhaustive-deps because we want to memoize the debounce function itself\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const debounceSearch = useCallback(\n debounce((term: string) => {\n setLoadingWhenSlow.current = setTimeout(() => {\n setPromptState(PromptState.Loading)\n }, 100)\n paginatedSearch(term)\n .then((result) => {\n // while we were waiting for the promise to resolve, the user\n // has emptied the search term, so we want to show the default\n // choices instead\n if (searchTermRef.current.length === 0) {\n setSearchResults(paginatedInitialChoices)\n setHasMorePages(initialHasMorePages)\n } else {\n setSearchResults(result.data)\n setHasMorePages(result.meta?.hasNextPage ?? false)\n }\n\n setPromptState(PromptState.Idle)\n })\n .catch(() => {\n setPromptState(PromptState.Error)\n })\n .finally(() => {\n clearTimeout(setLoadingWhenSlow.current)\n })\n }, 300),\n [initialHasMorePages, paginatedInitialChoices, paginatedSearch],\n )\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} ref={wrapperRef}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n {promptState !== PromptState.Submitted && canSearch ? (\n <Box marginLeft={3}>\n <TextInput\n value={searchTerm}\n onChange={(term) => {\n setSearchTerm(term)\n\n if (term.length > 0) {\n debounceSearch(term)\n } else {\n debounceSearch.cancel()\n setPromptState(PromptState.Idle)\n setSearchResults(paginatedInitialChoices)\n }\n }}\n placeholder=\"Type to search...\"\n />\n </Box>\n ) : null}\n </Box>\n\n {infoTable && promptState !== PromptState.Submitted ? (\n <Box marginLeft={7} marginTop={1}>\n <InfoTable table={infoTable} />\n </Box>\n ) : null}\n\n {promptState === PromptState.Submitted ? (\n <Box>\n <Box marginRight={2}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Text color=\"cyan\">{answer!.label}</Text>\n </Box>\n ) : (\n <Box marginTop={1}>\n <SelectInput\n items={searchResults}\n enableShortcuts={false}\n emptyMessage=\"No results found.\"\n highlightedTerm={searchTerm}\n loading={promptState === PromptState.Loading}\n errorMessage={\n promptState === PromptState.Error\n ? 'There has been an error while searching. Please try again later.'\n : undefined\n }\n hasMorePages={hasMorePages}\n morePagesMessage=\"Find what you're looking for by typing its name.\"\n ref={inputRef}\n limit={limit}\n onSubmit={submitAnswer}\n />\n </Box>\n )}\n </Box>\n )\n}\n\nexport {AutocompletePrompt}\n"]}
|
|
1
|
+
{"version":3,"file":"AutocompletePrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/AutocompletePrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTableProps} from './Prompts/InfoTable.js'\nimport {TextInput} from './TextInput.js'\nimport {InfoMessageProps} from './Prompts/InfoMessage.js'\nimport {GitDiffProps} from './Prompts/GitDiff.js'\nimport {Message, PromptLayout} from './Prompts/PromptLayout.js'\nimport {debounce} from '../../../../public/common/function.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\nimport React, {ReactElement, useCallback, useRef, useState} from 'react'\nimport {Box, useApp} from 'ink'\n\nexport interface SearchResults<T> {\n data: SelectItem<T>[]\n meta?: {\n hasNextPage: boolean\n }\n}\n\nexport interface AutocompletePromptProps<T> {\n message: Message\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n hasMorePages?: boolean\n search: (term: string) => Promise<SearchResults<T>>\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n gitDiff?: GitDiffProps['gitDiff']\n}\n\nconst MIN_NUMBER_OF_ITEMS_FOR_SEARCH = 5\n\n// eslint-disable-next-line react/function-component-definition\nfunction AutocompletePrompt<T>({\n message,\n choices,\n infoTable,\n onSubmit,\n search,\n hasMorePages: initialHasMorePages = false,\n abortSignal,\n infoMessage,\n gitDiff,\n}: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null {\n const {exit: unmountInk} = useApp()\n const [searchTerm, setSearchTerm] = useState('')\n const [searchResults, setSearchResults] = useState<SelectItem<T>[]>(choices)\n const canSearch = choices.length > MIN_NUMBER_OF_ITEMS_FOR_SEARCH\n const [hasMorePages, setHasMorePages] = useState(initialHasMorePages)\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<SelectItem<T> | undefined>({\n initialAnswer: undefined,\n })\n\n const paginatedSearch = useCallback(\n async (term: string) => {\n const results = await search(term)\n return results\n },\n [search],\n )\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n if (promptState === PromptState.Idle) {\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n setSearchTerm('')\n unmountInk()\n onSubmit(answer.value)\n }\n },\n [promptState, setAnswer, setPromptState, unmountInk, onSubmit],\n )\n\n const setLoadingWhenSlow = useRef<NodeJS.Timeout>()\n\n // we want to set it each time so that searchTermRef always tracks searchTerm,\n // this is NOT the same as writing useRef(searchTerm)\n const searchTermRef = useRef('')\n searchTermRef.current = searchTerm\n\n // disable exhaustive-deps because we want to memoize the debounce function itself\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const debounceSearch = useCallback(\n debounce((term: string) => {\n setLoadingWhenSlow.current = setTimeout(() => {\n setPromptState(PromptState.Loading)\n }, 100)\n paginatedSearch(term)\n .then((result) => {\n // while we were waiting for the promise to resolve, the user\n // has emptied the search term, so we want to show the default\n // choices instead\n if (searchTermRef.current.length === 0) {\n setSearchResults(choices)\n setHasMorePages(initialHasMorePages)\n } else {\n setSearchResults(result.data)\n setHasMorePages(result.meta?.hasNextPage ?? false)\n }\n\n setPromptState(PromptState.Idle)\n })\n .catch(() => {\n setPromptState(PromptState.Error)\n })\n .finally(() => {\n clearTimeout(setLoadingWhenSlow.current)\n })\n }, 300),\n [initialHasMorePages, choices, paginatedSearch, searchResults],\n )\n\n return (\n <PromptLayout\n message={message}\n state={promptState}\n infoTable={infoTable}\n infoMessage={infoMessage}\n gitDiff={gitDiff}\n abortSignal={abortSignal}\n header={\n promptState !== PromptState.Submitted && canSearch ? (\n <Box marginLeft={3}>\n <TextInput\n value={searchTerm}\n onChange={(term) => {\n setSearchTerm(term)\n\n if (term.length > 0) {\n debounceSearch(term)\n } else {\n debounceSearch.cancel()\n setPromptState(PromptState.Idle)\n setSearchResults(choices)\n }\n }}\n placeholder=\"Type to search...\"\n />\n </Box>\n ) : null\n }\n submittedAnswerLabel={answer?.label}\n input={\n <SelectInput\n items={searchResults}\n initialItems={choices}\n enableShortcuts={false}\n emptyMessage=\"No results found.\"\n highlightedTerm={searchTerm}\n loading={promptState === PromptState.Loading}\n errorMessage={\n promptState === PromptState.Error\n ? 'There has been an error while searching. Please try again later.'\n : undefined\n }\n hasMorePages={hasMorePages}\n morePagesMessage=\"Find what you're looking for by typing its name.\"\n onSubmit={submitAnswer}\n />\n }\n />\n )\n}\n\nexport {AutocompletePrompt}\n"]}
|