6a1b28bc12
## What & why A single, consistent **workspace-creation step** for both multi-workspace and single-workspace self-host — collecting **name + logo** (and the **subdomain** in multi-workspace) — which **removes the duplicate name/logo prompt** that previously reappeared on the workspace subdomain (reported after #21641). ## Changes **One creation form for both modes** - With 0 workspaces, both multi-workspace and single-workspace route to the shared `SignInUpWorkspaceCreationForm`; `SignInUp` renders it for the `WorkspaceCreation` step regardless of domain/scope. - The subdomain field shows only in multi-workspace; single-workspace keeps its fixed address. **Logo on the creation step** - New scoped `uploadNewWorkspaceLogo(workspaceId, file)` mutation: the creator sets a logo on their just-created `PENDING_CREATION` workspace via the workspace-agnostic token (membership enforced — only the creator is a member at that point), reusing `uploadWorkspacePicture`. Upload size is capped via `settings.storage.maxFileSize` (also applied to the existing logo / profile-picture uploads). - The picked file is held locally (object-URL preview, revoked on unmount) and uploaded right after creation (non-fatal on failure). **Onboarding step → pure activation loader** - The old "Create your workspace" form (name + logo) is removed. The onboarding step now activates the pending workspace on mount and shows the loader, with a **Retry** action on failure. ## Testing - typecheck (front + server) ✅; oxlint + oxfmt clean on changed files ✅ - Unit tests: `auth.resolver.spec`, `useWorkspaceSubdomainField`, `SignInUpWorkspaceCreationForm` (multi + single-workspace), `useAuth` ✅ - Metadata GraphQL + `twenty-client-sdk` schema regenerated. Follow-up to #21641. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Xw37hR5seiCyWnppG9z4op --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
import { t } from '@lingui/core/macro';
|
|
import { AppBasePath, AppPath, SettingsPath } from 'twenty-shared/types';
|
|
|
|
enum SettingsPathPrefixes {
|
|
Accounts = `${AppBasePath.Settings}/${SettingsPath.Accounts}`,
|
|
Experience = `${AppBasePath.Settings}/${SettingsPath.Experience}`,
|
|
Profile = `${AppBasePath.Settings}/${SettingsPath.ProfilePage}`,
|
|
Objects = `${AppBasePath.Settings}/${SettingsPath.Objects}`,
|
|
Members = `${AppBasePath.Settings}/${SettingsPath.WorkspaceMembersPage}`,
|
|
ApiWebhooks = `${AppBasePath.Settings}/${SettingsPath.ApiWebhooks}`,
|
|
LogicFunctions = `${AppBasePath.Settings}/${SettingsPath.LogicFunctions}`,
|
|
Integration = `${AppBasePath.Settings}/${SettingsPath.Integrations}`,
|
|
General = `${AppBasePath.Settings}/${SettingsPath.General}`,
|
|
Community = `${AppBasePath.Settings}/${SettingsPath.Community}`,
|
|
}
|
|
|
|
const getPathnameOrPrefix = (pathname: string) => {
|
|
for (const prefix of Object.values(SettingsPathPrefixes)) {
|
|
if (pathname.startsWith(prefix)) {
|
|
return prefix;
|
|
}
|
|
}
|
|
return pathname;
|
|
};
|
|
|
|
export const getPageTitleFromPath = (pathname: string): string => {
|
|
const pathnameOrPrefix = getPathnameOrPrefix(pathname);
|
|
switch (pathnameOrPrefix) {
|
|
case AppPath.Verify:
|
|
return t`Verify`;
|
|
case AppPath.SignInUp:
|
|
return t`Sign in or Create an account`;
|
|
case AppPath.Invite:
|
|
return t`Invite`;
|
|
case AppPath.WorkspaceActivation:
|
|
return t`Create Workspace`;
|
|
case AppPath.CreateProfile:
|
|
return t`Create Profile`;
|
|
case SettingsPathPrefixes.Experience:
|
|
return t`Experience - Settings`;
|
|
case SettingsPathPrefixes.Accounts:
|
|
return t`Account - Settings`;
|
|
case SettingsPathPrefixes.Profile:
|
|
return t`Profile - Settings`;
|
|
case SettingsPathPrefixes.Members:
|
|
return t`Members - Settings`;
|
|
case SettingsPathPrefixes.Objects:
|
|
return t`Data model - Settings`;
|
|
case SettingsPathPrefixes.ApiWebhooks:
|
|
return t`API Keys - Settings`;
|
|
case SettingsPathPrefixes.LogicFunctions:
|
|
return t`Functions - Settings`;
|
|
case SettingsPathPrefixes.Integration:
|
|
return t`Integrations - Settings`;
|
|
case SettingsPathPrefixes.General:
|
|
return t`General - Settings`;
|
|
case SettingsPathPrefixes.Community:
|
|
return t`Community - Settings`;
|
|
default:
|
|
return 'Twenty';
|
|
}
|
|
};
|