feat(web): add Go campaign entries and route upgrades to Pricing #19168
ci.yml
on: pull_request
Resolve runner profiles
12s
Matrix: daemon_unit_tests
Matrix: playwright_critical
Matrix: playwright_visual
Matrix: ui_p0
Matrix: web_workspace_tests
Preflight
2m 2s
Workspace unit tests
51s
Windows tools-pack payload tests
0s
E2E Vitest
3m 20s
Runtime summary
4s
Annotations
3 errors, 3 warnings, and 9 notices
|
Web workspace tests (1/2)
Process completed with exit code 1.
|
|
tests/campaigns/deepseek-v4-flash.test.ts > DeepSeek V4 Flash campaign > reuses the modal shell for Go without showing the paid secondary action:
apps/web/tests/campaigns/deepseek-v4-flash.test.ts#L155
AssertionError: expected 'import { useEffect, useId, useState }β¦' to contain 'goCopy.cta'
- Expected
+ Received
- goCopy.cta
+ import { useEffect, useId, useState } from 'react';
+ import { createPortal } from 'react-dom';
+ import { Button, Dialog } from '@open-design/components';
+ import {
+ DEEPSEEK_V4_FLASH_CAMPAIGN as campaign,
+ formatDeepSeekV4FlashCampaignCountdown,
+ type DeepSeekV4FlashCampaignAudience,
+ } from '../campaigns/deepseek-v4-flash';
+ import { GO_PLAN_CAMPAIGN, GO_PLAN_PRICING_URL } from '../campaigns/go-plan';
+ import { useAnalytics } from '../analytics/provider';
+ import {
+ trackDeepSeekCampaignModalClick,
+ trackDeepSeekCampaignModalSurfaceView,
+ } from '../analytics/events';
+ import { useI18n } from '../i18n';
+ import { Icon } from './Icon';
+ import styles from './DeepSeekV4FlashCampaign.module.css';
+
+ interface Props {
+ /**
+ * paid = an active personal/team subscription; unpaid = no active
+ * subscription (including users who previously recharged their wallet).
+ */
+ audience: DeepSeekV4FlashCampaignAudience;
+ /**
+ * Whether the home view is the ACTIVE entry view. EntryShell keeps HomeView
+ * permanently mounted behind `display:none` while this dialog portals to
+ * `document.body`, so without this gate the campaign would escape the home
+ * view and interrupt projects/tasks/plugins/... routes. The requirement is
+ * explicit: the modal shows on #/home only.
+ */
+ active?: boolean;
+ /**
+ * Performs the REAL workbench switch for the paid η«ε³δ½Ώη¨ CTA (δΊ§εζζΏ
+ * D5): agent to `amr`, model to the campaign model. EntryShell provides the
+ * same onAgentChange/onAgentModelChange pair the InlineModelSwitcher
+ * persists through.
+ */
+ onUseCampaignModel?: (agentId: string, modelId: string) => void;
+ /**
+ * Telemetry opt-in (config.telemetry.metrics). Gates the AMR analytics
+ * mirror of the recorded entry AND the od_device_id on the plans URL β
+ * the same treatment the workbench badge and the model-switcher upgrade
+ * already apply to this campaign's other touchpoints.
+ */
+ metricsConsent?: boolean;
+ /** config.installationId β the preferred consent-gated AMR join key. */
+ installationId?: string | null;
+ }
+
+ function hasSeenCampaign(campaignId: string): boolean {
+ if (typeof window === 'undefined') return true;
+ try {
+ return window.localStorage.getItem(`open-design:campaign-seen:${campaignId}`) === '1';
+ } catch {
+ // Fail closed: when the store is unreadable (private mode, disabled
+ // localStorage) `markCampaignSeen` cannot persist either, so answering
+ // "unseen" would re-open the modal on every mount. The campaign promise
+ // is one appearance per window β suppress instead of spamming.
+ return true;
+ }
+ }
+
+ function markCampaignSeen(campaignId: string): void {
+ try {
+ window.localStorage.setItem(`open-design:campaign-seen:${campaignId}`, '1');
+ } catch {
+ // Campaign frequency control is advisory; storage failures must not block Home.
+ }
+ }
+
+ /**
+ * Visual confirmation of the switch `onUseCampaignModel` already performed:
+ * pulse the composer's model chip. Deliberately no `chip.click()` β the model
+ * is switched for real, so opening the picker would only ask the user to redo
+ * a choice that has already been made.
+ */
+ function highlightModelSwitcher(): void {
+ const chip = document.querySelector<HTMLButtonElement>(
+ '[data-testid="inline-model-switcher-chip"]',
+ );
+ if (!chip) return;
+ chip.setAttribute('data-campaign-highlight', 'true');
+ window.setTimeout(() => chip.removeAttribute('data-campaign-highlight'), 1_500);
+ }
+
+ export function DeepSeekV4FlashCampaign({
+ audience,
+ active = true,
+ onUseCampaignModel,
+ metricsConsent = false,
+ installationId = null,
+ }: Props) {
+ const { locale, t } = useI18n();
+ const isZh = locale === 'zh-CN' || locale === 'zh-TW';
+ const analytics = useAnalytics();
+ const [modalOpen, setMod
|
|
Validate workspace
Process completed with exit code 1.
|
|
Detect validation scopes
Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/upload-artifact@v4. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
|
|
E2E Vitest
merge_group changed-file resolution failed; falling back to the full plan: Error: merge_group compare result reached GitHub's 300-file ceiling
|
|
E2E Vitest
merge_group changed-file resolution failed; falling back to the full plan: Error: Command failed: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /tmp/scopes-test-IA8jL1/gh-stub.mjs api repos/nexu-io/open-design/compare/1111111111111111111111111111111111111111...2222222222222222222222222222222222222222
|
|
π Playwright Run Summary
19 passed (1.6m)
|
|
π Playwright Run Summary
4 passed (2.4m)
|
|
π Playwright Run Summary
18 passed (2.4m)
|
|
π Playwright Run Summary
25 passed (2.7m)
|
|
π Playwright Run Summary
29 passed (3.0m)
|
|
π Playwright Run Summary
14 passed (3.5m)
|
|
π Playwright Run Summary
4 passed (55.1s)
|
|
π Playwright Run Summary
23 passed (2.4m)
|
|
π Playwright Run Summary
79 passed (4.9m)
|
Artifacts
Produced during runtime
| Name | Size | Digest | |
|---|---|---|---|
|
handoff-report-visual-pr
|
438 Bytes |
sha256:8f6a26eb6b48f694be93a01df918f02228835ba2fac795f60df9ca9d8600ef4b
|
|
|
ui-p0-ci-32254375393-entry-settings
|
424 KB |
sha256:03cd67ecec469082f2740e26fcd13dc82e5a34b4c3154892b3276d58b44bd9d4
|
|
|
ui-p0-ci-32254375393-project-collab
|
330 KB |
sha256:11ad1bf02be7163a75a6f17ee86c2aa587b72dc694e16575718bac5c1ec07c2c
|
|
|
ui-p0-ci-32254375393-project-runtime
|
307 KB |
sha256:15e31d2736fa43ac2f8a3fbdf6d9dc8861a43217244c2866fee419d4ac11a0da
|
|
|
ui-p0-ci-32254375393-project-runtime-domain
|
363 KB |
sha256:eb510d27133b3caa0324940e50d480821deefdb295fe654273f632814a2d7274
|
|
|
ui-p0-ci-32254375393-project-workspace
|
373 KB |
sha256:7ad309bb305607e23d0c0cdbaca52070b16e15e5e6a837b4064f5a5eef59ef43
|
|
|
ui-p0-ci-32254375393-project-workspace-editor
|
361 KB |
sha256:40d0d1fa4d769773d8485a883087e0687bace5d0fc422cbbd96cfea0fd2f237f
|
|
|
ui-p0-ci-32254375393-workspace-restoration
|
402 KB |
sha256:08ebfff9d9018712a56604ca01fec133f97c180d48e29f04eec4911be25d223d
|
|
|
visual-pr-capture-7122-32254375393-entry-navigation
|
6.03 MB |
sha256:756743170a872c63f9e1b72e5821d4b1f175e9793c0b549597efe6beebb256b8
|
|
|
visual-pr-capture-7122-32254375393-settings-workspace
|
3.18 MB |
sha256:ba034bedc566c6ac79c5edaeb4a88742afc1425533207c24fd00f0428b97eb08
|
|