Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .changeset/afraid-hairs-talk.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/render-tasks-to-stderr.md

This file was deleted.

4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a # v3
uses: github/codeql-action/init@4bdb89f48054571735e3792627da6195c57459e2 # v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
Expand Down Expand Up @@ -87,6 +87,6 @@ jobs:
exit 1

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a # v3
uses: github/codeql-action/analyze@4bdb89f48054571735e3792627da6195c57459e2 # v3
with:
category: "/language:${{matrix.language}}"
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Force snapshot changeset
run: "mv .changeset/force-snapshot-build.md.ignore .changeset/force-snapshot-build.md"
- name: Create snapshot version
uses: Shopify/snapit@0fec17dd6a0ae66f2672738dc8086f394218436c # registry-and-package-manager
uses: Shopify/snapit@ee98df3a4a2b221fc3f06d56b9a6b60996613102 # registry-and-package-manager
with:
comment_is_global: 'true'
comment_packages: '@shopify/cli'
Expand Down Expand Up @@ -99,7 +99,7 @@ jobs:
node-version: 24.12.0
- name: Create Release Pull Request
id: changesets
uses: changesets/action@6a0a831ff30acef54f2c6aa1cbbc1096b066edaf # v1
uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1
with:
version: pnpm changeset-manifests
title: Version Packages - ${{ github.ref_name }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/workflow-cleaner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Delete workflow runs
uses: Mattraks/delete-workflow-runs@b3018382ca039b53d238908238bd35d1fb14f8ee # v2
uses: Mattraks/delete-workflow-runs@bd2822c9d98065c9766fb1f4bbc32325c47de4fb # v2
with:
token: ${{ github.token }}
repository: ${{ github.repository }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,7 @@ import {unstyled} from '@shopify/cli-kit/node/output'
import {openURL} from '@shopify/cli-kit/node/system'
import {Writable} from 'stream'

vi.mock('@shopify/cli-kit/node/system', async () => {
const actual: any = await vi.importActual('@shopify/cli-kit/node/system')
return {
...actual,
openURL: vi.fn(),
terminalSupportsHyperlinks: mocks.terminalSupportsHyperlinks,
}
})
vi.mock('@shopify/cli-kit/node/system')
vi.mock('@shopify/cli-kit/node/context/local')
vi.mock('@shopify/cli-kit/node/tree-kill')

Expand All @@ -30,7 +23,6 @@ const mocks = vi.hoisted(() => {
useStdin: vi.fn(() => {
return {isRawModeSupported: true}
}),
terminalSupportsHyperlinks: vi.fn(() => false),
}
})

Expand All @@ -56,8 +48,6 @@ const onAbort = vi.fn()

describe('DevSessionUI', () => {
beforeEach(() => {
mocks.terminalSupportsHyperlinks.mockReturnValue(false)
mocks.useStdin.mockReturnValue({isRawModeSupported: true})
devSessionStatusManager = new DevSessionStatusManager()
devSessionStatusManager.reset()
devSessionStatusManager.updateStatus(initialStatus)
Expand Down Expand Up @@ -554,62 +544,6 @@ describe('DevSessionUI', () => {
renderInstance.unmount()
})

test('hides URL list when terminal supports hyperlinks', async () => {
// Given
mocks.terminalSupportsHyperlinks.mockReturnValue(true)

const renderInstance = render(
<DevSessionUI
processes={[]}
abortController={new AbortController()}
devSessionStatusManager={devSessionStatusManager}
shopFqdn="mystore.myshopify.com"
onAbort={onAbort}
/>,
)

await waitForInputsToBeReady()

// Then - shortcuts with label text should be present but URL list should be hidden
const output = unstyled(renderInstance.lastFrame()!)
expect(output).toContain('(p) Open app preview')
expect(output).toContain('(c) Open Dev Console for extension previews')
expect(output).toContain('(g) Open GraphiQL (Admin API)')
expect(output).not.toContain('Preview URL:')
expect(output).not.toContain('Dev Console URL:')
expect(output).not.toContain('GraphiQL URL:')

renderInstance.unmount()
})

test('shows URL list when terminal does not support hyperlinks', async () => {
// Given
mocks.terminalSupportsHyperlinks.mockReturnValue(false)

const renderInstance = render(
<DevSessionUI
processes={[]}
abortController={new AbortController()}
devSessionStatusManager={devSessionStatusManager}
shopFqdn="mystore.myshopify.com"
onAbort={onAbort}
/>,
)

await waitForInputsToBeReady()

// Then - both shortcuts with label text and URL list should be present
const output = unstyled(renderInstance.lastFrame()!)
expect(output).toContain('(p) Open app preview')
expect(output).toContain('(c) Open Dev Console for extension previews')
expect(output).toContain('(g) Open GraphiQL (Admin API)')
expect(output).toContain('Preview URL: https://shopify.com')
expect(output).toContain('Dev Console URL: https://mystore.myshopify.com/admin?dev-console=show')
expect(output).toContain('GraphiQL URL: https://graphiql.shopify.com')

renderInstance.unmount()
})

test('shows non-interactive fallback when raw mode is not supported', async () => {
// Given - mock useStdin to return false for isRawModeSupported
mocks.useStdin.mockReturnValue({isRawModeSupported: false})
Expand All @@ -636,5 +570,8 @@ describe('DevSessionUI', () => {
expect(output).toContain('GraphiQL URL: https://graphiql.shopify.com')

renderInstance.unmount()

// Restore original mock for other tests
mocks.useStdin.mockReturnValue({isRawModeSupported: true})
})
})
144 changes: 69 additions & 75 deletions packages/app/src/cli/services/dev/ui/components/DevSessionUI.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Spinner} from './Spinner.js'
import {TabPanel, Tab, TabShortcut} from './TabPanel.js'
import {TabPanel, Tab} from './TabPanel.js'
import metadata from '../../../../metadata.js'
import {
DevSessionStatus,
Expand All @@ -15,19 +15,13 @@ import React, {FunctionComponent, useEffect, useMemo, useState} from 'react'
import {AbortController, AbortSignal} from '@shopify/cli-kit/node/abort'
import {Box, Text, useInput, useStdin} from '@shopify/cli-kit/node/ink'
import {handleCtrlC} from '@shopify/cli-kit/node/ui'
import {openURL, terminalSupportsHyperlinks} from '@shopify/cli-kit/node/system'
import {openURL} from '@shopify/cli-kit/node/system'
import figures from '@shopify/cli-kit/node/figures'
import {isUnitTest} from '@shopify/cli-kit/node/context/local'
import {treeKill} from '@shopify/cli-kit/node/tree-kill'
import {postRunHookHasCompleted} from '@shopify/cli-kit/node/hooks/postrun'
import {Writable} from 'stream'

interface DevStatusShortcut extends TabShortcut {
shortcutLabel: string
linkLabel: string
url?: string
}

interface DevSesionUIProps {
processes: OutputProcess[]
abortController: AbortController
Expand Down Expand Up @@ -125,94 +119,94 @@ const DevSessionUI: FunctionComponent<DevSesionUIProps> = ({
}
}

const devStatusShortcuts: DevStatusShortcut[] = [
{
key: 'p',
shortcutLabel: 'Open app preview',
linkLabel: 'Preview',
url: status.previewURL,
condition: () => Boolean(status.isReady && status.previewURL),
action: async () => {
await metadata.addPublicMetadata(() => ({
cmd_dev_preview_url_opened: true,
}))
if (status.previewURL) {
await openURL(status.previewURL)
}
},
},
{
key: 'c',
shortcutLabel: 'Open Dev Console for extension previews',
linkLabel: 'Dev Console',
url: buildDevConsoleURL(shopFqdn),
condition: () => Boolean(status.isReady && status.appEmbedded === false && status.hasExtensions),
action: async () => {
await metadata.addPublicMetadata(() => ({
cmd_dev_preview_url_opened: true,
}))
await openURL(buildDevConsoleURL(shopFqdn))
},
},
{
key: 'g',
shortcutLabel: 'Open GraphiQL (Admin API)',
linkLabel: 'GraphiQL',
url: status.graphiqlURL,
condition: () => Boolean(status.isReady && status.graphiqlURL),
action: async () => {
await metadata.addPublicMetadata(() => ({
cmd_dev_graphiql_opened: true,
}))
if (status.graphiqlURL) {
await openURL(status.graphiqlURL)
}
},
},
]

const activeShortcuts = devStatusShortcuts.filter((shortcut) => shortcut.condition?.() ?? true)

const tabs: {[key: string]: Tab} = {
// eslint-disable-next-line id-length
d: {
label: 'Dev status',
shortcuts: devStatusShortcuts,
shortcuts: [
{
key: 'p',
condition: () => Boolean(status.previewURL && status.isReady),
action: async () => {
await metadata.addPublicMetadata(() => ({
cmd_dev_preview_url_opened: true,
}))
if (status.previewURL) {
await openURL(status.previewURL)
}
},
},
{
key: 'g',
condition: () => Boolean(status.graphiqlURL && status.isReady),
action: async () => {
await metadata.addPublicMetadata(() => ({
cmd_dev_graphiql_opened: true,
}))
if (status.graphiqlURL) {
await openURL(status.graphiqlURL)
}
},
},
{
key: 'c',
condition: () => Boolean(status.isReady && status.appEmbedded === false && status.hasExtensions),
action: async () => {
await metadata.addPublicMetadata(() => ({
cmd_dev_preview_url_opened: true,
}))
await openURL(buildDevConsoleURL(shopFqdn))
},
},
],
content: (
<>
{status.statusMessage && (
<Text>
{getStatusIndicator(status.statusMessage.type)} {status.statusMessage.message}
</Text>
)}
{canUseShortcuts && activeShortcuts.length > 0 && (
{canUseShortcuts && (
<Box marginTop={1} flexDirection="column">
{activeShortcuts.map((shortcut) => (
<Text key={shortcut.key}>
{figures.pointerSmall} <Text bold>({shortcut.key})</Text>{' '}
{terminalSupportsHyperlinks() && shortcut.url ? (
<Link url={shortcut.url} label={shortcut.shortcutLabel} />
) : (
shortcut.shortcutLabel
)}
{status.isReady ? (
<Text>
{figures.pointerSmall} <Text bold>(p)</Text> Open app preview
</Text>
) : null}
{status.isReady && !status.appEmbedded && status.hasExtensions ? (
<Text>
{figures.pointerSmall} <Text bold>(c)</Text> Open Dev Console for extension previews
</Text>
) : null}
{status.graphiqlURL && status.isReady ? (
<Text>
{figures.pointerSmall} <Text bold>(g)</Text> Open GraphiQL (Admin API)
</Text>
))}
) : null}
</Box>
)}
<Box marginTop={canUseShortcuts ? 1 : 0} flexDirection="column">
{isShuttingDownMessage ? (
<Text>{isShuttingDownMessage}</Text>
) : (
<>
{status.isReady && !(canUseShortcuts && terminalSupportsHyperlinks()) && (
{status.isReady && (
<>
{activeShortcuts
.filter((shortcut) => shortcut.url)
.map((shortcut) => (
<Text key={shortcut.key}>
{shortcut.linkLabel} URL: <Link url={shortcut.url!} />
</Text>
))}
{status.previewURL ? (
<Text>
Preview URL: <Link url={status.previewURL} />
</Text>
) : null}
{status.appEmbedded === false && status.hasExtensions ? (
<Text>
Dev Console URL: <Link url={buildDevConsoleURL(shopFqdn)} />
</Text>
) : null}
{status.graphiqlURL ? (
<Text>
GraphiQL URL: <Link url={status.graphiqlURL} />
</Text>
) : null}
</>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface Tab {
action?: () => Promise<void>
}

export interface TabShortcut {
interface TabShortcut {
key: string
condition?: () => boolean
action: () => Promise<void>
Expand Down
Loading
Loading