@streamoid/settings 0.6.1 → 0.6.3
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/README.md +16 -0
- package/dist/index.d.mts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +95 -0
- package/dist/index.mjs +97 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -155,3 +155,19 @@ See [`src/adapters.ts`](src/adapters.ts) for full type definitions.
|
|
|
155
155
|
|
|
156
156
|
- **0.1.0** — Adapter surface and package scaffold. Tab content lands in
|
|
157
157
|
subsequent releases as files migrate from `cxo-dashboard` into the package.
|
|
158
|
+
|
|
159
|
+
## Workspace owner in the sidebar
|
|
160
|
+
|
|
161
|
+
`useWorkspaceOrganization({ workspaceId, request, enabled, onOpenOrganization })`
|
|
162
|
+
returns organization props for `ScWorkspaceAccountMenu` from `@streamoid/ui`.
|
|
163
|
+
The host supplies a stable authenticated GET transport returning the unified
|
|
164
|
+
API envelope. The adapter reads `/workspace`, finds the exact selected workspace,
|
|
165
|
+
and resolves only its `organizationId` through `/organization/:id` and `/role`.
|
|
166
|
+
It never chooses an organization from the user's membership list. An unowned
|
|
167
|
+
workspace, a loading request, and an unavailable owner remain distinct states.
|
|
168
|
+
|
|
169
|
+
Enable it while the menu is open. Requests are aborted on close/switch and stale
|
|
170
|
+
responses cannot update the next workspace. Organization roles come from the
|
|
171
|
+
organization API, never the workspace role. Guests may see an authorized owner
|
|
172
|
+
name, but only members/admins get the optional navigation callback. The host
|
|
173
|
+
owns routing; apps without organization settings omit the callback.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import react__default, { SVGProps, ReactNode } from 'react';
|
|
3
|
+
import { WorkspaceUsage, ScWorkspaceAccountMenuProps } from '@streamoid/ui';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Settings tab identifiers and URL mapping helpers.
|
|
@@ -141,6 +142,13 @@ interface SettingsWorkspaceCurrent {
|
|
|
141
142
|
/** Optional reactive credit summary if the host tracks it. */
|
|
142
143
|
availableCredits?: number | null;
|
|
143
144
|
totalCredits?: number | null;
|
|
145
|
+
/**
|
|
146
|
+
* Storage & bandwidth against the plan allowance, as the HOST has already
|
|
147
|
+
* fetched and evaluated it (`evaluateWorkspaceUsage` from `@streamoid/ui`).
|
|
148
|
+
* This package never requests it. When present, the Billing tab renders a
|
|
149
|
+
* usage meter for each kind; absent or null renders none.
|
|
150
|
+
*/
|
|
151
|
+
usage?: WorkspaceUsage | null;
|
|
144
152
|
/** ISO country code for the workspace; drives plan currency selection. */
|
|
145
153
|
country?: string;
|
|
146
154
|
/**
|
|
@@ -512,6 +520,8 @@ interface MemberPermissionsPayload {
|
|
|
512
520
|
serviceIds: string[];
|
|
513
521
|
storeIds: string[];
|
|
514
522
|
}
|
|
523
|
+
/** `SettingsWorkspaceCurrent.usage`; re-exported from `@streamoid/ui`. */
|
|
524
|
+
type WorkspaceUsageResponse = WorkspaceUsage;
|
|
515
525
|
interface AvailableCreditsResponse {
|
|
516
526
|
availableCredits: number;
|
|
517
527
|
}
|
|
@@ -1384,4 +1394,20 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1384
1394
|
*/
|
|
1385
1395
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1386
1396
|
|
|
1387
|
-
|
|
1397
|
+
/** Host transport: authenticated GET returning the unified API envelope. */
|
|
1398
|
+
type WorkspaceOrganizationRequest = (path: string, signal: AbortSignal) => Promise<unknown>;
|
|
1399
|
+
interface WorkspaceOrganization {
|
|
1400
|
+
_id: string;
|
|
1401
|
+
name: string;
|
|
1402
|
+
role?: string;
|
|
1403
|
+
}
|
|
1404
|
+
/** Resolve only the selected workspace's owner, never a user's first org. */
|
|
1405
|
+
declare function loadWorkspaceOrganization(workspaceId: string, request: WorkspaceOrganizationRequest, signal: AbortSignal): Promise<WorkspaceOrganization | null>;
|
|
1406
|
+
declare function useWorkspaceOrganization({ workspaceId, request, enabled, onOpenOrganization, }: {
|
|
1407
|
+
workspaceId?: string | null;
|
|
1408
|
+
request: WorkspaceOrganizationRequest;
|
|
1409
|
+
enabled?: boolean;
|
|
1410
|
+
onOpenOrganization?: (organizationId: string) => void;
|
|
1411
|
+
}): Pick<ScWorkspaceAccountMenuProps, "organizationName" | "organizationRole" | "organizationStatus" | "onOrganizationClick">;
|
|
1412
|
+
|
|
1413
|
+
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, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, 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, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, type WorkspaceOrganization, type WorkspaceOrganizationRequest, WorkspaceTab, type WorkspaceUsageResponse, countLabel, loadWorkspaceOrganization, resolveSettingsTabFromPath, useSettingsAdapters, useWorkspaceOrganization, userLanguageLabel };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import react__default, { SVGProps, ReactNode } from 'react';
|
|
3
|
+
import { WorkspaceUsage, ScWorkspaceAccountMenuProps } from '@streamoid/ui';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Settings tab identifiers and URL mapping helpers.
|
|
@@ -141,6 +142,13 @@ interface SettingsWorkspaceCurrent {
|
|
|
141
142
|
/** Optional reactive credit summary if the host tracks it. */
|
|
142
143
|
availableCredits?: number | null;
|
|
143
144
|
totalCredits?: number | null;
|
|
145
|
+
/**
|
|
146
|
+
* Storage & bandwidth against the plan allowance, as the HOST has already
|
|
147
|
+
* fetched and evaluated it (`evaluateWorkspaceUsage` from `@streamoid/ui`).
|
|
148
|
+
* This package never requests it. When present, the Billing tab renders a
|
|
149
|
+
* usage meter for each kind; absent or null renders none.
|
|
150
|
+
*/
|
|
151
|
+
usage?: WorkspaceUsage | null;
|
|
144
152
|
/** ISO country code for the workspace; drives plan currency selection. */
|
|
145
153
|
country?: string;
|
|
146
154
|
/**
|
|
@@ -512,6 +520,8 @@ interface MemberPermissionsPayload {
|
|
|
512
520
|
serviceIds: string[];
|
|
513
521
|
storeIds: string[];
|
|
514
522
|
}
|
|
523
|
+
/** `SettingsWorkspaceCurrent.usage`; re-exported from `@streamoid/ui`. */
|
|
524
|
+
type WorkspaceUsageResponse = WorkspaceUsage;
|
|
515
525
|
interface AvailableCreditsResponse {
|
|
516
526
|
availableCredits: number;
|
|
517
527
|
}
|
|
@@ -1384,4 +1394,20 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1384
1394
|
*/
|
|
1385
1395
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1386
1396
|
|
|
1387
|
-
|
|
1397
|
+
/** Host transport: authenticated GET returning the unified API envelope. */
|
|
1398
|
+
type WorkspaceOrganizationRequest = (path: string, signal: AbortSignal) => Promise<unknown>;
|
|
1399
|
+
interface WorkspaceOrganization {
|
|
1400
|
+
_id: string;
|
|
1401
|
+
name: string;
|
|
1402
|
+
role?: string;
|
|
1403
|
+
}
|
|
1404
|
+
/** Resolve only the selected workspace's owner, never a user's first org. */
|
|
1405
|
+
declare function loadWorkspaceOrganization(workspaceId: string, request: WorkspaceOrganizationRequest, signal: AbortSignal): Promise<WorkspaceOrganization | null>;
|
|
1406
|
+
declare function useWorkspaceOrganization({ workspaceId, request, enabled, onOpenOrganization, }: {
|
|
1407
|
+
workspaceId?: string | null;
|
|
1408
|
+
request: WorkspaceOrganizationRequest;
|
|
1409
|
+
enabled?: boolean;
|
|
1410
|
+
onOpenOrganization?: (organizationId: string) => void;
|
|
1411
|
+
}): Pick<ScWorkspaceAccountMenuProps, "organizationName" | "organizationRole" | "organizationStatus" | "onOrganizationClick">;
|
|
1412
|
+
|
|
1413
|
+
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, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, 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, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, type WorkspaceOrganization, type WorkspaceOrganizationRequest, WorkspaceTab, type WorkspaceUsageResponse, countLabel, loadWorkspaceOrganization, resolveSettingsTabFromPath, useSettingsAdapters, useWorkspaceOrganization, userLanguageLabel };
|
package/dist/index.js
CHANGED
|
@@ -56,8 +56,10 @@ __export(index_exports, {
|
|
|
56
56
|
WorkspaceModal: () => WorkspaceModal,
|
|
57
57
|
WorkspaceTab: () => WorkspaceTab,
|
|
58
58
|
countLabel: () => countLabel,
|
|
59
|
+
loadWorkspaceOrganization: () => loadWorkspaceOrganization,
|
|
59
60
|
resolveSettingsTabFromPath: () => resolveSettingsTabFromPath,
|
|
60
61
|
useSettingsAdapters: () => useSettingsAdapters,
|
|
62
|
+
useWorkspaceOrganization: () => useWorkspaceOrganization,
|
|
61
63
|
userLanguageLabel: () => userLanguageLabel
|
|
62
64
|
});
|
|
63
65
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -9175,6 +9177,7 @@ function BillingContent({
|
|
|
9175
9177
|
fetchBillingOverview();
|
|
9176
9178
|
fetchUserMap();
|
|
9177
9179
|
}, [fetchBillingOverview, fetchUserMap]);
|
|
9180
|
+
const usage = workspace.current?.usage ?? null;
|
|
9178
9181
|
(0, import_react14.useEffect)(() => {
|
|
9179
9182
|
void logBillingEvent("billing_page_viewed", "Billing page viewed", {
|
|
9180
9183
|
action: "view"
|
|
@@ -9482,6 +9485,28 @@ function BillingContent({
|
|
|
9482
9485
|
]
|
|
9483
9486
|
}
|
|
9484
9487
|
),
|
|
9488
|
+
usage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
9489
|
+
"div",
|
|
9490
|
+
{
|
|
9491
|
+
className: "grid shrink-0 w-full",
|
|
9492
|
+
style: {
|
|
9493
|
+
gap: "var(--spacing-6xl)",
|
|
9494
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(18rem, 1fr))"
|
|
9495
|
+
},
|
|
9496
|
+
children: [
|
|
9497
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ui9.ScUsageMeterCard, { kind: "storage", plan: usage.plan, status: usage.storage }),
|
|
9498
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
9499
|
+
import_ui9.ScUsageMeterCard,
|
|
9500
|
+
{
|
|
9501
|
+
kind: "bandwidth",
|
|
9502
|
+
plan: usage.plan,
|
|
9503
|
+
status: usage.bandwidth,
|
|
9504
|
+
footnote: `This billing month \xB7 resets ${new Date(usage.period.to).toLocaleDateString(void 0, { day: "numeric", month: "short" })}`
|
|
9505
|
+
}
|
|
9506
|
+
)
|
|
9507
|
+
]
|
|
9508
|
+
}
|
|
9509
|
+
) : null,
|
|
9485
9510
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center justify-between shrink-0 w-full", children: [
|
|
9486
9511
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(BillingTabBar, { activeTab, onTabChange: setActiveTab }),
|
|
9487
9512
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
@@ -12309,3 +12334,73 @@ function SettingsContentInner({
|
|
|
12309
12334
|
}
|
|
12310
12335
|
);
|
|
12311
12336
|
}
|
|
12337
|
+
|
|
12338
|
+
// src/workspace-organization.ts
|
|
12339
|
+
var import_react17 = require("react");
|
|
12340
|
+
function dataOf(value) {
|
|
12341
|
+
if (!value || typeof value !== "object") throw new Error("Invalid response");
|
|
12342
|
+
const envelope = value;
|
|
12343
|
+
if (envelope.status?.code != null && envelope.status.code !== 0) {
|
|
12344
|
+
throw new Error("Organization request failed");
|
|
12345
|
+
}
|
|
12346
|
+
return "data" in envelope ? envelope.data : envelope;
|
|
12347
|
+
}
|
|
12348
|
+
async function loadWorkspaceOrganization(workspaceId, request, signal) {
|
|
12349
|
+
const rows = dataOf(await request("/workspace", signal));
|
|
12350
|
+
if (!Array.isArray(rows)) throw new Error("Invalid workspace list");
|
|
12351
|
+
const row = rows.find((item) => (item.workspace?._id ?? item._id) === workspaceId);
|
|
12352
|
+
if (!row) throw new Error("Workspace not found");
|
|
12353
|
+
const workspace = row.workspace ?? row;
|
|
12354
|
+
const owner = workspace.organization !== void 0 ? workspace.organization : row.organization;
|
|
12355
|
+
const ownerRef = workspace.organizationId !== void 0 ? workspace.organizationId : row.organizationId;
|
|
12356
|
+
if (ownerRef === null || owner === null) return null;
|
|
12357
|
+
const id = typeof ownerRef === "string" ? ownerRef : ownerRef?._id ?? owner?._id;
|
|
12358
|
+
if (!id) return null;
|
|
12359
|
+
const path = `/organization/${encodeURIComponent(id)}`;
|
|
12360
|
+
const [detail, role] = await Promise.allSettled([
|
|
12361
|
+
owner?.name && owner._id === id ? Promise.resolve(owner) : request(path, signal).then(dataOf),
|
|
12362
|
+
request(`${path}/role`, signal).then(dataOf)
|
|
12363
|
+
]);
|
|
12364
|
+
if (signal.aborted) throw new Error("Request aborted");
|
|
12365
|
+
if (detail.status !== "fulfilled" || !detail.value?.name || detail.value._id !== id) {
|
|
12366
|
+
throw new Error("Organization unavailable");
|
|
12367
|
+
}
|
|
12368
|
+
return {
|
|
12369
|
+
_id: id,
|
|
12370
|
+
name: detail.value.name,
|
|
12371
|
+
// A workspace role is never an organization permission.
|
|
12372
|
+
role: role.status === "fulfilled" ? role.value?.role : void 0
|
|
12373
|
+
};
|
|
12374
|
+
}
|
|
12375
|
+
function useWorkspaceOrganization({
|
|
12376
|
+
workspaceId,
|
|
12377
|
+
request,
|
|
12378
|
+
enabled = true,
|
|
12379
|
+
onOpenOrganization
|
|
12380
|
+
}) {
|
|
12381
|
+
const [result, setResult] = (0, import_react17.useState)();
|
|
12382
|
+
(0, import_react17.useEffect)(() => {
|
|
12383
|
+
if (!enabled || !workspaceId) return;
|
|
12384
|
+
const controller = new AbortController();
|
|
12385
|
+
setResult(void 0);
|
|
12386
|
+
loadWorkspaceOrganization(workspaceId, request, controller.signal).then(
|
|
12387
|
+
(owner2) => {
|
|
12388
|
+
if (!controller.signal.aborted) setResult({ workspaceId, owner: owner2 });
|
|
12389
|
+
},
|
|
12390
|
+
() => {
|
|
12391
|
+
if (!controller.signal.aborted) setResult({ workspaceId, error: true });
|
|
12392
|
+
}
|
|
12393
|
+
);
|
|
12394
|
+
return () => controller.abort();
|
|
12395
|
+
}, [workspaceId, request, enabled]);
|
|
12396
|
+
if (!workspaceId || !enabled) return {};
|
|
12397
|
+
if (result?.workspaceId !== workspaceId) return { organizationStatus: "loading" };
|
|
12398
|
+
if (result.error) return { organizationStatus: "error" };
|
|
12399
|
+
const owner = result.owner;
|
|
12400
|
+
const canOpen = owner?.role === "admin" || owner?.role === "member";
|
|
12401
|
+
return {
|
|
12402
|
+
organizationName: owner?.name ?? null,
|
|
12403
|
+
organizationRole: owner?.role,
|
|
12404
|
+
onOrganizationClick: owner && canOpen && onOpenOrganization ? () => onOpenOrganization(owner._id) : void 0
|
|
12405
|
+
};
|
|
12406
|
+
}
|
package/dist/index.mjs
CHANGED
|
@@ -6956,7 +6956,8 @@ import {
|
|
|
6956
6956
|
ScBillingHistoryTableList,
|
|
6957
6957
|
ScHeader,
|
|
6958
6958
|
ScPlanCard,
|
|
6959
|
-
ScPlanComparison
|
|
6959
|
+
ScPlanComparison,
|
|
6960
|
+
ScUsageMeterCard
|
|
6960
6961
|
} from "@streamoid/ui";
|
|
6961
6962
|
import {
|
|
6962
6963
|
SiconDownload,
|
|
@@ -9177,6 +9178,7 @@ function BillingContent({
|
|
|
9177
9178
|
fetchBillingOverview();
|
|
9178
9179
|
fetchUserMap();
|
|
9179
9180
|
}, [fetchBillingOverview, fetchUserMap]);
|
|
9181
|
+
const usage = workspace.current?.usage ?? null;
|
|
9180
9182
|
useEffect10(() => {
|
|
9181
9183
|
void logBillingEvent("billing_page_viewed", "Billing page viewed", {
|
|
9182
9184
|
action: "view"
|
|
@@ -9484,6 +9486,28 @@ function BillingContent({
|
|
|
9484
9486
|
]
|
|
9485
9487
|
}
|
|
9486
9488
|
),
|
|
9489
|
+
usage ? /* @__PURE__ */ jsxs16(
|
|
9490
|
+
"div",
|
|
9491
|
+
{
|
|
9492
|
+
className: "grid shrink-0 w-full",
|
|
9493
|
+
style: {
|
|
9494
|
+
gap: "var(--spacing-6xl)",
|
|
9495
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(18rem, 1fr))"
|
|
9496
|
+
},
|
|
9497
|
+
children: [
|
|
9498
|
+
/* @__PURE__ */ jsx18(ScUsageMeterCard, { kind: "storage", plan: usage.plan, status: usage.storage }),
|
|
9499
|
+
/* @__PURE__ */ jsx18(
|
|
9500
|
+
ScUsageMeterCard,
|
|
9501
|
+
{
|
|
9502
|
+
kind: "bandwidth",
|
|
9503
|
+
plan: usage.plan,
|
|
9504
|
+
status: usage.bandwidth,
|
|
9505
|
+
footnote: `This billing month \xB7 resets ${new Date(usage.period.to).toLocaleDateString(void 0, { day: "numeric", month: "short" })}`
|
|
9506
|
+
}
|
|
9507
|
+
)
|
|
9508
|
+
]
|
|
9509
|
+
}
|
|
9510
|
+
) : null,
|
|
9487
9511
|
/* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between shrink-0 w-full", children: [
|
|
9488
9512
|
/* @__PURE__ */ jsx18(BillingTabBar, { activeTab, onTabChange: setActiveTab }),
|
|
9489
9513
|
/* @__PURE__ */ jsxs16(
|
|
@@ -12317,6 +12341,76 @@ function SettingsContentInner({
|
|
|
12317
12341
|
}
|
|
12318
12342
|
);
|
|
12319
12343
|
}
|
|
12344
|
+
|
|
12345
|
+
// src/workspace-organization.ts
|
|
12346
|
+
import { useEffect as useEffect13, useState as useState15 } from "react";
|
|
12347
|
+
function dataOf(value) {
|
|
12348
|
+
if (!value || typeof value !== "object") throw new Error("Invalid response");
|
|
12349
|
+
const envelope = value;
|
|
12350
|
+
if (envelope.status?.code != null && envelope.status.code !== 0) {
|
|
12351
|
+
throw new Error("Organization request failed");
|
|
12352
|
+
}
|
|
12353
|
+
return "data" in envelope ? envelope.data : envelope;
|
|
12354
|
+
}
|
|
12355
|
+
async function loadWorkspaceOrganization(workspaceId, request, signal) {
|
|
12356
|
+
const rows = dataOf(await request("/workspace", signal));
|
|
12357
|
+
if (!Array.isArray(rows)) throw new Error("Invalid workspace list");
|
|
12358
|
+
const row = rows.find((item) => (item.workspace?._id ?? item._id) === workspaceId);
|
|
12359
|
+
if (!row) throw new Error("Workspace not found");
|
|
12360
|
+
const workspace = row.workspace ?? row;
|
|
12361
|
+
const owner = workspace.organization !== void 0 ? workspace.organization : row.organization;
|
|
12362
|
+
const ownerRef = workspace.organizationId !== void 0 ? workspace.organizationId : row.organizationId;
|
|
12363
|
+
if (ownerRef === null || owner === null) return null;
|
|
12364
|
+
const id = typeof ownerRef === "string" ? ownerRef : ownerRef?._id ?? owner?._id;
|
|
12365
|
+
if (!id) return null;
|
|
12366
|
+
const path = `/organization/${encodeURIComponent(id)}`;
|
|
12367
|
+
const [detail, role] = await Promise.allSettled([
|
|
12368
|
+
owner?.name && owner._id === id ? Promise.resolve(owner) : request(path, signal).then(dataOf),
|
|
12369
|
+
request(`${path}/role`, signal).then(dataOf)
|
|
12370
|
+
]);
|
|
12371
|
+
if (signal.aborted) throw new Error("Request aborted");
|
|
12372
|
+
if (detail.status !== "fulfilled" || !detail.value?.name || detail.value._id !== id) {
|
|
12373
|
+
throw new Error("Organization unavailable");
|
|
12374
|
+
}
|
|
12375
|
+
return {
|
|
12376
|
+
_id: id,
|
|
12377
|
+
name: detail.value.name,
|
|
12378
|
+
// A workspace role is never an organization permission.
|
|
12379
|
+
role: role.status === "fulfilled" ? role.value?.role : void 0
|
|
12380
|
+
};
|
|
12381
|
+
}
|
|
12382
|
+
function useWorkspaceOrganization({
|
|
12383
|
+
workspaceId,
|
|
12384
|
+
request,
|
|
12385
|
+
enabled = true,
|
|
12386
|
+
onOpenOrganization
|
|
12387
|
+
}) {
|
|
12388
|
+
const [result, setResult] = useState15();
|
|
12389
|
+
useEffect13(() => {
|
|
12390
|
+
if (!enabled || !workspaceId) return;
|
|
12391
|
+
const controller = new AbortController();
|
|
12392
|
+
setResult(void 0);
|
|
12393
|
+
loadWorkspaceOrganization(workspaceId, request, controller.signal).then(
|
|
12394
|
+
(owner2) => {
|
|
12395
|
+
if (!controller.signal.aborted) setResult({ workspaceId, owner: owner2 });
|
|
12396
|
+
},
|
|
12397
|
+
() => {
|
|
12398
|
+
if (!controller.signal.aborted) setResult({ workspaceId, error: true });
|
|
12399
|
+
}
|
|
12400
|
+
);
|
|
12401
|
+
return () => controller.abort();
|
|
12402
|
+
}, [workspaceId, request, enabled]);
|
|
12403
|
+
if (!workspaceId || !enabled) return {};
|
|
12404
|
+
if (result?.workspaceId !== workspaceId) return { organizationStatus: "loading" };
|
|
12405
|
+
if (result.error) return { organizationStatus: "error" };
|
|
12406
|
+
const owner = result.owner;
|
|
12407
|
+
const canOpen = owner?.role === "admin" || owner?.role === "member";
|
|
12408
|
+
return {
|
|
12409
|
+
organizationName: owner?.name ?? null,
|
|
12410
|
+
organizationRole: owner?.role,
|
|
12411
|
+
onOrganizationClick: owner && canOpen && onOpenOrganization ? () => onOpenOrganization(owner._id) : void 0
|
|
12412
|
+
};
|
|
12413
|
+
}
|
|
12320
12414
|
export {
|
|
12321
12415
|
APP_KEYS,
|
|
12322
12416
|
BillingContent,
|
|
@@ -12354,7 +12448,9 @@ export {
|
|
|
12354
12448
|
WorkspaceModal,
|
|
12355
12449
|
WorkspaceTab,
|
|
12356
12450
|
countLabel,
|
|
12451
|
+
loadWorkspaceOrganization,
|
|
12357
12452
|
resolveSettingsTabFromPath,
|
|
12358
12453
|
useSettingsAdapters,
|
|
12454
|
+
useWorkspaceOrganization,
|
|
12359
12455
|
userLanguageLabel
|
|
12360
12456
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamoid/settings",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"react": "^18.0.0 || ^19.0.0",
|
|
26
26
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
27
|
-
"@streamoid/ui": "
|
|
27
|
+
"@streamoid/ui": ">=0.6.74",
|
|
28
28
|
"@streamoid/icons": "*"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|