Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .changeset/11659-console-record-ux.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Console, record page and Studio copy from the 2026-10-05 cloud acceptance run (objectui#11659).

**The cloud home's primary button reads "Open workspace" (zh 「进入工作区」), not "Open Production".** A new customer has exactly one environment, and "production" is control-plane vocabulary. The `cloud:onboarding-next` widget's ready-state button now resolves `cloudOnboarding.openWorkspace`, which replaces `cloudOnboarding.openProduction` in all ten language packs, and the hint under it (`cloudOnboarding.hintReady`) says "workspace" instead of "production environment". The button still navigates to the page's `openProductionUrl`; the page-metadata contract is unchanged.
**The cloud home's primary button reads "Open workspace" (zh 「进入工作区」), not "Open Production".** A new customer has exactly one environment, and "production" is control-plane vocabulary. The `cloud:onboarding-next` widget's ready-state button now resolves `cloudOnboarding.openWorkspace`, which replaces `cloudOnboarding.openProduction` in all ten language packs, and the hint under it (`cloudOnboarding.hintReady`) says "workspace" instead of "production environment". The button still navigates to the page's `openProductionUrl`; the page-metadata contract is unchanged. The same release then retires the `cloud:onboarding-next` widget and every `cloudOnboarding.*` key (objectui#12954), so neither the button nor those keys ship.

**The create-workspace dialog asks for the name only.** `CreateWorkspaceDialog` no longer shows the "URL slug" field: the customer never sees the slug take effect at this step. The slug is still generated from the name, by the same rule as before, and sent with the create call; the owner can change it later in organization settings. Because the slug is no longer the user's to fix in the dialog, a slug collision (`ORGANIZATION_ALREADY_EXISTS` or `ORGANIZATION_SLUG_ALREADY_TAKEN`) is retried with a short random suffix, up to three attempts in all; any other refusal is shown as before. The `workspace.slugLabel` and `workspace.slugHint` pack keys are left in place, now unread.

Expand Down
2 changes: 1 addition & 1 deletion .changeset/11930-workspace-timezone-notice.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ New SDUI widget `cloud:workspace-timezone-notice`: one line on the Cloud welcome

**What changed, in observable terms.**

- A page places the node with no props: `{ "type": "cloud:workspace-timezone-notice" }`. The widget reads the summary through the hook the environment list and `cloud:plan-status` already use, and when the summary carries `workspaceTimezoneSeed` it renders one muted line naming that zone, verbatim. In English: "The workspace timezone was set to Asia/Shanghai from your browser when the workspace was created. You can change it in Settings → Localization."
- A page places the node with no props: `{ "type": "cloud:workspace-timezone-notice" }`. The widget reads the summary through the hook the environment list already uses, and when the summary carries `workspaceTimezoneSeed` it renders one muted line naming that zone, verbatim. In English: "The environment timezone was set to Asia/Shanghai from your browser when the environment was created. You can change it in Settings → Localization."
- It renders nothing when the summary carries no seed (workspaces created before the seed existed, and control planes that do not send it yet), while the summary loads, when the request fails or rejects, and when the body is not the `{ success, data }` envelope. A failed request does not throw.
- The line is text only: no link and no dismissal state.
- The node's `className` and `responsiveStyles` reach the line.
Expand Down
19 changes: 19 additions & 0 deletions .changeset/12954-retire-cloud-onboarding-plan-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'@object-ui/app-shell': minor
'@object-ui/types': minor
'@object-ui/i18n': minor
'@object-ui/cli': minor
---

Two Cloud SDUI widgets are retired: `cloud:onboarding-next`, the Welcome page's next-step block, and `cloud:plan-status`, the pricing page's current-plan marker (objectui#12954). The Cloud control plane was their one consumer, and objectstack-ai/cloud#3010 replaced both: the home's next step is declared `element:button` nodes over `GET /api/v1/cloud/home`, and the pricing page marks the current plan with a `visibleWhen` on the same summary. At retirement, hotcrm `main` (`3b05ae7`) and objectstack `main` (`0b44840dfd`) registered and authored neither type. They are retired at once, with no deprecation alias. This is breaking for a page or host that still names one of them; it is marked `minor` under this repository's version policy.

- **SDUI widget `cloud:onboarding-next`**, also registered as `app-shell:cloud:onboarding-next`. FROM: `@object-ui/app-shell` registered both keys. TO: neither is registered. A page that still names one draws the unknown-component panel, and `objectui check` no longer counts either key among the known component types.
- **SDUI widget `cloud:plan-status`**. FROM: `@object-ui/app-shell` registered it. TO: not registered, with the same two consequences.
- **Schema `CloudPlanStatusSchema`** in `@object-ui/types`: the TypeScript interface from the package entry, and the zod arm from `@object-ui/types/zod`, which was also a member of `AnyComponentSchema`. FROM: exported, and a `cloud:plan-status` node validated against the arm. TO: there is no such export, so importing it fails to compile. `AnyComponentSchema` keeps a refusal arm for the literal, which is not exported, so `objectui validate` refuses a `cloud:plan-status` node BY NAME at `type`, and the message names the remedy: a `visibleWhen` on the page's summary. `CloudWorkspaceTimezoneNoticeSchema` stays.
- **Locale keys `cloudOnboarding.*`** (`hintCreate`, `hintReady`, `createEnvironment`, `openWorkspace`, `manageEnvironments`) **and `cloudPlanStatus.current`** leave all ten built-in packs of `@object-ui/i18n`.

The two widget modules also leave the `sideEffects` array of `@object-ui/app-shell`. `useEnvironmentEntitlements` stays: the environment list and `cloud:workspace-timezone-notice` still read it.

Fix for a page that still names either widget: compose it from generic blocks, as objectstack-ai/cloud#3010 did — declared `element:button` nodes over the home summary in place of `cloud:onboarding-next`, and a `visibleWhen` on the same summary in place of `cloud:plan-status`.

Clause-②: no (narrowing)
4 changes: 0 additions & 4 deletions packages/app-shell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
"./dist/console/cloud-connection/CloudConnectionPanel.js",
"./dist/console/connect/ConnectAgentWidget.js",
"./dist/console/diagnostics/CloudAiModelStatus.js",
"./dist/console/home/CloudOnboardingNext.js",
"./dist/console/home/CloudPlanStatus.js",
"./dist/console/home/CloudWorkspaceTimezoneNotice.js",
"./dist/services/builtinComponents.js",
"./dist/views/global-notifications-renderer.js",
Expand All @@ -29,8 +27,6 @@
"./src/console/cloud-connection/CloudConnectionPanel.tsx",
"./src/console/connect/ConnectAgentWidget.tsx",
"./src/console/diagnostics/CloudAiModelStatus.tsx",
"./src/console/home/CloudOnboardingNext.tsx",
"./src/console/home/CloudPlanStatus.tsx",
"./src/console/home/CloudWorkspaceTimezoneNotice.tsx",
"./src/services/builtinComponents.tsx",
"./src/views/global-notifications-renderer.tsx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ const stripComments = (src: string): string =>
* Every file that used to hand-write the param name, plus the two that consume
* it today. If a future file needs the name, it imports the constant — so this
* list is allowed to grow only with files that DON'T contain the literal.
* `CloudOnboardingNext.tsx`, the producer half of the retired convention, left
* the list when the widget itself retired (objectui#12954).
*/
const SOURCES_THAT_MUST_NOT_SPELL_IT = [
'packages/app-shell/src/environment/EnvironmentListToolbar.tsx',
'packages/app-shell/src/console/home/CloudOnboardingNext.tsx',
'packages/app-shell/src/views/ObjectView.tsx',
'packages/app-shell/src/hooks/useNavRunAction.ts',
];
Expand All @@ -100,16 +101,6 @@ describe('the private `?runAction=` convention is gone from the source (#5216)',
expect(src).not.toContain('URLSearchParams');
expect(src).toContain('useNavRunAction');
});

it('the welcome CTA no longer concatenates its own deep link', () => {
const src = read('packages/app-shell/src/console/home/CloudOnboardingNext.tsx');

expect(src).toContain('navRunActionHref');
// The exact template that used to build it. Comments are stripped for the
// same reason as above: the comment there NAMES the retired string while
// explaining what replaced it, which is documentation, not a producer.
expect(stripComments(src)).not.toContain('?runAction=create_environment');
});
});

