@shopify/cli-kit 3.47.5 → 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.
Files changed (138) hide show
  1. package/assets/cli-ruby/lib/project_types/extension/messages/messages.rb +18 -1
  2. package/assets/cli-ruby/lib/shopify_cli/constants.rb +1 -0
  3. package/assets/cli-ruby/lib/shopify_cli/environment.rb +7 -0
  4. package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +8 -2
  5. package/dist/private/node/ui/alert.js +3 -1
  6. package/dist/private/node/ui/alert.js.map +1 -1
  7. package/dist/private/node/ui/components/Alert.d.ts +1 -1
  8. package/dist/private/node/ui/components/Alert.js.map +1 -1
  9. package/dist/private/node/ui/components/AutocompletePrompt.d.ts +7 -2
  10. package/dist/private/node/ui/components/AutocompletePrompt.js +28 -91
  11. package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
  12. package/dist/private/node/ui/components/AutocompletePrompt.test.js +317 -257
  13. package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
  14. package/dist/private/node/ui/components/ConcurrentOutput.d.ts +1 -0
  15. package/dist/private/node/ui/components/ConcurrentOutput.js +59 -32
  16. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  17. package/dist/private/node/ui/components/ConcurrentOutput.test.js +62 -22
  18. package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
  19. package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +12 -0
  20. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js +77 -0
  21. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -0
  22. package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js +101 -0
  23. package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js.map +1 -0
  24. package/dist/private/node/ui/components/List.d.ts +1 -0
  25. package/dist/private/node/ui/components/List.js +2 -2
  26. package/dist/private/node/ui/components/List.js.map +1 -1
  27. package/dist/private/node/ui/components/{GitDiff.d.ts → Prompts/GitDiff.d.ts} +4 -2
  28. package/dist/private/node/ui/components/{GitDiff.js → Prompts/GitDiff.js} +3 -2
  29. package/dist/private/node/ui/components/Prompts/GitDiff.js.map +1 -0
  30. package/dist/private/node/ui/components/Prompts/GitDiff.test.d.ts +1 -0
  31. package/dist/private/node/ui/components/{GitDiff.test.js → Prompts/GitDiff.test.js} +50 -28
  32. package/dist/private/node/ui/components/Prompts/GitDiff.test.js.map +1 -0
  33. package/dist/private/node/ui/components/Prompts/InfoMessage.d.ts +14 -0
  34. package/dist/private/node/ui/components/Prompts/InfoMessage.js +11 -0
  35. package/dist/private/node/ui/components/Prompts/InfoMessage.js.map +1 -0
  36. package/dist/private/node/ui/components/Prompts/InfoMessage.test.d.ts +1 -0
  37. package/dist/private/node/ui/components/Prompts/InfoMessage.test.js +21 -0
  38. package/dist/private/node/ui/components/Prompts/InfoMessage.test.js.map +1 -0
  39. package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -0
  40. package/dist/private/node/ui/components/Prompts/InfoTable.js +11 -7
  41. package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
  42. package/dist/private/node/ui/components/Prompts/InfoTable.test.js +6 -4
  43. package/dist/private/node/ui/components/Prompts/InfoTable.test.js.map +1 -1
  44. package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +21 -0
  45. package/dist/private/node/ui/components/Prompts/PromptLayout.js +73 -0
  46. package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -0
  47. package/dist/private/node/ui/components/Prompts/PromptLayout.test.d.ts +1 -0
  48. package/dist/private/node/ui/components/Prompts/PromptLayout.test.js +129 -0
  49. package/dist/private/node/ui/components/Prompts/PromptLayout.test.js.map +1 -0
  50. package/dist/private/node/ui/components/Scrollbar.d.ts +10 -0
  51. package/dist/private/node/ui/components/Scrollbar.js +44 -0
  52. package/dist/private/node/ui/components/Scrollbar.js.map +1 -0
  53. package/dist/private/node/ui/components/Scrollbar.test.d.ts +1 -0
  54. package/dist/private/node/ui/components/Scrollbar.test.js +96 -0
  55. package/dist/private/node/ui/components/Scrollbar.test.js.map +1 -0
  56. package/dist/private/node/ui/components/SelectInput.d.ts +3 -6
  57. package/dist/private/node/ui/components/SelectInput.js +57 -41
  58. package/dist/private/node/ui/components/SelectInput.js.map +1 -1
  59. package/dist/private/node/ui/components/SelectInput.test.js +120 -192
  60. package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
  61. package/dist/private/node/ui/components/SelectPrompt.d.ts +7 -6
  62. package/dist/private/node/ui/components/SelectPrompt.js +11 -68
  63. package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
  64. package/dist/private/node/ui/components/SelectPrompt.test.js +135 -65
  65. package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
  66. package/dist/private/node/ui/components/Table/Row.js +2 -1
  67. package/dist/private/node/ui/components/Table/Row.js.map +1 -1
  68. package/dist/private/node/ui/components/Table/Table.js +2 -1
  69. package/dist/private/node/ui/components/Table/Table.js.map +1 -1
  70. package/dist/private/node/ui/components/Tasks.js +1 -8
  71. package/dist/private/node/ui/components/Tasks.js.map +1 -1
  72. package/dist/private/node/ui/components/TextInput.d.ts +1 -0
  73. package/dist/private/node/ui/components/TextInput.js +10 -4
  74. package/dist/private/node/ui/components/TextInput.js.map +1 -1
  75. package/dist/private/node/ui/components/TextInput.test.js +27 -18
  76. package/dist/private/node/ui/components/TextInput.test.js.map +1 -1
  77. package/dist/private/node/ui/components/TextPrompt.d.ts +2 -3
  78. package/dist/private/node/ui/components/TextPrompt.js +18 -16
  79. package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
  80. package/dist/private/node/ui/components/TextPrompt.test.js +25 -11
  81. package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
  82. package/dist/private/node/ui/hooks/use-prompt.d.ts +18 -0
  83. package/dist/private/node/ui/hooks/use-prompt.js +20 -0
  84. package/dist/private/node/ui/hooks/use-prompt.js.map +1 -0
  85. package/dist/private/node/ui/hooks/use-select-state.d.ts +4 -4
  86. package/dist/private/node/ui/hooks/use-select-state.js +9 -9
  87. package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
  88. package/dist/public/common/object.d.ts +16 -0
  89. package/dist/public/common/object.js +26 -0
  90. package/dist/public/common/object.js.map +1 -1
  91. package/dist/public/common/string.d.ts +16 -0
  92. package/dist/public/common/string.js +30 -0
  93. package/dist/public/common/string.js.map +1 -1
  94. package/dist/public/common/version.d.ts +1 -1
  95. package/dist/public/common/version.js +1 -1
  96. package/dist/public/common/version.js.map +1 -1
  97. package/dist/public/node/analytics.js +3 -1
  98. package/dist/public/node/analytics.js.map +1 -1
  99. package/dist/public/node/base-command.d.ts +1 -0
  100. package/dist/public/node/base-command.js +21 -1
  101. package/dist/public/node/base-command.js.map +1 -1
  102. package/dist/public/node/figures.d.ts +2 -0
  103. package/dist/public/node/figures.js +3 -0
  104. package/dist/public/node/figures.js.map +1 -0
  105. package/dist/public/node/metadata.d.ts +2 -1
  106. package/dist/public/node/metadata.js +5 -2
  107. package/dist/public/node/metadata.js.map +1 -1
  108. package/dist/public/node/monorail.d.ts +22 -1
  109. package/dist/public/node/monorail.js +1 -1
  110. package/dist/public/node/monorail.js.map +1 -1
  111. package/dist/public/node/output.d.ts +1 -1
  112. package/dist/public/node/output.js +1 -1
  113. package/dist/public/node/output.js.map +1 -1
  114. package/dist/public/node/ruby.d.ts +1 -0
  115. package/dist/public/node/ruby.js +1 -0
  116. package/dist/public/node/ruby.js.map +1 -1
  117. package/dist/public/node/system.js +2 -2
  118. package/dist/public/node/system.js.map +1 -1
  119. package/dist/public/node/themes/models/theme.d.ts +2 -1
  120. package/dist/public/node/themes/models/theme.js +2 -1
  121. package/dist/public/node/themes/models/theme.js.map +1 -1
  122. package/dist/public/node/themes/theme-urls.d.ts +1 -0
  123. package/dist/public/node/themes/theme-urls.js +4 -0
  124. package/dist/public/node/themes/theme-urls.js.map +1 -1
  125. package/dist/public/node/themes/themes-api.d.ts +9 -1
  126. package/dist/public/node/themes/themes-api.js +14 -3
  127. package/dist/public/node/themes/themes-api.js.map +1 -1
  128. package/dist/public/node/toml.d.ts +3 -2
  129. package/dist/public/node/toml.js +5 -2
  130. package/dist/public/node/toml.js.map +1 -1
  131. package/dist/public/node/ui.d.ts +82 -27
  132. package/dist/public/node/ui.js +97 -32
  133. package/dist/public/node/ui.js.map +1 -1
  134. package/dist/tsconfig.tsbuildinfo +1 -1
  135. package/package.json +14 -14
  136. package/dist/private/node/ui/components/GitDiff.js.map +0 -1
  137. package/dist/private/node/ui/components/GitDiff.test.js.map +0 -1
  138. /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
