refactor: workspaces DDD (#8921)

## Summary

Refactor: workspaces related functionality into DDD structure.

Note: this is the 1st PR of 2 more refactoring.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8921-refactor-DDD-3096d73d3650812bb7f6eb955f042663)
by [Unito](https://www.unito.io)
This commit is contained in:
Simula_r
2026-02-17 12:28:47 -08:00
committed by GitHub
parent e83e396c09
commit 631d484901
42 changed files with 39 additions and 38 deletions

View File

@@ -69,7 +69,7 @@ import Skeleton from 'primevue/skeleton'
import { computed, defineAsyncComponent, ref } from 'vue'
import UserAvatar from '@/components/common/UserAvatar.vue'
import WorkspaceProfilePic from '@/components/common/WorkspaceProfilePic.vue'
import WorkspaceProfilePic from '@/platform/workspace/components/WorkspaceProfilePic.vue'
import Button from '@/components/ui/button/Button.vue'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
@@ -80,7 +80,8 @@ import { cn } from '@/utils/tailwindUtil'
import CurrentUserPopoverLegacy from './CurrentUserPopoverLegacy.vue'
const CurrentUserPopoverWorkspace = defineAsyncComponent(
() => import('./CurrentUserPopoverWorkspace.vue')
() =>
import('../../platform/workspace/components/CurrentUserPopoverWorkspace.vue')
)
const { showArrow = true, compact = false } = defineProps<{

View File

@@ -18,7 +18,7 @@ import type {
SubscriptionInfo
} from './types'
import { useLegacyBilling } from './useLegacyBilling'
import { useWorkspaceBilling } from './useWorkspaceBilling'
import { useWorkspaceBilling } from '@/platform/workspace/composables/useWorkspaceBilling'
/**
* Unified billing context that automatically switches between legacy (user-scoped)

View File

@@ -80,7 +80,7 @@ import { isCloud } from '@/platform/distribution/types'
const SubscriptionPanelContentWorkspace = defineAsyncComponent(
() =>
import('@/platform/cloud/subscription/components/SubscriptionPanelContentWorkspace.vue')
import('@/platform/workspace/components/SubscriptionPanelContentWorkspace.vue')
)
const { flags } = useFeatureFlags()

View File

@@ -23,7 +23,7 @@ export const useSubscriptionDialog = () => {
const component = useWorkspaceVariant
? defineAsyncComponent(
() =>
import('@/platform/cloud/subscription/components/SubscriptionRequiredDialogContentWorkspace.vue')
import('@/platform/workspace/components/SubscriptionRequiredDialogContentWorkspace.vue')
)
: defineAsyncComponent(
() =>

View File

@@ -177,7 +177,7 @@ export function useSettingUI(
},
component: defineAsyncComponent(
() =>
import('@/components/dialog/content/setting/WorkspacePanelContent.vue')
import('@/platform/workspace/components/dialogs/settings/WorkspacePanelContent.vue')
)
}

View File

@@ -207,8 +207,8 @@ import { useI18n } from 'vue-i18n'
import { formatCreditsFromCents } from '@/base/credits/comfyCredits'
import UserAvatar from '@/components/common/UserAvatar.vue'
import WorkspaceProfilePic from '@/components/common/WorkspaceProfilePic.vue'
import WorkspaceSwitcherPopover from '@/components/topbar/WorkspaceSwitcherPopover.vue'
import WorkspaceProfilePic from '@/platform/workspace/components/WorkspaceProfilePic.vue'
import WorkspaceSwitcherPopover from '@/platform/workspace/components/WorkspaceSwitcherPopover.vue'
import Button from '@/components/ui/button/Button.vue'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'

View File

@@ -357,7 +357,7 @@ import { useToast } from 'primevue/usetoast'
import StatusBadge from '@/components/common/StatusBadge.vue'
import Button from '@/components/ui/button/Button.vue'
import { useBillingContext } from '@/composables/billing/useBillingContext'
import { useBillingOperationStore } from '@/stores/billingOperationStore'
import { useBillingOperationStore } from '@/platform/workspace/stores/billingOperationStore'
import { useSubscriptionActions } from '@/platform/cloud/subscription/composables/useSubscriptionActions'
import { useSubscriptionCredits } from '@/platform/cloud/subscription/composables/useSubscriptionCredits'
import { workspaceApi } from '@/platform/workspace/api/workspaceApi'

View File

@@ -74,7 +74,7 @@ import type { TierKey } from '@/platform/cloud/subscription/constants/tierPricin
import type { BillingCycle } from '@/platform/cloud/subscription/utils/subscriptionTierRank'
import type { PreviewSubscribeResponse } from '@/platform/workspace/api/workspaceApi'
import { workspaceApi } from '@/platform/workspace/api/workspaceApi'
import { useBillingOperationStore } from '@/stores/billingOperationStore'
import { useBillingOperationStore } from '@/platform/workspace/stores/billingOperationStore'
import PricingTableWorkspace from './PricingTableWorkspace.vue'
import SubscriptionAddPaymentPreviewWorkspace from './SubscriptionAddPaymentPreviewWorkspace.vue'

View File

@@ -162,7 +162,7 @@ import { useTelemetry } from '@/platform/telemetry'
import { clearTopupTracking } from '@/platform/telemetry/topupTracker'
import { workspaceApi } from '@/platform/workspace/api/workspaceApi'
import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog'
import { useBillingOperationStore } from '@/stores/billingOperationStore'
import { useBillingOperationStore } from '@/platform/workspace/stores/billingOperationStore'
import { useDialogStore } from '@/stores/dialogStore'
import { cn } from '@/utils/tailwindUtil'

View File

@@ -112,9 +112,9 @@ import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import WorkspaceProfilePic from '@/components/common/WorkspaceProfilePic.vue'
import WorkspaceProfilePic from '@/platform/workspace/components/WorkspaceProfilePic.vue'
import { useBillingContext } from '@/composables/billing/useBillingContext'
import { useWorkspaceSwitch } from '@/platform/auth/workspace/useWorkspaceSwitch'
import { useWorkspaceSwitch } from '@/platform/workspace/composables/useWorkspaceSwitch'
import type {
SubscriptionTier,
WorkspaceRole,

View File

@@ -120,12 +120,12 @@ import { useI18n } from 'vue-i18n'
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from 'reka-ui'
import WorkspaceProfilePic from '@/components/common/WorkspaceProfilePic.vue'
import MembersPanelContent from '@/components/dialog/content/setting/MembersPanelContent.vue'
import WorkspaceProfilePic from '@/platform/workspace/components/WorkspaceProfilePic.vue'
import MembersPanelContent from '@/platform/workspace/components/dialogs/settings/MembersPanelContent.vue'
import Button from '@/components/ui/button/Button.vue'
import { useBillingContext } from '@/composables/billing/useBillingContext'
import { TIER_TO_KEY } from '@/platform/cloud/subscription/constants/tierPricing'
import SubscriptionPanelContentWorkspace from '@/platform/cloud/subscription/components/SubscriptionPanelContentWorkspace.vue'
import SubscriptionPanelContentWorkspace from '@/platform/workspace/components/SubscriptionPanelContentWorkspace.vue'
import { useWorkspaceUI } from '@/platform/workspace/composables/useWorkspaceUI'
import { useTeamWorkspaceStore } from '@/platform/workspace/stores/teamWorkspaceStore'
import { useDialogService } from '@/services/dialogService'

View File

@@ -29,7 +29,7 @@ import Toast from 'primevue/toast'
import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { useWorkspaceSwitch } from '@/platform/auth/workspace/useWorkspaceSwitch'
import { useWorkspaceSwitch } from '@/platform/workspace/composables/useWorkspaceSwitch'
const { t } = useI18n()
const toast = useToast()

View File

@@ -16,7 +16,7 @@ import type {
BillingActions,
BillingState,
SubscriptionInfo
} from './types'
} from '../../../composables/billing/types'
/**
* Adapter for workspace-scoped billing via /billing/* endpoints.

View File

@@ -1,6 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { useWorkspaceSwitch } from '@/platform/auth/workspace/useWorkspaceSwitch'
import { useWorkspaceSwitch } from '@/platform/workspace/composables/useWorkspaceSwitch'
import type { WorkspaceWithRole } from '@/platform/workspace/api/workspaceApi'
const mockSwitchWorkspace = vi.hoisted(() => vi.fn())

View File

@@ -25,7 +25,7 @@ const mockWorkspaceAuthStore = vi.hoisted(() => ({
clearWorkspaceContext: vi.fn()
}))
vi.mock('@/stores/workspaceAuthStore', () => ({
vi.mock('@/platform/workspace/stores/workspaceAuthStore', () => ({
useWorkspaceAuthStore: () => mockWorkspaceAuthStore
}))

View File

@@ -1,10 +1,10 @@
import { defineStore } from 'pinia'
import { computed, ref, shallowRef } from 'vue'
import { WORKSPACE_STORAGE_KEYS } from '@/platform/auth/workspace/workspaceConstants'
import { WORKSPACE_STORAGE_KEYS } from '@/platform/workspace/workspaceConstants'
import { clearPreservedQuery } from '@/platform/navigation/preservedQueryManager'
import { PRESERVED_QUERY_NAMESPACES } from '@/platform/navigation/preservedQueryNamespaces'
import { useWorkspaceAuthStore } from '@/stores/workspaceAuthStore'
import { useWorkspaceAuthStore } from '@/platform/workspace/stores/workspaceAuthStore'
import type {
ListMembersParams,

View File

@@ -4,9 +4,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
useWorkspaceAuthStore,
WorkspaceAuthError
} from '@/stores/workspaceAuthStore'
} from '@/platform/workspace/stores/workspaceAuthStore'
import { WORKSPACE_STORAGE_KEYS } from './workspaceConstants'
import { WORKSPACE_STORAGE_KEYS } from '@/platform/workspace/workspaceConstants'
const mockGetIdToken = vi.fn()

View File

@@ -7,11 +7,11 @@ import { t } from '@/i18n'
import {
TOKEN_REFRESH_BUFFER_MS,
WORKSPACE_STORAGE_KEYS
} from '@/platform/auth/workspace/workspaceConstants'
} from '@/platform/workspace/workspaceConstants'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import type { AuthHeader } from '@/types/authTypes'
import type { WorkspaceWithRole } from '@/platform/auth/workspace/workspaceTypes'
import type { WorkspaceWithRole } from '@/platform/workspace/workspaceTypes'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
const WorkspaceWithRoleSchema = z.object({

View File

@@ -5,7 +5,7 @@ import ConfirmationDialogContent from '@/components/dialog/content/ConfirmationD
import ErrorDialogContent from '@/components/dialog/content/ErrorDialogContent.vue'
import PromptDialogContent from '@/components/dialog/content/PromptDialogContent.vue'
import TopUpCreditsDialogContentLegacy from '@/components/dialog/content/TopUpCreditsDialogContentLegacy.vue'
import TopUpCreditsDialogContentWorkspace from '@/components/dialog/content/TopUpCreditsDialogContentWorkspace.vue'
import TopUpCreditsDialogContentWorkspace from '@/platform/workspace/components/TopUpCreditsDialogContentWorkspace.vue'
import { t } from '@/i18n'
import { useTelemetry } from '@/platform/telemetry'
import { isCloud } from '@/platform/distribution/types'
@@ -571,7 +571,7 @@ export const useDialogService = () => {
workspaceName?: string
}) {
const { default: component } =
await import('@/components/dialog/content/workspace/DeleteWorkspaceDialogContent.vue')
await import('@/platform/workspace/components/dialogs/DeleteWorkspaceDialogContent.vue')
return dialogStore.showDialog({
key: 'delete-workspace',
component,
@@ -584,7 +584,7 @@ export const useDialogService = () => {
onConfirm?: (name: string) => void | Promise<void>
) {
const { default: component } =
await import('@/components/dialog/content/workspace/CreateWorkspaceDialogContent.vue')
await import('@/platform/workspace/components/dialogs/CreateWorkspaceDialogContent.vue')
return dialogStore.showDialog({
key: 'create-workspace',
component,
@@ -601,7 +601,7 @@ export const useDialogService = () => {
async function showLeaveWorkspaceDialog() {
const { default: component } =
await import('@/components/dialog/content/workspace/LeaveWorkspaceDialogContent.vue')
await import('@/platform/workspace/components/dialogs/LeaveWorkspaceDialogContent.vue')
return dialogStore.showDialog({
key: 'leave-workspace',
component,
@@ -611,7 +611,7 @@ export const useDialogService = () => {
async function showEditWorkspaceDialog() {
const { default: component } =
await import('@/components/dialog/content/workspace/EditWorkspaceDialogContent.vue')
await import('@/platform/workspace/components/dialogs/EditWorkspaceDialogContent.vue')
return dialogStore.showDialog({
key: 'edit-workspace',
component,
@@ -627,7 +627,7 @@ export const useDialogService = () => {
async function showRemoveMemberDialog(memberId: string) {
const { default: component } =
await import('@/components/dialog/content/workspace/RemoveMemberDialogContent.vue')
await import('@/platform/workspace/components/dialogs/RemoveMemberDialogContent.vue')
return dialogStore.showDialog({
key: 'remove-member',
component,
@@ -638,7 +638,7 @@ export const useDialogService = () => {
async function showInviteMemberDialog() {
const { default: component } =
await import('@/components/dialog/content/workspace/InviteMemberDialogContent.vue')
await import('@/platform/workspace/components/dialogs/InviteMemberDialogContent.vue')
return dialogStore.showDialog({
key: 'invite-member',
component,
@@ -654,7 +654,7 @@ export const useDialogService = () => {
async function showInviteMemberUpsellDialog() {
const { default: component } =
await import('@/components/dialog/content/workspace/InviteMemberUpsellDialogContent.vue')
await import('@/platform/workspace/components/dialogs/InviteMemberUpsellDialogContent.vue')
return dialogStore.showDialog({
key: 'invite-member-upsell',
component,
@@ -670,7 +670,7 @@ export const useDialogService = () => {
async function showRevokeInviteDialog(inviteId: string) {
const { default: component } =
await import('@/components/dialog/content/workspace/RevokeInviteDialogContent.vue')
await import('@/platform/workspace/components/dialogs/RevokeInviteDialogContent.vue')
return dialogStore.showDialog({
key: 'revoke-invite',
component,

View File

@@ -22,7 +22,7 @@ import { useFirebaseAuth } from 'vuefire'
import { getComfyApiBaseUrl } from '@/config/comfyApi'
import { t } from '@/i18n'
import { WORKSPACE_STORAGE_KEYS } from '@/platform/auth/workspace/workspaceConstants'
import { WORKSPACE_STORAGE_KEYS } from '@/platform/workspace/workspaceConstants'
import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import { useDialogService } from '@/services/dialogService'

View File

@@ -45,7 +45,7 @@ import MenuHamburger from '@/components/MenuHamburger.vue'
import UnloadWindowConfirmDialog from '@/components/dialog/UnloadWindowConfirmDialog.vue'
import GraphCanvas from '@/components/graph/GraphCanvas.vue'
import GlobalToast from '@/components/toast/GlobalToast.vue'
import InviteAcceptedToast from '@/components/toast/InviteAcceptedToast.vue'
import InviteAcceptedToast from '@/platform/workspace/components/toasts/InviteAcceptedToast.vue'
import RerouteMigrationToast from '@/components/toast/RerouteMigrationToast.vue'
import { useBrowserTabTitle } from '@/composables/useBrowserTabTitle'
import { useCoreCommands } from '@/composables/useCoreCommands'

View File

@@ -9,7 +9,7 @@
<script setup lang="ts">
import { useFavicon } from '@vueuse/core'
import WorkspaceAuthGate from '@/components/auth/WorkspaceAuthGate.vue'
import WorkspaceAuthGate from '@/platform/workspace/auth/WorkspaceAuthGate.vue'
useFavicon('/assets/favicon.ico')
</script>