describe('the param name now has exactly one definition (#5216)', () => {
Expand Down
15 changes: 0 additions & 15 deletions packages/app-shell/src/__tests__/product-specific.allowlist.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,13 @@
"registrations": [
"app-shell:cloud-connection:panel",
"app-shell:cloud:ai-model-status",
"app-shell:cloud:onboarding-next",
"cloud-connection:panel",
"cloud:ai-model-status",
"cloud:onboarding-next",
"cloud:plan-status",
"cloud:workspace-timezone-notice"
],
"files": [
"packages/app-shell/src/console/cloud-connection/CloudConnectionPanel.tsx",
"packages/app-shell/src/console/diagnostics/CloudAiModelStatus.tsx",
"packages/app-shell/src/console/home/CloudOnboardingNext.tsx",
"packages/app-shell/src/console/home/CloudPlanStatus.tsx",
"packages/app-shell/src/console/home/CloudWorkspaceTimezoneNotice.tsx",
"packages/app-shell/src/console/organizations/CreateWorkspaceDialog.tsx",
"packages/app-shell/src/console/organizations/OrganizationsLayout.tsx",
Expand Down Expand Up @@ -86,16 +81,6 @@
"waiting.polling",
"waiting.popupOpened"
],
"cloudOnboarding": [
"createEnvironment",
"hintCreate",
"hintReady",
"manageEnvironments",
"openWorkspace"
],
"cloudPlanStatus": [
"current"
],
"cloudWorkspaceTimezoneNotice": [
"seeded"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@ describe('product-page blocks are registered under product-neutral names (object
for (const input of config?.inputs ?? []) expect(input.description, `${type}.${input.name}`).toBeTruthy();
}
});

it('keeps `cloud:onboarding-next` registered (control)', async () => {
await import('../../home/CloudOnboardingNext');
expect(ComponentRegistry.get('app-shell:cloud:onboarding-next')).toBeTruthy();
});
});

describe('hero', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* panel never re-computes the model (a second compute source is exactly the
* drift trap the boot-convergence guard fixed). The component owns only the
* fetch + render; the endpoint path comes from page metadata `properties`, so
* the Cloud/Setup page owns its URL. Same pattern as `cloud:onboarding-next`.
* the Cloud/Setup page owns its URL.
*/

import { useEffect, useMemo, useState } from 'react';
Expand Down
Loading
Loading