diff --git a/src/components/common/WorkspaceProfilePic.vue b/src/components/common/WorkspaceProfilePic.vue
new file mode 100644
index 000000000..b8ecd6108
--- /dev/null
+++ b/src/components/common/WorkspaceProfilePic.vue
@@ -0,0 +1,43 @@
+
+
+ {{ letter }}
+
+
+
+
diff --git a/src/components/dialog/GlobalDialog.vue b/src/components/dialog/GlobalDialog.vue
index 9ae81ea69..6bf3eab44 100644
--- a/src/components/dialog/GlobalDialog.vue
+++ b/src/components/dialog/GlobalDialog.vue
@@ -4,7 +4,10 @@
v-for="item in dialogStore.dialogStack"
:key="item.key"
v-model:visible="item.visible"
- class="global-dialog"
+ :class="[
+ 'global-dialog',
+ item.key === 'global-settings' ? 'settings-dialog' : ''
+ ]"
v-bind="item.dialogComponentProps"
:pt="item.dialogComponentProps.pt"
:aria-labelledby="item.key"
diff --git a/src/components/dialog/content/setting/MembersPanelContent.vue b/src/components/dialog/content/setting/MembersPanelContent.vue
new file mode 100644
index 000000000..db5e7c458
--- /dev/null
+++ b/src/components/dialog/content/setting/MembersPanelContent.vue
@@ -0,0 +1,470 @@
+
+
+
+
+
+
+
+ {{
+ $t('workspacePanel.members.membersCount', {
+ count: members.length
+ })
+ }}
+
+
+ {{
+ $t(
+ 'workspacePanel.members.pendingInvitesCount',
+ pendingInvites.length
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ userDisplayName }}
+
+ ({{ $t('g.you') }})
+
+
+
+ {{ workspaceRole }}
+
+
+
+ {{ userEmail }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ member.name.charAt(0).toUpperCase() }}
+
+
+
+
+ {{ member.name }}
+
+
+ {{ member.email }}
+
+
+
+
+
+ {{ formatDate(member.joinDate) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ invite.name.charAt(0).toUpperCase() }}
+
+
+
+
+ {{ invite.name }}
+
+
+ {{ invite.email }}
+
+
+
+
+
+ {{ formatDate(invite.inviteDate) }}
+
+
+
+ {{ formatDate(invite.expiryDate) }}
+
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.members.noInvites') }}
+
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.members.personalWorkspaceMessage') }}
+
+
+
+
+
+
diff --git a/src/components/dialog/content/setting/WorkspacePanel.vue b/src/components/dialog/content/setting/WorkspacePanel.vue
index dd303371e..aff8f3733 100644
--- a/src/components/dialog/content/setting/WorkspacePanel.vue
+++ b/src/components/dialog/content/setting/WorkspacePanel.vue
@@ -2,12 +2,6 @@
-
-
-
-
-
-
diff --git a/src/components/dialog/content/setting/WorkspaceSidebarItem.vue b/src/components/dialog/content/setting/WorkspaceSidebarItem.vue
index 79b006da3..375c02321 100644
--- a/src/components/dialog/content/setting/WorkspaceSidebarItem.vue
+++ b/src/components/dialog/content/setting/WorkspaceSidebarItem.vue
@@ -1,16 +1,17 @@
-
+
- {{ workspaceName ?? 'Personal' }}
+ {{ workspaceName }}
diff --git a/src/components/dialog/content/workspace/CreateWorkspaceDialogContent.vue b/src/components/dialog/content/workspace/CreateWorkspaceDialogContent.vue
new file mode 100644
index 000000000..0c317c6fe
--- /dev/null
+++ b/src/components/dialog/content/workspace/CreateWorkspaceDialogContent.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+ {{ $t('workspacePanel.createWorkspaceDialog.title') }}
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.createWorkspaceDialog.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/dialog/content/workspace/DeleteWorkspaceDialogContent.vue b/src/components/dialog/content/workspace/DeleteWorkspaceDialogContent.vue
new file mode 100644
index 000000000..5a455a953
--- /dev/null
+++ b/src/components/dialog/content/workspace/DeleteWorkspaceDialogContent.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+ {{ $t('workspacePanel.deleteDialog.title') }}
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.deleteDialog.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/dialog/content/workspace/InviteMemberDialogContent.vue b/src/components/dialog/content/workspace/InviteMemberDialogContent.vue
new file mode 100644
index 000000000..784a11596
--- /dev/null
+++ b/src/components/dialog/content/workspace/InviteMemberDialogContent.vue
@@ -0,0 +1,178 @@
+
+
+
+
+
+ {{
+ step === 'email'
+ ? $t('workspacePanel.inviteMemberDialog.title')
+ : $t('workspacePanel.inviteMemberDialog.linkStep.title')
+ }}
+
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.inviteMemberDialog.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.inviteMemberDialog.linkStep.message') }}
+
+
+ {{ email }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/dialog/content/workspace/LeaveWorkspaceDialogContent.vue b/src/components/dialog/content/workspace/LeaveWorkspaceDialogContent.vue
new file mode 100644
index 000000000..da6703cba
--- /dev/null
+++ b/src/components/dialog/content/workspace/LeaveWorkspaceDialogContent.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+ {{ $t('workspacePanel.leaveDialog.title') }}
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.leaveDialog.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/dialog/content/workspace/RemoveMemberDialogContent.vue b/src/components/dialog/content/workspace/RemoveMemberDialogContent.vue
new file mode 100644
index 000000000..29f444587
--- /dev/null
+++ b/src/components/dialog/content/workspace/RemoveMemberDialogContent.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+ {{ $t('workspacePanel.removeMemberDialog.title') }}
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.removeMemberDialog.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/dialog/content/workspace/RevokeInviteDialogContent.vue b/src/components/dialog/content/workspace/RevokeInviteDialogContent.vue
new file mode 100644
index 000000000..76744a76d
--- /dev/null
+++ b/src/components/dialog/content/workspace/RevokeInviteDialogContent.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+ {{ $t('workspacePanel.revokeInviteDialog.title') }}
+
+
+
+
+
+
+
+ {{ $t('workspacePanel.revokeInviteDialog.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/toast/WorkspaceCreatedToast.vue b/src/components/toast/WorkspaceCreatedToast.vue
new file mode 100644
index 000000000..16f9189db
--- /dev/null
+++ b/src/components/toast/WorkspaceCreatedToast.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+ {{ $t('workspacePanel.toast.workspaceCreated.title') }}
+
+
+ {{ $t('workspacePanel.toast.workspaceCreated.message') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/topbar/CurrentUserPopover.vue b/src/components/topbar/CurrentUserPopover.vue
index fa5e9b6d3..77ebdd1de 100644
--- a/src/components/topbar/CurrentUserPopover.vue
+++ b/src/components/topbar/CurrentUserPopover.vue
@@ -21,114 +21,197 @@
{{ userEmail }}
-
{{ subscriptionTierName }}
-
+ -->
-
-
-
-
- {{
- formattedBalance
- }}
-
-
-
-
-
-
-
-
-
-
+
-
-
{{
- $t('subscription.partnerNodesCredits')
- }}
+
+
+
{{
+ workspaceName
+ }}
+
+ {{ subscriptionTierName }}
+
+
+ {{ $t('workspaceSwitcher.subscribe') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ formattedBalance
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- {{
+
+ {{
$t('subscription.plansAndPricing')
}}
{{ $t('subscription.upgrade') }}
+
-
- {{
+
+ {{
$t('subscription.managePlan')
}}
+
+
+ {{
+ $t('subscription.partnerNodesCredits')
+ }}
+
+
+
+
+
+
+
+ {{
+ $t('userSettings.workspaceSettings')
+ }}
+
+
+
+
-
- {{
+
+ {{
$t('userSettings.accountSettings')
}}
-
+
+
-
- {{
+
+ {{
$t('auth.signOut.signOut')
}}
@@ -137,12 +220,15 @@
diff --git a/src/locales/en/main.json b/src/locales/en/main.json
index d44665044..4137e5dea 100644
--- a/src/locales/en/main.json
+++ b/src/locales/en/main.json
@@ -1,6 +1,7 @@
{
"g": {
"user": "User",
+ "you": "You",
"currentUser": "Current user",
"empty": "Empty",
"noWorkflowsFound": "No workflows found.",
@@ -2000,6 +2001,8 @@
"renewsDate": "Renews {date}",
"expiresDate": "Expires {date}",
"manageSubscription": "Manage subscription",
+ "managePayment": "Manage Payment",
+ "cancelSubscription": "Cancel Subscription",
"partnerNodesBalance": "\"Partner Nodes\" Credit Balance",
"partnerNodesDescription": "For running commercial/proprietary models",
"totalCredits": "Total credits",
@@ -2054,6 +2057,8 @@
"subscribeToRunFull": "Subscribe to Run",
"subscribeNow": "Subscribe Now",
"subscribeToComfyCloud": "Subscribe to Comfy Cloud",
+ "workspaceNotSubscribed": "This workspace is not on a subscription",
+ "subscriptionRequiredMessage": "A subscription is required for members to run workflows on Cloud",
"description": "Choose the best plan for you",
"haveQuestions": "Have questions or wondering about enterprise?",
"contactUs": "Contact us",
@@ -2089,6 +2094,7 @@
"userSettings": {
"title": "My Account Settings",
"accountSettings": "Account settings",
+ "workspaceSettings": "Workspace settings",
"name": "Name",
"email": "Email",
"provider": "Sign-in Provider",
@@ -2096,18 +2102,98 @@
"updatePassword": "Update Password"
},
"workspacePanel": {
+ "invite": "Invite",
+ "inviteMember": "Invite member",
+ "inviteLimitReached": "You've reached the maximum of 50 members",
"tabs": {
"dashboard": "Dashboard",
"planCredits": "Plan & Credits",
- "members": "Members"
+ "membersCount": "Members ({count})"
},
"dashboard": {
"placeholder": "Dashboard workspace settings"
},
"members": {
- "placeholder": "Member settings"
+ "membersCount": "{count}/50 Members",
+ "pendingInvitesCount": "{count} pending invite | {count} pending invites",
+ "tabs": {
+ "active": "Active",
+ "pendingCount": "Pending ({count})"
+ },
+ "columns": {
+ "inviteDate": "Invite date",
+ "expiryDate": "Expiry date",
+ "joinDate": "Join date"
+ },
+ "actions": {
+ "copyLink": "Copy invite link",
+ "revokeInvite": "Revoke invite",
+ "removeMember": "Remove member"
+ },
+ "noInvites": "No pending invites",
+ "noMembers": "No members",
+ "personalWorkspaceMessage": "You can't invite other members to your personal workspace right now. To add members to a workspace,",
+ "createNewWorkspace": "create a new one."
+ },
+ "menu": {
+ "leaveWorkspace": "Leave Workspace",
+ "deleteWorkspace": "Delete Workspace",
+ "deleteWorkspaceDisabledTooltip": "Cancel your workspace's active subscription first"
+ },
+ "leaveDialog": {
+ "title": "Leave this workspace?",
+ "message": "You won't be able to join again unless you contact the workspace owner.",
+ "leave": "Leave"
+ },
+ "deleteDialog": {
+ "title": "Delete this workspace?",
+ "message": "Any unused credits or unsaved assets will be lost. This action cannot be undone."
+ },
+ "removeMemberDialog": {
+ "title": "Remove this member?",
+ "message": "This member will be removed from your workspace. Credits they've used will not be refunded.",
+ "remove": "Remove member"
+ },
+ "revokeInviteDialog": {
+ "title": "Uninvite this person?",
+ "message": "This member won't be able to join your workspace anymore. Their invite link will be invalidated.",
+ "revoke": "Uninvite"
+ },
+ "inviteMemberDialog": {
+ "title": "Invite a person to this workspace",
+ "message": "Create a shareable invite link to send to someone",
+ "placeholder": "Enter the person's email",
+ "createLink": "Create link",
+ "linkStep": {
+ "title": "Send this link to the person",
+ "message": "Make sure their account uses this email.",
+ "copyLink": "Copy Link",
+ "done": "Done"
+ }
+ },
+ "createWorkspaceDialog": {
+ "title": "Create a new workspace",
+ "message": "Workspaces let members share a single credits pool. You'll become the owner after creating this.",
+ "nameLabel": "Workspace name*",
+ "namePlaceholder": "Enter workspace name",
+ "create": "Create"
+ },
+ "toast": {
+ "workspaceCreated": {
+ "title": "Workspace created",
+ "message": "Subscribe to a plan, invite teammates, and start collaborating.",
+ "subscribe": "Subscribe"
+ }
}
},
+ "workspaceSwitcher": {
+ "switchWorkspace": "Switch workspace",
+ "subscribe": "Subscribe",
+ "roleOwner": "Owner",
+ "roleMember": "Member",
+ "createWorkspace": "Create new workspace",
+ "maxWorkspacesReached": "You can only own 10 workspaces. Delete one to create a new one."
+ },
"selectionToolbox": {
"executeButton": {
"tooltip": "Execute to selected output nodes (Highlighted with orange border)",
@@ -2635,4 +2721,4 @@
"tokenExchangeFailed": "Failed to authenticate with workspace: {error}"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/platform/cloud/subscription/components/SubscriptionPanelContent.vue b/src/platform/cloud/subscription/components/SubscriptionPanelContent.vue
index 0568101c1..f1fa68c37 100644
--- a/src/platform/cloud/subscription/components/SubscriptionPanelContent.vue
+++ b/src/platform/cloud/subscription/components/SubscriptionPanelContent.vue
@@ -3,66 +3,98 @@
-
-
- {{ subscriptionTierName }}
+
+
+
+
+ {{ $t('subscription.workspaceNotSubscribed') }}
+
+
+ {{ $t('subscription.subscriptionRequiredMessage') }}
+
-
- ${{ tierPrice }}
- {{
- $t('subscription.perMonth')
- }}
-
-
-
- {{
- $t('subscription.expiresDate', {
- date: formattedEndDate
- })
- }}
-
-
- {{
- $t('subscription.renewsDate', {
- date: formattedRenewalDate
- })
- }}
-
+ {{ $t('subscription.subscribeNow') }}
+
+
+
+
+
+
+
+ {{ subscriptionTierName }}
+
+
+ ${{ tierPrice }}
+ {{ $t('subscription.perMonth') }}
+
+
+
+ {{
+ $t('subscription.expiresDate', {
+ date: formattedEndDate
+ })
+ }}
+
+
+ {{
+ $t('subscription.renewsDate', {
+ date: formattedRenewalDate
+ })
+ }}
+
+
-
-
-
+
+
+
+
+
+
-
+
+
@@ -91,13 +123,9 @@
{{ $t('subscription.totalCredits') }}
-
+
- {{ totalCredits }}
+ {{ isOwnerUnsubscribed ? '0' : totalCredits }}
@@ -111,7 +139,9 @@
width="5rem"
height="1rem"
/>
-
{{ includedCreditsDisplay }}
+
{{
+ isOwnerUnsubscribed ? '0 / 0' : includedCreditsDisplay
+ }}
{{ creditsRemainingLabel }}
@@ -124,7 +154,9 @@
width="3rem"
height="1rem"
/>
- {{ prepaidCredits }}
+ {{
+ isOwnerUnsubscribed ? '0' : prepaidCredits
+ }}
|
|