chore: rename workspaces to organizations, bump ciphera-ui to 0.0.49

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Usman Baig
2026-02-08 21:07:33 +01:00
parent 827f16a217
commit 34c854ed7c
6 changed files with 41 additions and 41 deletions

View File

@@ -17,7 +17,7 @@ export default function LayoutContent({ children }: { children: React.ReactNode
const isOnline = useOnlineStatus()
const [orgs, setOrgs] = useState<any[]>([])
// * Fetch organizations for the header workspace switcher
// * Fetch organizations for the header organization switcher
useEffect(() => {
if (auth.user) {
getUserOrganizations()
@@ -26,14 +26,14 @@ export default function LayoutContent({ children }: { children: React.ReactNode
}
}, [auth.user])
const handleSwitchWorkspace = async (orgId: string | null) => {
if (!orgId) return // Pulse doesn't support personal workspace
const handleSwitchOrganization = async (orgId: string | null) => {
if (!orgId) return // Pulse doesn't support personal organization context
try {
const { access_token } = await switchContext(orgId)
await setSessionAction(access_token)
window.location.reload()
} catch (err) {
console.error('Failed to switch workspace', err)
console.error('Failed to switch organization', err)
}
}
@@ -56,9 +56,9 @@ export default function LayoutContent({ children }: { children: React.ReactNode
appName="Pulse"
orgs={orgs}
activeOrgId={auth.user?.org_id}
onSwitchWorkspace={handleSwitchWorkspace}
onSwitchOrganization={handleSwitchOrganization}
onCreateOrganization={handleCreateOrganization}
allowPersonalWorkspace={false}
allowPersonalOrganization={false}
showFaq={false}
showSecurity={false}
showPricing={true}

View File

@@ -2,7 +2,7 @@
/**
* Guided onboarding wizard for new Pulse users.
* Steps: Welcome → Workspace (create org) → Plan / trial → First site (optional) → Done.
* Steps: Welcome → Organization (create org) → Plan / trial → First site (optional) → Done.
* Supports ?step= in URL for back/refresh. Handles pulse_pending_checkout from pricing.
*/
@@ -47,12 +47,12 @@ import ScriptSetupBlock from '@/components/sites/ScriptSetupBlock'
import VerificationModal from '@/components/sites/VerificationModal'
const TOTAL_STEPS = 5
const DEFAULT_ORG_NAME = 'My workspace'
const DEFAULT_ORG_NAME = 'My organization'
const SITE_DRAFT_KEY = 'pulse_welcome_site_draft'
const WELCOME_COMPLETED_KEY = 'pulse_welcome_completed'
function slugFromName(name: string): string {
return name.toLowerCase().replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'my-workspace'
return name.toLowerCase().replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'my-organization'
}
function suggestSlugVariant(slug: string): string {
@@ -143,7 +143,7 @@ function WelcomeContent() {
}
}, [user, step])
const handleSelectWorkspace = async (org: OrganizationMember) => {
const handleSelectOrganization = async (org: OrganizationMember) => {
setSwitchingOrgId(org.organization_id)
try {
const { access_token } = await switchContext(org.organization_id)
@@ -155,13 +155,13 @@ function WelcomeContent() {
setStep(3)
}
} catch (err) {
toast.error(getAuthErrorMessage(err) || 'Failed to switch workspace')
toast.error(getAuthErrorMessage(err) || 'Failed to switch organization')
} finally {
setSwitchingOrgId(null)
}
}
const handleCreateNewWorkspace = () => setStep(2)
const handleCreateNewOrganization = () => setStep(2)
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = e.target.value
@@ -171,7 +171,7 @@ function WelcomeContent() {
)
}
const handleWorkspaceSubmit = async (e: React.FormEvent) => {
const handleOrganizationSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setOrgLoading(true)
setOrgError('')
@@ -186,7 +186,7 @@ function WelcomeContent() {
trackWelcomeWorkspaceCreated(!!(typeof window !== 'undefined' && localStorage.getItem('pulse_pending_checkout')))
setStep(3)
} catch (err: unknown) {
const { message, suggestSlug } = getOrgErrorMessage(err, orgSlug, 'Failed to create workspace')
const { message, suggestSlug } = getOrgErrorMessage(err, orgSlug, 'Failed to create organization')
setOrgError(message)
if (suggestSlug) setOrgSlug(suggestSlug)
} finally {
@@ -367,10 +367,10 @@ function WelcomeContent() {
<BarChartIcon className="h-7 w-7" />
</div>
<h1 className="text-xl font-bold text-neutral-900 dark:text-white">
Choose your workspace
Choose your organization
</h1>
<p className="mt-1 text-sm text-neutral-600 dark:text-neutral-400">
Continue with an existing workspace or create a new one.
Continue with an existing organization or create a new one.
</p>
</div>
<div className="space-y-2 mb-6">
@@ -378,12 +378,12 @@ function WelcomeContent() {
<button
key={org.organization_id}
type="button"
onClick={() => handleSelectWorkspace(org)}
onClick={() => handleSelectOrganization(org)}
disabled={!!switchingOrgId}
className="w-full flex items-center justify-between gap-3 rounded-xl border border-neutral-200 dark:border-neutral-700 bg-neutral-50 dark:bg-neutral-800/50 hover:bg-neutral-100 dark:hover:bg-neutral-800 hover:border-brand-orange/50 px-4 py-3 text-left transition-colors disabled:opacity-60 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2"
>
<span className="font-medium text-neutral-900 dark:text-white">
{org.organization_name || 'Workspace'}
{org.organization_name || 'Organization'}
</span>
{user?.org_id === org.organization_id && (
<span className="text-xs text-neutral-500 dark:text-neutral-400">Current</span>
@@ -396,10 +396,10 @@ function WelcomeContent() {
type="button"
variant="secondary"
className="w-full"
onClick={handleCreateNewWorkspace}
onClick={handleCreateNewOrganization}
>
<PlusIcon className="h-4 w-4 mr-2" />
Create a new workspace
Create a new organization
</Button>
</>
) : (
@@ -450,16 +450,16 @@ function WelcomeContent() {
<BarChartIcon className="h-7 w-7" />
</div>
<h1 className="text-xl font-bold text-neutral-900 dark:text-white">
Name your workspace
Name your organization
</h1>
<p className="mt-1 text-sm text-neutral-600 dark:text-neutral-400">
You can change this later in settings.
</p>
</div>
<form onSubmit={handleWorkspaceSubmit} className="space-y-4">
<form onSubmit={handleOrganizationSubmit} className="space-y-4">
<div>
<label htmlFor="welcome-org-name" className="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1">
Workspace name
Organization name
</label>
<Input
id="welcome-org-name"
@@ -485,7 +485,7 @@ function WelcomeContent() {
className="w-full"
/>
<p className="mt-1 text-sm text-neutral-600 dark:text-neutral-400">
Used in your workspace URL.
Used in your organization URL.
</p>
</div>
{orgError && (
@@ -511,7 +511,7 @@ function WelcomeContent() {
type="button"
onClick={() => setStep(2)}
className="flex items-center gap-1.5 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
aria-label="Back to workspace"
aria-label="Back to organization"
>
<ArrowLeftIcon className="h-4 w-4" />
Back

View File

@@ -7,16 +7,16 @@ import { switchContext, OrganizationMember } from '@/lib/api/organization'
import { setSessionAction } from '@/app/actions/auth'
import Link from 'next/link'
export default function WorkspaceSwitcher({ orgs, activeOrgId }: { orgs: OrganizationMember[], activeOrgId: string | null }) {
export default function OrganizationSwitcher({ orgs, activeOrgId }: { orgs: OrganizationMember[], activeOrgId: string | null }) {
const router = useRouter()
const [switching, setSwitching] = useState<string | null>(null)
const handleSwitch = async (orgId: string | null) => {
console.log('Switching to workspace:', orgId)
console.log('Switching to organization:', orgId)
setSwitching(orgId || 'personal')
try {
// * If orgId is null, we can't switch context via API in the same way if strict mode is on
// * BUT, Pulse doesn't support personal workspace.
// * Pulse doesn't support personal organization context.
// * So we should probably NOT show the "Personal" option in Pulse if strict mode is enforced.
// * However, to match Drop exactly, we might want to show it but have it fail or redirect?
// * Let's assume for now we want to match Drop's UI structure.
@@ -38,7 +38,7 @@ export default function WorkspaceSwitcher({ orgs, activeOrgId }: { orgs: Organiz
window.location.reload()
} catch (err) {
console.error('Failed to switch workspace', err)
console.error('Failed to switch organization', err)
setSwitching(null)
}
}
@@ -46,10 +46,10 @@ export default function WorkspaceSwitcher({ orgs, activeOrgId }: { orgs: Organiz
return (
<div className="border-b border-neutral-100 dark:border-neutral-800 pb-2 mb-2">
<div className="px-3 py-2 text-xs font-medium text-neutral-500 uppercase tracking-wider">
Workspaces
Organizations
</div>
{/* Personal Workspace - HIDDEN IN PULSE (Strict Mode) */}
{/* Personal organization - HIDDEN IN PULSE (Strict Mode) */}
{/*
<button
onClick={() => handleSwitch(null)}
@@ -70,7 +70,7 @@ export default function WorkspaceSwitcher({ orgs, activeOrgId }: { orgs: Organiz
</button>
*/}
{/* Organization Workspaces */}
{/* Organization list */}
{orgs.map((org) => (
<button
key={org.organization_id}

View File

@@ -237,11 +237,11 @@ export default function OrganizationSettings() {
}
}, [activeTab, currentOrgId, loadAudit, auditFetchTrigger])
// If no org ID, we are in personal workspace, so don't show org settings
// If no org ID, we are in personal organization context, so don't show org settings
if (!currentOrgId) {
return (
<div className="p-6 text-center text-neutral-500">
<p>You are in your Personal Workspace. Switch to an Organization to manage its settings.</p>
<p>You are in your personal context. Switch to an Organization to manage its settings.</p>
</div>
)
}

8
package-lock.json generated
View File

@@ -8,7 +8,7 @@
"name": "pulse-frontend",
"version": "0.1.3",
"dependencies": {
"@ciphera-net/ui": "^0.0.48",
"@ciphera-net/ui": "^0.0.49",
"@ducanh2912/next-pwa": "^10.2.9",
"axios": "^1.13.2",
"country-flag-icons": "^1.6.4",
@@ -1467,9 +1467,9 @@
}
},
"node_modules/@ciphera-net/ui": {
"version": "0.0.48",
"resolved": "https://npm.pkg.github.com/download/@ciphera-net/ui/0.0.48/20eedc6319567fff80530d865ebbed6e6f784dab",
"integrity": "sha512-kDrGV7tzAjeiz7MtK5G81iY08Zg4NxHTlDNkH5/Pkl2aSpyraf04/J/pGshChjdXMdioXrJA7JU8YH+GlI1LfA==",
"version": "0.0.49",
"resolved": "https://npm.pkg.github.com/download/@ciphera-net/ui/0.0.49/ef6f7f06a134bc3d3b4cb1086f689ddb34f1652a",
"integrity": "sha512-ga2n0kO7JeOFzVVRX+FU5iQxodv2yE/hUnlEUHEomorKzWCADM9wAOLGcxi8mcVz49jy/4IQlHRdpF9LH64uQg==",
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"clsx": "^2.1.0",

View File

@@ -10,7 +10,7 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"@ciphera-net/ui": "^0.0.48",
"@ciphera-net/ui": "^0.0.49",
"@ducanh2912/next-pwa": "^10.2.9",
"axios": "^1.13.2",
"country-flag-icons": "^1.6.4",