diff --git a/packages/cli-kit/package.json b/packages/cli-kit/package.json index dfa0fa9d20b..345616db570 100644 --- a/packages/cli-kit/package.json +++ b/packages/cli-kit/package.json @@ -107,8 +107,6 @@ "@graphql-typed-document-node/core": "3.2.0", "@iarna/toml": "2.2.5", "@oclif/core": "4.8.3", - "@shopify/polaris": "12.27.0", - "@shopify/polaris-icons": "8.11.1", "@shopify/toml-patch": "0.3.0", "@opentelemetry/api": "1.9.1", "@opentelemetry/core": "2.8.0", @@ -155,7 +153,6 @@ "pathe": "1.1.2", "react": "19.2.4", "semver": "7.8.4", - "react-dom": "19.2.4", "stacktracey": "2.2.0", "strip-ansi": "7.2.0", "supports-hyperlinks": "3.2.0", @@ -169,7 +166,6 @@ "@types/gradient-string": "^1.1.2", "@types/lodash": "4.17.24", "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", "@types/semver": "^7.5.2", "@types/which": "3.0.4", "@vitest/coverage-istanbul": "^3.2.7", diff --git a/packages/cli-kit/src/public/node/graphiql/templates/graphiql.ts b/packages/cli-kit/src/public/node/graphiql/templates/graphiql.ts new file mode 100644 index 00000000000..ce1bf94a7ca --- /dev/null +++ b/packages/cli-kit/src/public/node/graphiql/templates/graphiql.ts @@ -0,0 +1,392 @@ +import {platformAndArch} from '../../os.js' +import {MUTATIONS_BLOCKED_MESSAGE} from '../server.js' + +const controlKey = platformAndArch().platform === 'darwin' ? 'MAC_COMMAND_KEY' : 'Ctrl' + +const graphiqlIntroMessage = ` +# Welcome to GraphiQL for the Shopify Admin API! If you've used +# GraphiQL before, you can jump to the next tab. +# +# GraphiQL is an in-browser tool for writing, validating, and +# testing GraphQL queries. +# +# Type queries into this side of the screen, and you will see intelligent +# typeaheads aware of the current GraphQL type schema and live syntax and +# validation errors highlighted within the text. +# +# GraphQL queries typically start with a "{" character. Lines that start +# with a # are ignored. +# +# Keyboard shortcuts: +# +# Prettify query: Shift-${controlKey}-P (or press the prettify button) +# +# Merge fragments: Shift-${controlKey}-M (or press the merge button) +# +# Run Query: ${controlKey}-Enter (or press the play button) +# +# Auto Complete: ${controlKey}-Space (or just start typing) +# +` + +export const defaultQuery = `query shopInfo { + shop { + name + url + myshopifyDomain + plan { + displayName + partnerDevelopment + shopifyPlus + } + } +} +`.replace(/\n/g, '\\n') + +interface GraphiQLTemplateOptions { + apiVersion: string + apiVersions: string[] + appName?: string + appUrl?: string + key: string + storeFqdn: string + protectMutations?: boolean +} + +// Escapes a value the same way react-dom's renderToStaticMarkup escaped it when +// the markup below was produced by rendering Polaris components. +function escapeHtml(value: string): string { + return value + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>') +} + +// The HTML chunks below are the exact static markup that rendering the previous +// Polaris/React components with renderToStaticMarkup produced, with the dynamic +// values interpolated where the components received props. +const topBarOpenHtml = `
` + +function statusBadgesHtml(unauthorizedLabel: string): string { + return `
Status: Running
Status: ${escapeHtml(unauthorizedLabel)}
Status: Disconnected
` +} + +function versionSelectHtml(apiVersions: string[], apiVersion: string): string { + const options = apiVersions + .map( + (version) => + ``, + ) + .join('') + return `
API version:
` +} + +function linkPillHtml(url: string, label: string): string { + return `${escapeHtml(label)}` +} + +interface LinkPillOptions { + storeFqdn: string + appName?: string + appUrl?: string +} + +function linkPillsHtml({storeFqdn, appName, appUrl}: LinkPillOptions): string { + const appPill = + appName && appUrl ? `App: ${linkPillHtml(appUrl, appName)}` : '' + return `` +} + +const serverStoppedBannerHtml = `` + +interface TopBarOptions extends LinkPillOptions { + apiVersion: string + apiVersions: string[] + unauthorizedLabel: string + scopesNote: string +} + +function topBarHtml({ + apiVersion, + apiVersions, + storeFqdn, + appName, + appUrl, + unauthorizedLabel, + scopesNote, +}: TopBarOptions): string { + return `${topBarOpenHtml}${statusBadgesHtml(unauthorizedLabel)}${versionSelectHtml( + apiVersions, + apiVersion, + )}${linkPillsHtml({ + storeFqdn, + appName, + appUrl, + })}
${escapeHtml( + scopesNote, + )}
${serverStoppedBannerHtml}
` +} + +/** + * Returns the HTML for the GraphiQL page, ready to be rendered as a Liquid template. + * + * @param options - The dynamic values to interpolate into the page. + * @returns The HTML for the GraphiQL page. + */ +export function graphiqlTemplate(options: GraphiQLTemplateOptions): string { + const {apiVersion, apiVersions, appName, appUrl, key, storeFqdn, protectMutations = false} = options + const hasAppContext = Boolean(appName && appUrl) + const unauthorizedLabel = hasAppContext ? 'App uninstalled' : 'Auth invalid' + return ` + + + GraphiQL + + + + + + + + + +
+ ${topBarHtml({ + apiVersion, + apiVersions, + storeFqdn, + appName, + appUrl, + unauthorizedLabel, + scopesNote: scopesNoteText({hasAppContext, protectMutations}), + })} +
Loading...
+
+ + + + +` +} + +function scopesNoteText({ + hasAppContext, + protectMutations, +}: { + hasAppContext: boolean + protectMutations: boolean +}): string { + if (protectMutations) { + return MUTATIONS_BLOCKED_MESSAGE + } + if (hasAppContext) { + return "GraphiQL runs on the same access scopes you've defined in the TOML file for your app." + } + return 'GraphiQL runs with the access scopes granted to the stored app authentication for this store.' +} diff --git a/packages/cli-kit/src/public/node/graphiql/templates/graphiql.tsx b/packages/cli-kit/src/public/node/graphiql/templates/graphiql.tsx deleted file mode 100644 index 36ee7cbedb4..00000000000 --- a/packages/cli-kit/src/public/node/graphiql/templates/graphiql.tsx +++ /dev/null @@ -1,398 +0,0 @@ -import {platformAndArch} from '../../os.js' -import {MUTATIONS_BLOCKED_MESSAGE} from '../server.js' -import React from 'react' -import {renderToStaticMarkup} from 'react-dom/server' -import {AppProvider, Badge, Banner, BlockStack, Box, Grid, InlineStack, Link, Select, Text} from '@shopify/polaris' -import {AlertCircleIcon, DisabledIcon, LinkIcon} from '@shopify/polaris-icons' - -const controlKey = platformAndArch().platform === 'darwin' ? 'MAC_COMMAND_KEY' : 'Ctrl' - -const graphiqlIntroMessage = ` -# Welcome to GraphiQL for the Shopify Admin API! If you've used -# GraphiQL before, you can jump to the next tab. -# -# GraphiQL is an in-browser tool for writing, validating, and -# testing GraphQL queries. -# -# Type queries into this side of the screen, and you will see intelligent -# typeaheads aware of the current GraphQL type schema and live syntax and -# validation errors highlighted within the text. -# -# GraphQL queries typically start with a "{" character. Lines that start -# with a # are ignored. -# -# Keyboard shortcuts: -# -# Prettify query: Shift-${controlKey}-P (or press the prettify button) -# -# Merge fragments: Shift-${controlKey}-M (or press the merge button) -# -# Run Query: ${controlKey}-Enter (or press the play button) -# -# Auto Complete: ${controlKey}-Space (or just start typing) -# -` - -export const defaultQuery = `query shopInfo { - shop { - name - url - myshopifyDomain - plan { - displayName - partnerDevelopment - shopifyPlus - } - } -} -`.replace(/\n/g, '\\n') - -interface GraphiQLTemplateOptions { - apiVersion: string - apiVersions: string[] - appName?: string - appUrl?: string - key: string - storeFqdn: string - protectMutations?: boolean -} - -export function graphiqlTemplate({ - apiVersion, - apiVersions, - appName, - appUrl, - key, - storeFqdn, - protectMutations = false, -}: GraphiQLTemplateOptions): string { - const hasAppContext = Boolean(appName && appUrl) - const unauthorizedLabel = hasAppContext ? 'App uninstalled' : 'Auth invalid' - return ` - - - GraphiQL - - - - - - - - - -
- ${renderToStaticMarkup( - -
- - - - - -
-
- Status: - - Running - -
-
- Status: - - {unauthorizedLabel} - -
-
- Status: - - Disconnected - -
-
-
- API version: -