@streamoid/settings 0.7.3 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +197 -23
- package/dist/index.mjs +199 -24
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -182,6 +182,9 @@ interface SettingsWorkspaceListItem {
|
|
|
182
182
|
/** The organization this workspace belongs to, if any. My workspaces groups
|
|
183
183
|
* the list under each organization (named from `organization.list()`). */
|
|
184
184
|
organizationId?: string;
|
|
185
|
+
/** The organization's name, when the host has it (used by `listPage()`
|
|
186
|
+
* rows whose organization isn't in `organization.list()`). */
|
|
187
|
+
organizationName?: string;
|
|
185
188
|
}
|
|
186
189
|
interface SettingsWorkspaceAdapter {
|
|
187
190
|
/** Same authenticated transport used by the sidebar owner lookup. */
|
|
@@ -240,6 +243,20 @@ interface SettingsWorkspaceAdapter {
|
|
|
240
243
|
* When omitted, the plan on each `list()` item is used as before.
|
|
241
244
|
*/
|
|
242
245
|
fetchPlans?: (workspaceIds: string[]) => Promise<Record<string, string>>;
|
|
246
|
+
/**
|
|
247
|
+
* Optional: one page of the workspace list, from the API
|
|
248
|
+
* (`GET /workspace?limit=&offset=`). When given, My workspaces asks for each
|
|
249
|
+
* page as it is shown and renders exactly what comes back — `total` is every
|
|
250
|
+
* workspace the user can see. When omitted (or when a page request fails),
|
|
251
|
+
* My workspaces pages through `list()` in the browser as before.
|
|
252
|
+
*/
|
|
253
|
+
listPage?: (params: {
|
|
254
|
+
limit: number;
|
|
255
|
+
offset: number;
|
|
256
|
+
}) => Promise<{
|
|
257
|
+
items: SettingsWorkspaceListItem[];
|
|
258
|
+
total: number;
|
|
259
|
+
}>;
|
|
243
260
|
/**
|
|
244
261
|
* Optional: host-controlled refresh after the package mutates workspace
|
|
245
262
|
* state. If provided, the package will call this instead of (or in addition
|
|
@@ -349,6 +366,14 @@ interface OrganizationWorkspaceItem {
|
|
|
349
366
|
imageUrl?: string;
|
|
350
367
|
orgVisibility: "private" | "shared";
|
|
351
368
|
}
|
|
369
|
+
/** A shared workspace in the organization that the viewer isn't in yet. */
|
|
370
|
+
interface OrganizationJoinableWorkspace {
|
|
371
|
+
_id: string;
|
|
372
|
+
name: string;
|
|
373
|
+
imageUrl?: string;
|
|
374
|
+
/** Who created it, shown under the name. */
|
|
375
|
+
ownerName?: string;
|
|
376
|
+
}
|
|
352
377
|
interface OrganizationJoinRequest {
|
|
353
378
|
_id: string;
|
|
354
379
|
workspace: {
|
|
@@ -438,6 +463,15 @@ interface SettingsOrganizationAdapter {
|
|
|
438
463
|
canClaimEmailDomain?: boolean;
|
|
439
464
|
}>;
|
|
440
465
|
fetchWorkspaces: () => Promise<OrganizationWorkspaceItem[]>;
|
|
466
|
+
/**
|
|
467
|
+
* Optional: the organization's shared workspaces the viewer isn't in yet —
|
|
468
|
+
* the workspace picker's list. When given (with `joinWorkspaces`), org
|
|
469
|
+
* members see them under Organization › Workspaces and can join any of them
|
|
470
|
+
* as a member at any time, not only at first sign-in.
|
|
471
|
+
*/
|
|
472
|
+
fetchJoinableWorkspaces?: () => Promise<OrganizationJoinableWorkspace[]>;
|
|
473
|
+
/** Optional: join those workspaces as a member. Resolves to the ids joined. */
|
|
474
|
+
joinWorkspaces?: (workspaceIds: string[]) => Promise<string[]>;
|
|
441
475
|
fetchJoinRequests: () => Promise<OrganizationJoinRequest[]>;
|
|
442
476
|
approveJoinRequest: (requestId: string) => Promise<void>;
|
|
443
477
|
rejectJoinRequest: (requestId: string) => Promise<void>;
|
|
@@ -961,7 +995,7 @@ interface WorkspaceListGroup {
|
|
|
961
995
|
* last. Groups keep the order the organizations came in.
|
|
962
996
|
*/
|
|
963
997
|
declare function groupWorkspaceList(workspaces: WorkspaceInfo[], organizations?: WorkspaceListOrganization[]): WorkspaceListGroup[];
|
|
964
|
-
declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreateClick, onEditClick, onSwitchClick, onLeaveClick, fetchPlans, organizations, pageSize, }: {
|
|
998
|
+
declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreateClick, onEditClick, onSwitchClick, onLeaveClick, fetchPlans, organizations, pageSize, listPage, reloadKey, }: {
|
|
965
999
|
workspaces: WorkspaceInfo[];
|
|
966
1000
|
loading: boolean;
|
|
967
1001
|
onCreateClick: () => void;
|
|
@@ -973,6 +1007,18 @@ declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreat
|
|
|
973
1007
|
/** The viewer's organizations, to group the list under. */
|
|
974
1008
|
organizations?: WorkspaceListOrganization[];
|
|
975
1009
|
pageSize?: number;
|
|
1010
|
+
/** One page from the API (see SettingsWorkspaceAdapter.listPage). When
|
|
1011
|
+
* given, each page is fetched as it is shown and rendered as returned. */
|
|
1012
|
+
listPage?: (params: {
|
|
1013
|
+
limit: number;
|
|
1014
|
+
offset: number;
|
|
1015
|
+
}) => Promise<{
|
|
1016
|
+
items: WorkspaceInfo[];
|
|
1017
|
+
total: number;
|
|
1018
|
+
}>;
|
|
1019
|
+
/** Changes whenever the host's list changes (a leave, a rename…), so the
|
|
1020
|
+
* page on screen is fetched again. */
|
|
1021
|
+
reloadKey?: string;
|
|
976
1022
|
}): react.JSX.Element;
|
|
977
1023
|
/**
|
|
978
1024
|
* @deprecated Renamed to `WorkspaceListTab` in 0.4.0 — the tab is a workspace
|
|
@@ -1439,4 +1485,4 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1439
1485
|
*/
|
|
1440
1486
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1441
1487
|
|
|
1442
|
-
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, DEFAULT_USER_LANGUAGE, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrganizationContent, type OrganizationData, type OrganizationInvite, type OrganizationJoinRequest, type OrganizationMember, OrganizationMemberModal, type OrganizationMemberModalProps, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, USER_LANGUAGES, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserLanguage, type UserPermissions, WORKSPACE_LIST_PAGE_SIZE, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, type WorkspaceListOrganization, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, type WorkspaceOrganization, type WorkspaceOrganizationRequest, WorkspacePicker, type WorkspacePickerItem, type WorkspacePickerProps, WorkspaceTab, type WorkspaceUsageResponse, countLabel, groupWorkspaceList, loadWorkspaceOrganization, resolveSettingsTabFromPath, useSettingsAdapters, useWorkspaceOrganization, userLanguageLabel };
|
|
1488
|
+
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, DEFAULT_USER_LANGUAGE, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrganizationContent, type OrganizationData, type OrganizationInvite, type OrganizationJoinRequest, type OrganizationJoinableWorkspace, type OrganizationMember, OrganizationMemberModal, type OrganizationMemberModalProps, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, USER_LANGUAGES, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserLanguage, type UserPermissions, WORKSPACE_LIST_PAGE_SIZE, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, type WorkspaceListOrganization, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, type WorkspaceOrganization, type WorkspaceOrganizationRequest, WorkspacePicker, type WorkspacePickerItem, type WorkspacePickerProps, WorkspaceTab, type WorkspaceUsageResponse, countLabel, groupWorkspaceList, loadWorkspaceOrganization, resolveSettingsTabFromPath, useSettingsAdapters, useWorkspaceOrganization, userLanguageLabel };
|
package/dist/index.d.ts
CHANGED
|
@@ -182,6 +182,9 @@ interface SettingsWorkspaceListItem {
|
|
|
182
182
|
/** The organization this workspace belongs to, if any. My workspaces groups
|
|
183
183
|
* the list under each organization (named from `organization.list()`). */
|
|
184
184
|
organizationId?: string;
|
|
185
|
+
/** The organization's name, when the host has it (used by `listPage()`
|
|
186
|
+
* rows whose organization isn't in `organization.list()`). */
|
|
187
|
+
organizationName?: string;
|
|
185
188
|
}
|
|
186
189
|
interface SettingsWorkspaceAdapter {
|
|
187
190
|
/** Same authenticated transport used by the sidebar owner lookup. */
|
|
@@ -240,6 +243,20 @@ interface SettingsWorkspaceAdapter {
|
|
|
240
243
|
* When omitted, the plan on each `list()` item is used as before.
|
|
241
244
|
*/
|
|
242
245
|
fetchPlans?: (workspaceIds: string[]) => Promise<Record<string, string>>;
|
|
246
|
+
/**
|
|
247
|
+
* Optional: one page of the workspace list, from the API
|
|
248
|
+
* (`GET /workspace?limit=&offset=`). When given, My workspaces asks for each
|
|
249
|
+
* page as it is shown and renders exactly what comes back — `total` is every
|
|
250
|
+
* workspace the user can see. When omitted (or when a page request fails),
|
|
251
|
+
* My workspaces pages through `list()` in the browser as before.
|
|
252
|
+
*/
|
|
253
|
+
listPage?: (params: {
|
|
254
|
+
limit: number;
|
|
255
|
+
offset: number;
|
|
256
|
+
}) => Promise<{
|
|
257
|
+
items: SettingsWorkspaceListItem[];
|
|
258
|
+
total: number;
|
|
259
|
+
}>;
|
|
243
260
|
/**
|
|
244
261
|
* Optional: host-controlled refresh after the package mutates workspace
|
|
245
262
|
* state. If provided, the package will call this instead of (or in addition
|
|
@@ -349,6 +366,14 @@ interface OrganizationWorkspaceItem {
|
|
|
349
366
|
imageUrl?: string;
|
|
350
367
|
orgVisibility: "private" | "shared";
|
|
351
368
|
}
|
|
369
|
+
/** A shared workspace in the organization that the viewer isn't in yet. */
|
|
370
|
+
interface OrganizationJoinableWorkspace {
|
|
371
|
+
_id: string;
|
|
372
|
+
name: string;
|
|
373
|
+
imageUrl?: string;
|
|
374
|
+
/** Who created it, shown under the name. */
|
|
375
|
+
ownerName?: string;
|
|
376
|
+
}
|
|
352
377
|
interface OrganizationJoinRequest {
|
|
353
378
|
_id: string;
|
|
354
379
|
workspace: {
|
|
@@ -438,6 +463,15 @@ interface SettingsOrganizationAdapter {
|
|
|
438
463
|
canClaimEmailDomain?: boolean;
|
|
439
464
|
}>;
|
|
440
465
|
fetchWorkspaces: () => Promise<OrganizationWorkspaceItem[]>;
|
|
466
|
+
/**
|
|
467
|
+
* Optional: the organization's shared workspaces the viewer isn't in yet —
|
|
468
|
+
* the workspace picker's list. When given (with `joinWorkspaces`), org
|
|
469
|
+
* members see them under Organization › Workspaces and can join any of them
|
|
470
|
+
* as a member at any time, not only at first sign-in.
|
|
471
|
+
*/
|
|
472
|
+
fetchJoinableWorkspaces?: () => Promise<OrganizationJoinableWorkspace[]>;
|
|
473
|
+
/** Optional: join those workspaces as a member. Resolves to the ids joined. */
|
|
474
|
+
joinWorkspaces?: (workspaceIds: string[]) => Promise<string[]>;
|
|
441
475
|
fetchJoinRequests: () => Promise<OrganizationJoinRequest[]>;
|
|
442
476
|
approveJoinRequest: (requestId: string) => Promise<void>;
|
|
443
477
|
rejectJoinRequest: (requestId: string) => Promise<void>;
|
|
@@ -961,7 +995,7 @@ interface WorkspaceListGroup {
|
|
|
961
995
|
* last. Groups keep the order the organizations came in.
|
|
962
996
|
*/
|
|
963
997
|
declare function groupWorkspaceList(workspaces: WorkspaceInfo[], organizations?: WorkspaceListOrganization[]): WorkspaceListGroup[];
|
|
964
|
-
declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreateClick, onEditClick, onSwitchClick, onLeaveClick, fetchPlans, organizations, pageSize, }: {
|
|
998
|
+
declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreateClick, onEditClick, onSwitchClick, onLeaveClick, fetchPlans, organizations, pageSize, listPage, reloadKey, }: {
|
|
965
999
|
workspaces: WorkspaceInfo[];
|
|
966
1000
|
loading: boolean;
|
|
967
1001
|
onCreateClick: () => void;
|
|
@@ -973,6 +1007,18 @@ declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreat
|
|
|
973
1007
|
/** The viewer's organizations, to group the list under. */
|
|
974
1008
|
organizations?: WorkspaceListOrganization[];
|
|
975
1009
|
pageSize?: number;
|
|
1010
|
+
/** One page from the API (see SettingsWorkspaceAdapter.listPage). When
|
|
1011
|
+
* given, each page is fetched as it is shown and rendered as returned. */
|
|
1012
|
+
listPage?: (params: {
|
|
1013
|
+
limit: number;
|
|
1014
|
+
offset: number;
|
|
1015
|
+
}) => Promise<{
|
|
1016
|
+
items: WorkspaceInfo[];
|
|
1017
|
+
total: number;
|
|
1018
|
+
}>;
|
|
1019
|
+
/** Changes whenever the host's list changes (a leave, a rename…), so the
|
|
1020
|
+
* page on screen is fetched again. */
|
|
1021
|
+
reloadKey?: string;
|
|
976
1022
|
}): react.JSX.Element;
|
|
977
1023
|
/**
|
|
978
1024
|
* @deprecated Renamed to `WorkspaceListTab` in 0.4.0 — the tab is a workspace
|
|
@@ -1439,4 +1485,4 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1439
1485
|
*/
|
|
1440
1486
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1441
1487
|
|
|
1442
|
-
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, DEFAULT_USER_LANGUAGE, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrganizationContent, type OrganizationData, type OrganizationInvite, type OrganizationJoinRequest, type OrganizationMember, OrganizationMemberModal, type OrganizationMemberModalProps, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, USER_LANGUAGES, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserLanguage, type UserPermissions, WORKSPACE_LIST_PAGE_SIZE, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, type WorkspaceListOrganization, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, type WorkspaceOrganization, type WorkspaceOrganizationRequest, WorkspacePicker, type WorkspacePickerItem, type WorkspacePickerProps, WorkspaceTab, type WorkspaceUsageResponse, countLabel, groupWorkspaceList, loadWorkspaceOrganization, resolveSettingsTabFromPath, useSettingsAdapters, useWorkspaceOrganization, userLanguageLabel };
|
|
1488
|
+
export { APP_KEYS, type ApiToken, type AppKey, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, DEFAULT_USER_LANGUAGE, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrganizationContent, type OrganizationData, type OrganizationInvite, type OrganizationJoinRequest, type OrganizationJoinableWorkspace, type OrganizationMember, OrganizationMemberModal, type OrganizationMemberModalProps, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, USER_LANGUAGES, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserLanguage, type UserPermissions, WORKSPACE_LIST_PAGE_SIZE, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, type WorkspaceListOrganization, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, type WorkspaceOrganization, type WorkspaceOrganizationRequest, WorkspacePicker, type WorkspacePickerItem, type WorkspacePickerProps, WorkspaceTab, type WorkspaceUsageResponse, countLabel, groupWorkspaceList, loadWorkspaceOrganization, resolveSettingsTabFromPath, useSettingsAdapters, useWorkspaceOrganization, userLanguageLabel };
|
package/dist/index.js
CHANGED
|
@@ -6174,6 +6174,79 @@ function WorkspaceRow({ workspace }) {
|
|
|
6174
6174
|
}
|
|
6175
6175
|
);
|
|
6176
6176
|
}
|
|
6177
|
+
function JoinableWorkspaceRow({
|
|
6178
|
+
workspace,
|
|
6179
|
+
joining,
|
|
6180
|
+
onJoin
|
|
6181
|
+
}) {
|
|
6182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6183
|
+
"div",
|
|
6184
|
+
{
|
|
6185
|
+
className: "flex items-center self-stretch shrink-0",
|
|
6186
|
+
style: {
|
|
6187
|
+
borderBottom: `1px solid ${T11.borderSubtle}`,
|
|
6188
|
+
padding: `${T11.spXl} ${T11.sp3xl}`,
|
|
6189
|
+
gap: T11.sp6xl
|
|
6190
|
+
},
|
|
6191
|
+
children: [
|
|
6192
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center min-w-0", style: { flex: 1, gap: T11.spMd }, children: [
|
|
6193
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6194
|
+
ProfileAvatar,
|
|
6195
|
+
{
|
|
6196
|
+
name: workspace.name,
|
|
6197
|
+
profileImage: workspace.imageUrl,
|
|
6198
|
+
size: 28,
|
|
6199
|
+
borderRadius: "var(--radius-lg)"
|
|
6200
|
+
}
|
|
6201
|
+
),
|
|
6202
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col min-w-0", children: [
|
|
6203
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6204
|
+
"span",
|
|
6205
|
+
{
|
|
6206
|
+
className: "truncate",
|
|
6207
|
+
style: {
|
|
6208
|
+
fontFamily: T11.font,
|
|
6209
|
+
fontSize: T11.fsSm,
|
|
6210
|
+
fontWeight: 500,
|
|
6211
|
+
lineHeight: T11.lhSm,
|
|
6212
|
+
color: T11.primary
|
|
6213
|
+
},
|
|
6214
|
+
children: workspace.name
|
|
6215
|
+
}
|
|
6216
|
+
),
|
|
6217
|
+
workspace.ownerName && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
6218
|
+
"span",
|
|
6219
|
+
{
|
|
6220
|
+
className: "truncate",
|
|
6221
|
+
style: {
|
|
6222
|
+
fontFamily: T11.font,
|
|
6223
|
+
fontSize: T11.fsXs,
|
|
6224
|
+
fontWeight: 400,
|
|
6225
|
+
lineHeight: T11.lhXs,
|
|
6226
|
+
color: T11.muted
|
|
6227
|
+
},
|
|
6228
|
+
children: [
|
|
6229
|
+
"Created by ",
|
|
6230
|
+
workspace.ownerName
|
|
6231
|
+
]
|
|
6232
|
+
}
|
|
6233
|
+
)
|
|
6234
|
+
] })
|
|
6235
|
+
] }),
|
|
6236
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6237
|
+
import_ui8.ScButton,
|
|
6238
|
+
{
|
|
6239
|
+
text: joining ? "Joining\u2026" : "Join",
|
|
6240
|
+
variant: "secondary",
|
|
6241
|
+
size: "sm",
|
|
6242
|
+
state: joining ? "disabled" : "default",
|
|
6243
|
+
onClick: joining ? void 0 : onJoin
|
|
6244
|
+
}
|
|
6245
|
+
)
|
|
6246
|
+
]
|
|
6247
|
+
}
|
|
6248
|
+
);
|
|
6249
|
+
}
|
|
6177
6250
|
function JoinRequestRow({
|
|
6178
6251
|
request,
|
|
6179
6252
|
onApprove,
|
|
@@ -6293,10 +6366,13 @@ function OrganizationContent({
|
|
|
6293
6366
|
embedded = false,
|
|
6294
6367
|
view = "people"
|
|
6295
6368
|
} = {}) {
|
|
6296
|
-
const { organization, toast } = useSettingsAdapters();
|
|
6369
|
+
const { organization, workspace: workspaceAdapter, toast } = useSettingsAdapters();
|
|
6297
6370
|
const current = organization.current;
|
|
6298
6371
|
const [members, setMembers] = (0, import_react12.useState)([]);
|
|
6299
6372
|
const [workspaces, setWorkspaces] = (0, import_react12.useState)([]);
|
|
6373
|
+
const canJoinShared = current?.role === "member" && !!organization.fetchJoinableWorkspaces && !!organization.joinWorkspaces;
|
|
6374
|
+
const [joinable, setJoinable] = (0, import_react12.useState)([]);
|
|
6375
|
+
const [joiningId, setJoiningId] = (0, import_react12.useState)(null);
|
|
6300
6376
|
const [joinRequests, setJoinRequests] = (0, import_react12.useState)([]);
|
|
6301
6377
|
const [highestRole, setHighestRole] = (0, import_react12.useState)("guest");
|
|
6302
6378
|
const [searchQuery, setSearchQuery] = (0, import_react12.useState)("");
|
|
@@ -6306,12 +6382,20 @@ function OrganizationContent({
|
|
|
6306
6382
|
if (!organization.current) return;
|
|
6307
6383
|
setLoadingData(true);
|
|
6308
6384
|
try {
|
|
6309
|
-
const [
|
|
6385
|
+
const [
|
|
6386
|
+
membersRes,
|
|
6387
|
+
workspacesRes,
|
|
6388
|
+
joinRequestsRes,
|
|
6389
|
+
highestRoleRes,
|
|
6390
|
+
joinableRes
|
|
6391
|
+
] = await Promise.all([
|
|
6310
6392
|
organization.fetchMembers().catch(() => null),
|
|
6311
6393
|
organization.fetchWorkspaces().catch(() => null),
|
|
6312
6394
|
organization.fetchJoinRequests().catch(() => null),
|
|
6313
|
-
organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null)
|
|
6395
|
+
organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null),
|
|
6396
|
+
canJoinShared ? organization.fetchJoinableWorkspaces().catch(() => null) : Promise.resolve(null)
|
|
6314
6397
|
]);
|
|
6398
|
+
if (joinableRes) setJoinable(joinableRes);
|
|
6315
6399
|
if (highestRoleRes?.role) setHighestRole(highestRoleRes.role);
|
|
6316
6400
|
if (membersRes) setMembers(membersRes.filter((m) => m?.user));
|
|
6317
6401
|
if (workspacesRes) setWorkspaces(workspacesRes);
|
|
@@ -6320,10 +6404,30 @@ function OrganizationContent({
|
|
|
6320
6404
|
} finally {
|
|
6321
6405
|
setLoadingData(false);
|
|
6322
6406
|
}
|
|
6323
|
-
}, [organization]);
|
|
6407
|
+
}, [organization, canJoinShared]);
|
|
6324
6408
|
(0, import_react12.useEffect)(() => {
|
|
6325
6409
|
fetchData();
|
|
6326
6410
|
}, [fetchData]);
|
|
6411
|
+
const handleJoinWorkspace = async (target) => {
|
|
6412
|
+
if (!organization.joinWorkspaces) return;
|
|
6413
|
+
setJoiningId(target._id);
|
|
6414
|
+
try {
|
|
6415
|
+
const joined = await organization.joinWorkspaces([target._id]);
|
|
6416
|
+
if (!joined.includes(target._id)) {
|
|
6417
|
+
toast.error(`Couldn't join ${target.name}. Try again.`);
|
|
6418
|
+
return;
|
|
6419
|
+
}
|
|
6420
|
+
toast.success(`Joined ${target.name}`);
|
|
6421
|
+
await workspaceAdapter.refresh?.().catch(() => void 0);
|
|
6422
|
+
await fetchData();
|
|
6423
|
+
} catch (err) {
|
|
6424
|
+
toast.error(
|
|
6425
|
+
err instanceof Error ? err.message : `Couldn't join ${target.name}`
|
|
6426
|
+
);
|
|
6427
|
+
} finally {
|
|
6428
|
+
setJoiningId(null);
|
|
6429
|
+
}
|
|
6430
|
+
};
|
|
6327
6431
|
const [manageModalOpen, setManageModalOpen] = (0, import_react12.useState)(false);
|
|
6328
6432
|
const handleUpdateOrganization = async (name, imageFile) => {
|
|
6329
6433
|
if (!current) return false;
|
|
@@ -6552,6 +6656,23 @@ function OrganizationContent({
|
|
|
6552
6656
|
children: workspaces.map((ws) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(WorkspaceRow, { workspace: ws }, ws._id))
|
|
6553
6657
|
}
|
|
6554
6658
|
),
|
|
6659
|
+
canJoinShared && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6660
|
+
Section,
|
|
6661
|
+
{
|
|
6662
|
+
title: "Shared workspaces you can join",
|
|
6663
|
+
empty: joinable.length === 0,
|
|
6664
|
+
emptyText: "You're in every shared workspace in this organization",
|
|
6665
|
+
children: joinable.map((ws) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6666
|
+
JoinableWorkspaceRow,
|
|
6667
|
+
{
|
|
6668
|
+
workspace: ws,
|
|
6669
|
+
joining: joiningId === ws._id,
|
|
6670
|
+
onJoin: () => void handleJoinWorkspace(ws)
|
|
6671
|
+
},
|
|
6672
|
+
ws._id
|
|
6673
|
+
))
|
|
6674
|
+
}
|
|
6675
|
+
),
|
|
6555
6676
|
(isOrgAdmin || joinRequests.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
6556
6677
|
Section,
|
|
6557
6678
|
{
|
|
@@ -10938,26 +11059,59 @@ function WorkspaceListTab({
|
|
|
10938
11059
|
onLeaveClick,
|
|
10939
11060
|
fetchPlans,
|
|
10940
11061
|
organizations = [],
|
|
10941
|
-
pageSize = WORKSPACE_LIST_PAGE_SIZE
|
|
11062
|
+
pageSize = WORKSPACE_LIST_PAGE_SIZE,
|
|
11063
|
+
listPage,
|
|
11064
|
+
reloadKey
|
|
10942
11065
|
}) {
|
|
10943
11066
|
const currentWorkspace = workspaces.find((ws) => ws.isCurrent);
|
|
10944
|
-
const
|
|
11067
|
+
const currentOrganization = organizations.find(
|
|
11068
|
+
(org) => org._id && org._id === currentWorkspace?.organizationId
|
|
11069
|
+
);
|
|
11070
|
+
const [page, setPage] = (0, import_react17.useState)(0);
|
|
11071
|
+
const [serverPage, setServerPage] = (0, import_react17.useState)(null);
|
|
11072
|
+
const [serverFailed, setServerFailed] = (0, import_react17.useState)(false);
|
|
11073
|
+
const serverMode = !!listPage && !serverFailed;
|
|
11074
|
+
(0, import_react17.useEffect)(() => {
|
|
11075
|
+
if (!listPage || serverFailed) return;
|
|
11076
|
+
let cancelled = false;
|
|
11077
|
+
listPage({ limit: pageSize, offset: page * pageSize }).then((result) => {
|
|
11078
|
+
if (cancelled) return;
|
|
11079
|
+
const lastPage = Math.max(0, Math.ceil(result.total / pageSize) - 1);
|
|
11080
|
+
if (page > lastPage) {
|
|
11081
|
+
setPage(lastPage);
|
|
11082
|
+
return;
|
|
11083
|
+
}
|
|
11084
|
+
setServerPage({ page, items: result.items, total: result.total });
|
|
11085
|
+
}).catch(() => {
|
|
11086
|
+
if (!cancelled) setServerFailed(true);
|
|
11087
|
+
});
|
|
11088
|
+
return () => {
|
|
11089
|
+
cancelled = true;
|
|
11090
|
+
};
|
|
11091
|
+
}, [listPage, serverFailed, page, pageSize, reloadKey]);
|
|
11092
|
+
const organizationLabel = (org) => org.role === "guest" ? `${org.name} \xB7 Guest` : org.name;
|
|
11093
|
+
const serverGroupOf = (ws) => {
|
|
11094
|
+
const org = organizations.find((o) => o._id === ws.organizationId);
|
|
11095
|
+
if (org) return { key: org._id, label: organizationLabel(org), workspaces: [] };
|
|
11096
|
+
if (ws.organizationId && ws.organizationName) {
|
|
11097
|
+
return { key: ws.organizationId, label: ws.organizationName, workspaces: [] };
|
|
11098
|
+
}
|
|
11099
|
+
return { key: "__no_org__", label: "No organization", workspaces: [] };
|
|
11100
|
+
};
|
|
11101
|
+
const groups = serverMode ? [] : groupWorkspaceList(
|
|
10945
11102
|
workspaces.filter((ws) => !ws.isCurrent),
|
|
10946
11103
|
organizations
|
|
10947
11104
|
);
|
|
10948
11105
|
const rows = groups.flatMap(
|
|
10949
11106
|
(group) => group.workspaces.map((ws) => ({ ws, group }))
|
|
10950
11107
|
);
|
|
10951
|
-
const
|
|
10952
|
-
const
|
|
10953
|
-
|
|
10954
|
-
);
|
|
10955
|
-
const pageCount = Math.max(1, Math.ceil(otherWorkspaces.length / pageSize));
|
|
10956
|
-
const [page, setPage] = (0, import_react17.useState)(0);
|
|
10957
|
-
const safePage = Math.min(page, pageCount - 1);
|
|
11108
|
+
const listTotal = serverMode ? serverPage?.total ?? 0 : rows.length;
|
|
11109
|
+
const pageCount = Math.max(1, Math.ceil(listTotal / pageSize));
|
|
11110
|
+
const safePage = serverMode ? serverPage?.page ?? 0 : Math.min(page, pageCount - 1);
|
|
10958
11111
|
const pageStart = safePage * pageSize;
|
|
10959
|
-
const pageRows = rows.slice(pageStart, pageStart + pageSize);
|
|
11112
|
+
const pageRows = serverMode ? (serverPage?.items ?? []).map((ws) => ({ ws, group: serverGroupOf(ws) })) : rows.slice(pageStart, pageStart + pageSize);
|
|
10960
11113
|
const pageWorkspaces = pageRows.map((row) => row.ws);
|
|
11114
|
+
const listLoading = loading || serverMode && !serverPage;
|
|
10961
11115
|
const [plans, setPlans] = (0, import_react17.useState)({});
|
|
10962
11116
|
const requestedPlans = (0, import_react17.useRef)(/* @__PURE__ */ new Set());
|
|
10963
11117
|
const visibleIds = [
|
|
@@ -10973,7 +11127,7 @@ function WorkspaceListTab({
|
|
|
10973
11127
|
};
|
|
10974
11128
|
}, []);
|
|
10975
11129
|
(0, import_react17.useEffect)(() => {
|
|
10976
|
-
if (!fetchPlans ||
|
|
11130
|
+
if (!fetchPlans || listLoading) return;
|
|
10977
11131
|
const missing = visibleKey.split(",").filter((id) => id && !requestedPlans.current.has(id));
|
|
10978
11132
|
if (!missing.length) return;
|
|
10979
11133
|
missing.forEach((id) => requestedPlans.current.add(id));
|
|
@@ -10981,7 +11135,7 @@ function WorkspaceListTab({
|
|
|
10981
11135
|
if (mounted.current) setPlans((prev) => ({ ...prev, ...found }));
|
|
10982
11136
|
}).catch(() => {
|
|
10983
11137
|
});
|
|
10984
|
-
}, [fetchPlans,
|
|
11138
|
+
}, [fetchPlans, listLoading, visibleKey]);
|
|
10985
11139
|
const planOf = (ws) => fetchPlans ? plans[ws._id] ?? "" : ws.plan ?? "";
|
|
10986
11140
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
10987
11141
|
"div",
|
|
@@ -11002,7 +11156,7 @@ function WorkspaceListTab({
|
|
|
11002
11156
|
children: "Switching changes which workspace the rest of Settings acts on."
|
|
11003
11157
|
}
|
|
11004
11158
|
),
|
|
11005
|
-
|
|
11159
|
+
listLoading && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
11006
11160
|
"p",
|
|
11007
11161
|
{
|
|
11008
11162
|
style: {
|
|
@@ -11013,7 +11167,7 @@ function WorkspaceListTab({
|
|
|
11013
11167
|
children: "Loading workspaces\u2026"
|
|
11014
11168
|
}
|
|
11015
11169
|
),
|
|
11016
|
-
!
|
|
11170
|
+
!listLoading && currentWorkspace && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
11017
11171
|
"div",
|
|
11018
11172
|
{
|
|
11019
11173
|
className: "flex flex-col items-start shrink-0 w-full",
|
|
@@ -11053,7 +11207,7 @@ function WorkspaceListTab({
|
|
|
11053
11207
|
]
|
|
11054
11208
|
}
|
|
11055
11209
|
),
|
|
11056
|
-
!
|
|
11210
|
+
!listLoading && currentWorkspace && listTotal > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
11057
11211
|
"div",
|
|
11058
11212
|
{
|
|
11059
11213
|
className: "shrink-0 w-full",
|
|
@@ -11063,7 +11217,7 @@ function WorkspaceListTab({
|
|
|
11063
11217
|
}
|
|
11064
11218
|
}
|
|
11065
11219
|
),
|
|
11066
|
-
!
|
|
11220
|
+
!listLoading && listTotal > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
11067
11221
|
"div",
|
|
11068
11222
|
{
|
|
11069
11223
|
className: "flex flex-col items-start flex-1 min-h-0 w-full",
|
|
@@ -11099,8 +11253,8 @@ function WorkspaceListTab({
|
|
|
11099
11253
|
role: ws.role,
|
|
11100
11254
|
plan: planOf(ws),
|
|
11101
11255
|
ownerId: ws.ownerEmail,
|
|
11102
|
-
type: "otherWS",
|
|
11103
|
-
onSwitch: () => onSwitchClick(ws),
|
|
11256
|
+
type: ws.isCurrent ? "currentWS" : "otherWS",
|
|
11257
|
+
onSwitch: ws.isCurrent ? void 0 : () => onSwitchClick(ws),
|
|
11104
11258
|
onSettings: () => onEditClick(ws),
|
|
11105
11259
|
onLeave: () => onLeaveClick(ws)
|
|
11106
11260
|
}
|
|
@@ -11129,7 +11283,7 @@ function WorkspaceListTab({
|
|
|
11129
11283
|
pageStart + pageWorkspaces.length,
|
|
11130
11284
|
" of",
|
|
11131
11285
|
" ",
|
|
11132
|
-
|
|
11286
|
+
listTotal
|
|
11133
11287
|
]
|
|
11134
11288
|
}
|
|
11135
11289
|
),
|
|
@@ -11303,6 +11457,24 @@ function SettingsContentInner({
|
|
|
11303
11457
|
(0, import_react17.useEffect)(() => {
|
|
11304
11458
|
void refreshWorkspaceList();
|
|
11305
11459
|
}, [refreshWorkspaceList]);
|
|
11460
|
+
const hostListPage = workspace.listPage;
|
|
11461
|
+
const listWorkspacePage = (0, import_react17.useMemo)(
|
|
11462
|
+
() => hostListPage ? async (params) => {
|
|
11463
|
+
const result = await hostListPage(params);
|
|
11464
|
+
return {
|
|
11465
|
+
total: result.total,
|
|
11466
|
+
items: result.items.map(
|
|
11467
|
+
(it) => ({
|
|
11468
|
+
...it,
|
|
11469
|
+
isCurrent: it.isCurrent ?? it._id === workspaceId,
|
|
11470
|
+
imageUrl: it.imageUrl ?? it.image,
|
|
11471
|
+
initials: deriveInitials(it.name)
|
|
11472
|
+
})
|
|
11473
|
+
)
|
|
11474
|
+
};
|
|
11475
|
+
} : void 0,
|
|
11476
|
+
[hostListPage, workspaceId]
|
|
11477
|
+
);
|
|
11306
11478
|
const [listOrganizations, setListOrganizations] = (0, import_react17.useState)([]);
|
|
11307
11479
|
(0, import_react17.useEffect)(() => {
|
|
11308
11480
|
if (activeTab !== "workspaceList" || typeof organization?.list !== "function") {
|
|
@@ -11976,6 +12148,8 @@ function SettingsContentInner({
|
|
|
11976
12148
|
loading: workspaceListLoading && workspaceList.length === 0,
|
|
11977
12149
|
fetchPlans: workspace.fetchPlans,
|
|
11978
12150
|
organizations: listOrganizations,
|
|
12151
|
+
listPage: listWorkspacePage,
|
|
12152
|
+
reloadKey: displayWorkspaces.map((ws) => `${ws._id}:${ws.name}:${ws.role}`).join(","),
|
|
11979
12153
|
onCreateClick: handleCreateClick,
|
|
11980
12154
|
onEditClick: handleEditClick,
|
|
11981
12155
|
onSwitchClick: async (ws) => {
|
package/dist/index.mjs
CHANGED
|
@@ -167,7 +167,8 @@ import {
|
|
|
167
167
|
useState as useState15,
|
|
168
168
|
useEffect as useEffect13,
|
|
169
169
|
useRef as useRef7,
|
|
170
|
-
useCallback as useCallback7
|
|
170
|
+
useCallback as useCallback7,
|
|
171
|
+
useMemo as useMemo3
|
|
171
172
|
} from "react";
|
|
172
173
|
import {
|
|
173
174
|
ScSidebarMenu,
|
|
@@ -6150,6 +6151,79 @@ function WorkspaceRow({ workspace }) {
|
|
|
6150
6151
|
}
|
|
6151
6152
|
);
|
|
6152
6153
|
}
|
|
6154
|
+
function JoinableWorkspaceRow({
|
|
6155
|
+
workspace,
|
|
6156
|
+
joining,
|
|
6157
|
+
onJoin
|
|
6158
|
+
}) {
|
|
6159
|
+
return /* @__PURE__ */ jsxs14(
|
|
6160
|
+
"div",
|
|
6161
|
+
{
|
|
6162
|
+
className: "flex items-center self-stretch shrink-0",
|
|
6163
|
+
style: {
|
|
6164
|
+
borderBottom: `1px solid ${T11.borderSubtle}`,
|
|
6165
|
+
padding: `${T11.spXl} ${T11.sp3xl}`,
|
|
6166
|
+
gap: T11.sp6xl
|
|
6167
|
+
},
|
|
6168
|
+
children: [
|
|
6169
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center min-w-0", style: { flex: 1, gap: T11.spMd }, children: [
|
|
6170
|
+
/* @__PURE__ */ jsx17(
|
|
6171
|
+
ProfileAvatar,
|
|
6172
|
+
{
|
|
6173
|
+
name: workspace.name,
|
|
6174
|
+
profileImage: workspace.imageUrl,
|
|
6175
|
+
size: 28,
|
|
6176
|
+
borderRadius: "var(--radius-lg)"
|
|
6177
|
+
}
|
|
6178
|
+
),
|
|
6179
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex flex-col min-w-0", children: [
|
|
6180
|
+
/* @__PURE__ */ jsx17(
|
|
6181
|
+
"span",
|
|
6182
|
+
{
|
|
6183
|
+
className: "truncate",
|
|
6184
|
+
style: {
|
|
6185
|
+
fontFamily: T11.font,
|
|
6186
|
+
fontSize: T11.fsSm,
|
|
6187
|
+
fontWeight: 500,
|
|
6188
|
+
lineHeight: T11.lhSm,
|
|
6189
|
+
color: T11.primary
|
|
6190
|
+
},
|
|
6191
|
+
children: workspace.name
|
|
6192
|
+
}
|
|
6193
|
+
),
|
|
6194
|
+
workspace.ownerName && /* @__PURE__ */ jsxs14(
|
|
6195
|
+
"span",
|
|
6196
|
+
{
|
|
6197
|
+
className: "truncate",
|
|
6198
|
+
style: {
|
|
6199
|
+
fontFamily: T11.font,
|
|
6200
|
+
fontSize: T11.fsXs,
|
|
6201
|
+
fontWeight: 400,
|
|
6202
|
+
lineHeight: T11.lhXs,
|
|
6203
|
+
color: T11.muted
|
|
6204
|
+
},
|
|
6205
|
+
children: [
|
|
6206
|
+
"Created by ",
|
|
6207
|
+
workspace.ownerName
|
|
6208
|
+
]
|
|
6209
|
+
}
|
|
6210
|
+
)
|
|
6211
|
+
] })
|
|
6212
|
+
] }),
|
|
6213
|
+
/* @__PURE__ */ jsx17(
|
|
6214
|
+
ScButton5,
|
|
6215
|
+
{
|
|
6216
|
+
text: joining ? "Joining\u2026" : "Join",
|
|
6217
|
+
variant: "secondary",
|
|
6218
|
+
size: "sm",
|
|
6219
|
+
state: joining ? "disabled" : "default",
|
|
6220
|
+
onClick: joining ? void 0 : onJoin
|
|
6221
|
+
}
|
|
6222
|
+
)
|
|
6223
|
+
]
|
|
6224
|
+
}
|
|
6225
|
+
);
|
|
6226
|
+
}
|
|
6153
6227
|
function JoinRequestRow({
|
|
6154
6228
|
request,
|
|
6155
6229
|
onApprove,
|
|
@@ -6269,10 +6343,13 @@ function OrganizationContent({
|
|
|
6269
6343
|
embedded = false,
|
|
6270
6344
|
view = "people"
|
|
6271
6345
|
} = {}) {
|
|
6272
|
-
const { organization, toast } = useSettingsAdapters();
|
|
6346
|
+
const { organization, workspace: workspaceAdapter, toast } = useSettingsAdapters();
|
|
6273
6347
|
const current = organization.current;
|
|
6274
6348
|
const [members, setMembers] = useState10([]);
|
|
6275
6349
|
const [workspaces, setWorkspaces] = useState10([]);
|
|
6350
|
+
const canJoinShared = current?.role === "member" && !!organization.fetchJoinableWorkspaces && !!organization.joinWorkspaces;
|
|
6351
|
+
const [joinable, setJoinable] = useState10([]);
|
|
6352
|
+
const [joiningId, setJoiningId] = useState10(null);
|
|
6276
6353
|
const [joinRequests, setJoinRequests] = useState10([]);
|
|
6277
6354
|
const [highestRole, setHighestRole] = useState10("guest");
|
|
6278
6355
|
const [searchQuery, setSearchQuery] = useState10("");
|
|
@@ -6282,12 +6359,20 @@ function OrganizationContent({
|
|
|
6282
6359
|
if (!organization.current) return;
|
|
6283
6360
|
setLoadingData(true);
|
|
6284
6361
|
try {
|
|
6285
|
-
const [
|
|
6362
|
+
const [
|
|
6363
|
+
membersRes,
|
|
6364
|
+
workspacesRes,
|
|
6365
|
+
joinRequestsRes,
|
|
6366
|
+
highestRoleRes,
|
|
6367
|
+
joinableRes
|
|
6368
|
+
] = await Promise.all([
|
|
6286
6369
|
organization.fetchMembers().catch(() => null),
|
|
6287
6370
|
organization.fetchWorkspaces().catch(() => null),
|
|
6288
6371
|
organization.fetchJoinRequests().catch(() => null),
|
|
6289
|
-
organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null)
|
|
6372
|
+
organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null),
|
|
6373
|
+
canJoinShared ? organization.fetchJoinableWorkspaces().catch(() => null) : Promise.resolve(null)
|
|
6290
6374
|
]);
|
|
6375
|
+
if (joinableRes) setJoinable(joinableRes);
|
|
6291
6376
|
if (highestRoleRes?.role) setHighestRole(highestRoleRes.role);
|
|
6292
6377
|
if (membersRes) setMembers(membersRes.filter((m) => m?.user));
|
|
6293
6378
|
if (workspacesRes) setWorkspaces(workspacesRes);
|
|
@@ -6296,10 +6381,30 @@ function OrganizationContent({
|
|
|
6296
6381
|
} finally {
|
|
6297
6382
|
setLoadingData(false);
|
|
6298
6383
|
}
|
|
6299
|
-
}, [organization]);
|
|
6384
|
+
}, [organization, canJoinShared]);
|
|
6300
6385
|
useEffect10(() => {
|
|
6301
6386
|
fetchData();
|
|
6302
6387
|
}, [fetchData]);
|
|
6388
|
+
const handleJoinWorkspace = async (target) => {
|
|
6389
|
+
if (!organization.joinWorkspaces) return;
|
|
6390
|
+
setJoiningId(target._id);
|
|
6391
|
+
try {
|
|
6392
|
+
const joined = await organization.joinWorkspaces([target._id]);
|
|
6393
|
+
if (!joined.includes(target._id)) {
|
|
6394
|
+
toast.error(`Couldn't join ${target.name}. Try again.`);
|
|
6395
|
+
return;
|
|
6396
|
+
}
|
|
6397
|
+
toast.success(`Joined ${target.name}`);
|
|
6398
|
+
await workspaceAdapter.refresh?.().catch(() => void 0);
|
|
6399
|
+
await fetchData();
|
|
6400
|
+
} catch (err) {
|
|
6401
|
+
toast.error(
|
|
6402
|
+
err instanceof Error ? err.message : `Couldn't join ${target.name}`
|
|
6403
|
+
);
|
|
6404
|
+
} finally {
|
|
6405
|
+
setJoiningId(null);
|
|
6406
|
+
}
|
|
6407
|
+
};
|
|
6303
6408
|
const [manageModalOpen, setManageModalOpen] = useState10(false);
|
|
6304
6409
|
const handleUpdateOrganization = async (name, imageFile) => {
|
|
6305
6410
|
if (!current) return false;
|
|
@@ -6528,6 +6633,23 @@ function OrganizationContent({
|
|
|
6528
6633
|
children: workspaces.map((ws) => /* @__PURE__ */ jsx17(WorkspaceRow, { workspace: ws }, ws._id))
|
|
6529
6634
|
}
|
|
6530
6635
|
),
|
|
6636
|
+
canJoinShared && /* @__PURE__ */ jsx17(
|
|
6637
|
+
Section,
|
|
6638
|
+
{
|
|
6639
|
+
title: "Shared workspaces you can join",
|
|
6640
|
+
empty: joinable.length === 0,
|
|
6641
|
+
emptyText: "You're in every shared workspace in this organization",
|
|
6642
|
+
children: joinable.map((ws) => /* @__PURE__ */ jsx17(
|
|
6643
|
+
JoinableWorkspaceRow,
|
|
6644
|
+
{
|
|
6645
|
+
workspace: ws,
|
|
6646
|
+
joining: joiningId === ws._id,
|
|
6647
|
+
onJoin: () => void handleJoinWorkspace(ws)
|
|
6648
|
+
},
|
|
6649
|
+
ws._id
|
|
6650
|
+
))
|
|
6651
|
+
}
|
|
6652
|
+
),
|
|
6531
6653
|
(isOrgAdmin || joinRequests.length > 0) && /* @__PURE__ */ jsx17(
|
|
6532
6654
|
Section,
|
|
6533
6655
|
{
|
|
@@ -10941,26 +11063,59 @@ function WorkspaceListTab({
|
|
|
10941
11063
|
onLeaveClick,
|
|
10942
11064
|
fetchPlans,
|
|
10943
11065
|
organizations = [],
|
|
10944
|
-
pageSize = WORKSPACE_LIST_PAGE_SIZE
|
|
11066
|
+
pageSize = WORKSPACE_LIST_PAGE_SIZE,
|
|
11067
|
+
listPage,
|
|
11068
|
+
reloadKey
|
|
10945
11069
|
}) {
|
|
10946
11070
|
const currentWorkspace = workspaces.find((ws) => ws.isCurrent);
|
|
10947
|
-
const
|
|
11071
|
+
const currentOrganization = organizations.find(
|
|
11072
|
+
(org) => org._id && org._id === currentWorkspace?.organizationId
|
|
11073
|
+
);
|
|
11074
|
+
const [page, setPage] = useState15(0);
|
|
11075
|
+
const [serverPage, setServerPage] = useState15(null);
|
|
11076
|
+
const [serverFailed, setServerFailed] = useState15(false);
|
|
11077
|
+
const serverMode = !!listPage && !serverFailed;
|
|
11078
|
+
useEffect13(() => {
|
|
11079
|
+
if (!listPage || serverFailed) return;
|
|
11080
|
+
let cancelled = false;
|
|
11081
|
+
listPage({ limit: pageSize, offset: page * pageSize }).then((result) => {
|
|
11082
|
+
if (cancelled) return;
|
|
11083
|
+
const lastPage = Math.max(0, Math.ceil(result.total / pageSize) - 1);
|
|
11084
|
+
if (page > lastPage) {
|
|
11085
|
+
setPage(lastPage);
|
|
11086
|
+
return;
|
|
11087
|
+
}
|
|
11088
|
+
setServerPage({ page, items: result.items, total: result.total });
|
|
11089
|
+
}).catch(() => {
|
|
11090
|
+
if (!cancelled) setServerFailed(true);
|
|
11091
|
+
});
|
|
11092
|
+
return () => {
|
|
11093
|
+
cancelled = true;
|
|
11094
|
+
};
|
|
11095
|
+
}, [listPage, serverFailed, page, pageSize, reloadKey]);
|
|
11096
|
+
const organizationLabel = (org) => org.role === "guest" ? `${org.name} \xB7 Guest` : org.name;
|
|
11097
|
+
const serverGroupOf = (ws) => {
|
|
11098
|
+
const org = organizations.find((o) => o._id === ws.organizationId);
|
|
11099
|
+
if (org) return { key: org._id, label: organizationLabel(org), workspaces: [] };
|
|
11100
|
+
if (ws.organizationId && ws.organizationName) {
|
|
11101
|
+
return { key: ws.organizationId, label: ws.organizationName, workspaces: [] };
|
|
11102
|
+
}
|
|
11103
|
+
return { key: "__no_org__", label: "No organization", workspaces: [] };
|
|
11104
|
+
};
|
|
11105
|
+
const groups = serverMode ? [] : groupWorkspaceList(
|
|
10948
11106
|
workspaces.filter((ws) => !ws.isCurrent),
|
|
10949
11107
|
organizations
|
|
10950
11108
|
);
|
|
10951
11109
|
const rows = groups.flatMap(
|
|
10952
11110
|
(group) => group.workspaces.map((ws) => ({ ws, group }))
|
|
10953
11111
|
);
|
|
10954
|
-
const
|
|
10955
|
-
const
|
|
10956
|
-
|
|
10957
|
-
);
|
|
10958
|
-
const pageCount = Math.max(1, Math.ceil(otherWorkspaces.length / pageSize));
|
|
10959
|
-
const [page, setPage] = useState15(0);
|
|
10960
|
-
const safePage = Math.min(page, pageCount - 1);
|
|
11112
|
+
const listTotal = serverMode ? serverPage?.total ?? 0 : rows.length;
|
|
11113
|
+
const pageCount = Math.max(1, Math.ceil(listTotal / pageSize));
|
|
11114
|
+
const safePage = serverMode ? serverPage?.page ?? 0 : Math.min(page, pageCount - 1);
|
|
10961
11115
|
const pageStart = safePage * pageSize;
|
|
10962
|
-
const pageRows = rows.slice(pageStart, pageStart + pageSize);
|
|
11116
|
+
const pageRows = serverMode ? (serverPage?.items ?? []).map((ws) => ({ ws, group: serverGroupOf(ws) })) : rows.slice(pageStart, pageStart + pageSize);
|
|
10963
11117
|
const pageWorkspaces = pageRows.map((row) => row.ws);
|
|
11118
|
+
const listLoading = loading || serverMode && !serverPage;
|
|
10964
11119
|
const [plans, setPlans] = useState15({});
|
|
10965
11120
|
const requestedPlans = useRef7(/* @__PURE__ */ new Set());
|
|
10966
11121
|
const visibleIds = [
|
|
@@ -10976,7 +11131,7 @@ function WorkspaceListTab({
|
|
|
10976
11131
|
};
|
|
10977
11132
|
}, []);
|
|
10978
11133
|
useEffect13(() => {
|
|
10979
|
-
if (!fetchPlans ||
|
|
11134
|
+
if (!fetchPlans || listLoading) return;
|
|
10980
11135
|
const missing = visibleKey.split(",").filter((id) => id && !requestedPlans.current.has(id));
|
|
10981
11136
|
if (!missing.length) return;
|
|
10982
11137
|
missing.forEach((id) => requestedPlans.current.add(id));
|
|
@@ -10984,7 +11139,7 @@ function WorkspaceListTab({
|
|
|
10984
11139
|
if (mounted.current) setPlans((prev) => ({ ...prev, ...found }));
|
|
10985
11140
|
}).catch(() => {
|
|
10986
11141
|
});
|
|
10987
|
-
}, [fetchPlans,
|
|
11142
|
+
}, [fetchPlans, listLoading, visibleKey]);
|
|
10988
11143
|
const planOf = (ws) => fetchPlans ? plans[ws._id] ?? "" : ws.plan ?? "";
|
|
10989
11144
|
return /* @__PURE__ */ jsxs19(
|
|
10990
11145
|
"div",
|
|
@@ -11005,7 +11160,7 @@ function WorkspaceListTab({
|
|
|
11005
11160
|
children: "Switching changes which workspace the rest of Settings acts on."
|
|
11006
11161
|
}
|
|
11007
11162
|
),
|
|
11008
|
-
|
|
11163
|
+
listLoading && /* @__PURE__ */ jsx22(
|
|
11009
11164
|
"p",
|
|
11010
11165
|
{
|
|
11011
11166
|
style: {
|
|
@@ -11016,7 +11171,7 @@ function WorkspaceListTab({
|
|
|
11016
11171
|
children: "Loading workspaces\u2026"
|
|
11017
11172
|
}
|
|
11018
11173
|
),
|
|
11019
|
-
!
|
|
11174
|
+
!listLoading && currentWorkspace && /* @__PURE__ */ jsxs19(
|
|
11020
11175
|
"div",
|
|
11021
11176
|
{
|
|
11022
11177
|
className: "flex flex-col items-start shrink-0 w-full",
|
|
@@ -11056,7 +11211,7 @@ function WorkspaceListTab({
|
|
|
11056
11211
|
]
|
|
11057
11212
|
}
|
|
11058
11213
|
),
|
|
11059
|
-
!
|
|
11214
|
+
!listLoading && currentWorkspace && listTotal > 0 && /* @__PURE__ */ jsx22(
|
|
11060
11215
|
"div",
|
|
11061
11216
|
{
|
|
11062
11217
|
className: "shrink-0 w-full",
|
|
@@ -11066,7 +11221,7 @@ function WorkspaceListTab({
|
|
|
11066
11221
|
}
|
|
11067
11222
|
}
|
|
11068
11223
|
),
|
|
11069
|
-
!
|
|
11224
|
+
!listLoading && listTotal > 0 && /* @__PURE__ */ jsxs19(
|
|
11070
11225
|
"div",
|
|
11071
11226
|
{
|
|
11072
11227
|
className: "flex flex-col items-start flex-1 min-h-0 w-full",
|
|
@@ -11102,8 +11257,8 @@ function WorkspaceListTab({
|
|
|
11102
11257
|
role: ws.role,
|
|
11103
11258
|
plan: planOf(ws),
|
|
11104
11259
|
ownerId: ws.ownerEmail,
|
|
11105
|
-
type: "otherWS",
|
|
11106
|
-
onSwitch: () => onSwitchClick(ws),
|
|
11260
|
+
type: ws.isCurrent ? "currentWS" : "otherWS",
|
|
11261
|
+
onSwitch: ws.isCurrent ? void 0 : () => onSwitchClick(ws),
|
|
11107
11262
|
onSettings: () => onEditClick(ws),
|
|
11108
11263
|
onLeave: () => onLeaveClick(ws)
|
|
11109
11264
|
}
|
|
@@ -11132,7 +11287,7 @@ function WorkspaceListTab({
|
|
|
11132
11287
|
pageStart + pageWorkspaces.length,
|
|
11133
11288
|
" of",
|
|
11134
11289
|
" ",
|
|
11135
|
-
|
|
11290
|
+
listTotal
|
|
11136
11291
|
]
|
|
11137
11292
|
}
|
|
11138
11293
|
),
|
|
@@ -11306,6 +11461,24 @@ function SettingsContentInner({
|
|
|
11306
11461
|
useEffect13(() => {
|
|
11307
11462
|
void refreshWorkspaceList();
|
|
11308
11463
|
}, [refreshWorkspaceList]);
|
|
11464
|
+
const hostListPage = workspace.listPage;
|
|
11465
|
+
const listWorkspacePage = useMemo3(
|
|
11466
|
+
() => hostListPage ? async (params) => {
|
|
11467
|
+
const result = await hostListPage(params);
|
|
11468
|
+
return {
|
|
11469
|
+
total: result.total,
|
|
11470
|
+
items: result.items.map(
|
|
11471
|
+
(it) => ({
|
|
11472
|
+
...it,
|
|
11473
|
+
isCurrent: it.isCurrent ?? it._id === workspaceId,
|
|
11474
|
+
imageUrl: it.imageUrl ?? it.image,
|
|
11475
|
+
initials: deriveInitials(it.name)
|
|
11476
|
+
})
|
|
11477
|
+
)
|
|
11478
|
+
};
|
|
11479
|
+
} : void 0,
|
|
11480
|
+
[hostListPage, workspaceId]
|
|
11481
|
+
);
|
|
11309
11482
|
const [listOrganizations, setListOrganizations] = useState15([]);
|
|
11310
11483
|
useEffect13(() => {
|
|
11311
11484
|
if (activeTab !== "workspaceList" || typeof organization?.list !== "function") {
|
|
@@ -11979,6 +12152,8 @@ function SettingsContentInner({
|
|
|
11979
12152
|
loading: workspaceListLoading && workspaceList.length === 0,
|
|
11980
12153
|
fetchPlans: workspace.fetchPlans,
|
|
11981
12154
|
organizations: listOrganizations,
|
|
12155
|
+
listPage: listWorkspacePage,
|
|
12156
|
+
reloadKey: displayWorkspaces.map((ws) => `${ws._id}:${ws.name}:${ws.role}`).join(","),
|
|
11982
12157
|
onCreateClick: handleCreateClick,
|
|
11983
12158
|
onEditClick: handleEditClick,
|
|
11984
12159
|
onSwitchClick: async (ws) => {
|