- {{green:%s}}
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.location)
162
+ parsed_uri = URI.parse(extension.preview_message)
163
163
  shopify_org_url = "#{parsed_uri.scheme}://#{parsed_uri.host}/9082/impersonate"
164
- ctx.message("serve.preview_message_1p", shopify_org_url, extension.location, theme.editor_url, address)
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;AACxF,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;CAChB,CAAA;AAED,MAAM,YAAY,GAA0C;IAC1D,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,WAAW;IACpB,OAAO,EAAE,UAAU;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 {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}\n\nconst typeToLogger: {[key in AlertProps['type']]: Logger} = {\n info: consoleLog,\n warning: consoleWarn,\n success: consoleLog,\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"]}
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, 'error' | 'external_error'>;
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, 'error' | '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
+ {"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: string;
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: initialChoices, infoTable, onSubmit, search, hasMorePages: initialHasMorePages, abortSignal, }: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null;
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 { TokenizedText } from './TokenizedText.js';
5
- import { messageWithPunctuation } from '../utilities.js';
3
+ import { PromptLayout } from './Prompts/PromptLayout.js';
6
4
  import { debounce } from '../../../../public/common/function.js';
7
- import useAbortSignal from '../hooks/use-abort-signal.js';
8
- import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
9
- import { Box, measureElement, Text, useApp, useStdout } from 'ink';
10
- import figures from 'figures';
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: initialChoices, infoTable, onSubmit, search, hasMorePages: initialHasMorePages = false, abortSignal, }) {
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(paginatedInitialChoices.slice(0, PAGE_SIZE));
29
- const { stdout } = useStdout();
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 [wrapperHeight, setWrapperHeight] = useState(0);
33
- const [selectInputHeight, setSelectInputHeight] = useState(0);
34
- const [limit, setLimit] = useState(searchResults.length);
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, stdout, wrapperHeight, onSubmit, unmountInk]);
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(paginatedInitialChoices);
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, paginatedInitialChoices, paginatedSearch]);
116
- return isAborted ? null : (React.createElement(Box, { flexDirection: "column", marginBottom: 1, ref: wrapperRef },
117
- React.createElement(Box, null,
118
- React.createElement(Box, { marginRight: 2 },
119
- React.createElement(Text, null, "?")),
120
- React.createElement(TokenizedText, { item: messageWithPunctuation(message) }),
121
- promptState !== PromptState.Submitted && canSearch ? (React.createElement(Box, { marginLeft: 3 },
122
- React.createElement(TextInput, { value: searchTerm, onChange: (term) => {
123
- setSearchTerm(term);
124
- if (term.length > 0) {
125
- debounceSearch(term);
126
- }
127
- else {
128
- debounceSearch.cancel();
129
- setPromptState(PromptState.Idle);
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"]}