@streamoid/settings 0.6.2 → 0.6.4
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 +20 -0
- package/dist/index.d.mts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +73 -0
- package/dist/index.mjs +73 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -155,3 +155,23 @@ 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.
|
|
174
|
+
|
|
175
|
+
The adapter prefers `organizationName` from the authorized workspace response.
|
|
176
|
+
This lets invited workspace members see its owner without organization membership;
|
|
177
|
+
the separately checked organization role still controls settings navigation.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import react__default, { SVGProps, ReactNode } from 'react';
|
|
3
|
-
import { WorkspaceUsage } from '@streamoid/ui';
|
|
3
|
+
import { WorkspaceUsage, ScWorkspaceAccountMenuProps } from '@streamoid/ui';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Settings tab identifiers and URL mapping helpers.
|
|
@@ -1394,4 +1394,20 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1394
1394
|
*/
|
|
1395
1395
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1396
1396
|
|
|
1397
|
-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import react__default, { SVGProps, ReactNode } from 'react';
|
|
3
|
-
import { WorkspaceUsage } from '@streamoid/ui';
|
|
3
|
+
import { WorkspaceUsage, ScWorkspaceAccountMenuProps } from '@streamoid/ui';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Settings tab identifiers and URL mapping helpers.
|
|
@@ -1394,4 +1394,20 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
|
|
|
1394
1394
|
*/
|
|
1395
1395
|
declare function useSettingsAdapters(): SettingsAdapters;
|
|
1396
1396
|
|
|
1397
|
-
|
|
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);
|
|
@@ -12332,3 +12334,74 @@ function SettingsContentInner({
|
|
|
12332
12334
|
}
|
|
12333
12335
|
);
|
|
12334
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 displayName = workspace.organizationName ?? row.organizationName;
|
|
12361
|
+
const [detail, role] = await Promise.allSettled([
|
|
12362
|
+
typeof displayName === "string" && displayName.trim() ? Promise.resolve({ _id: id, name: displayName }) : owner?.name && owner._id === id ? Promise.resolve(owner) : request(path, signal).then(dataOf),
|
|
12363
|
+
request(`${path}/role`, signal).then(dataOf)
|
|
12364
|
+
]);
|
|
12365
|
+
if (signal.aborted) throw new Error("Request aborted");
|
|
12366
|
+
if (detail.status !== "fulfilled" || !detail.value?.name || detail.value._id !== id) {
|
|
12367
|
+
throw new Error("Organization unavailable");
|
|
12368
|
+
}
|
|
12369
|
+
return {
|
|
12370
|
+
_id: id,
|
|
12371
|
+
name: detail.value.name,
|
|
12372
|
+
// A workspace role is never an organization permission.
|
|
12373
|
+
role: role.status === "fulfilled" ? role.value?.role : void 0
|
|
12374
|
+
};
|
|
12375
|
+
}
|
|
12376
|
+
function useWorkspaceOrganization({
|
|
12377
|
+
workspaceId,
|
|
12378
|
+
request,
|
|
12379
|
+
enabled = true,
|
|
12380
|
+
onOpenOrganization
|
|
12381
|
+
}) {
|
|
12382
|
+
const [result, setResult] = (0, import_react17.useState)();
|
|
12383
|
+
(0, import_react17.useEffect)(() => {
|
|
12384
|
+
if (!enabled || !workspaceId) return;
|
|
12385
|
+
const controller = new AbortController();
|
|
12386
|
+
setResult(void 0);
|
|
12387
|
+
loadWorkspaceOrganization(workspaceId, request, controller.signal).then(
|
|
12388
|
+
(owner2) => {
|
|
12389
|
+
if (!controller.signal.aborted) setResult({ workspaceId, owner: owner2 });
|
|
12390
|
+
},
|
|
12391
|
+
() => {
|
|
12392
|
+
if (!controller.signal.aborted) setResult({ workspaceId, error: true });
|
|
12393
|
+
}
|
|
12394
|
+
);
|
|
12395
|
+
return () => controller.abort();
|
|
12396
|
+
}, [workspaceId, request, enabled]);
|
|
12397
|
+
if (!workspaceId || !enabled) return {};
|
|
12398
|
+
if (result?.workspaceId !== workspaceId) return { organizationStatus: "loading" };
|
|
12399
|
+
if (result.error) return { organizationStatus: "error" };
|
|
12400
|
+
const owner = result.owner;
|
|
12401
|
+
const canOpen = owner?.role === "admin" || owner?.role === "member";
|
|
12402
|
+
return {
|
|
12403
|
+
organizationName: owner?.name ?? null,
|
|
12404
|
+
organizationRole: owner?.role,
|
|
12405
|
+
onOrganizationClick: owner && canOpen && onOpenOrganization ? () => onOpenOrganization(owner._id) : void 0
|
|
12406
|
+
};
|
|
12407
|
+
}
|
package/dist/index.mjs
CHANGED
|
@@ -12341,6 +12341,77 @@ function SettingsContentInner({
|
|
|
12341
12341
|
}
|
|
12342
12342
|
);
|
|
12343
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 displayName = workspace.organizationName ?? row.organizationName;
|
|
12368
|
+
const [detail, role] = await Promise.allSettled([
|
|
12369
|
+
typeof displayName === "string" && displayName.trim() ? Promise.resolve({ _id: id, name: displayName }) : owner?.name && owner._id === id ? Promise.resolve(owner) : request(path, signal).then(dataOf),
|
|
12370
|
+
request(`${path}/role`, signal).then(dataOf)
|
|
12371
|
+
]);
|
|
12372
|
+
if (signal.aborted) throw new Error("Request aborted");
|
|
12373
|
+
if (detail.status !== "fulfilled" || !detail.value?.name || detail.value._id !== id) {
|
|
12374
|
+
throw new Error("Organization unavailable");
|
|
12375
|
+
}
|
|
12376
|
+
return {
|
|
12377
|
+
_id: id,
|
|
12378
|
+
name: detail.value.name,
|
|
12379
|
+
// A workspace role is never an organization permission.
|
|
12380
|
+
role: role.status === "fulfilled" ? role.value?.role : void 0
|
|
12381
|
+
};
|
|
12382
|
+
}
|
|
12383
|
+
function useWorkspaceOrganization({
|
|
12384
|
+
workspaceId,
|
|
12385
|
+
request,
|
|
12386
|
+
enabled = true,
|
|
12387
|
+
onOpenOrganization
|
|
12388
|
+
}) {
|
|
12389
|
+
const [result, setResult] = useState15();
|
|
12390
|
+
useEffect13(() => {
|
|
12391
|
+
if (!enabled || !workspaceId) return;
|
|
12392
|
+
const controller = new AbortController();
|
|
12393
|
+
setResult(void 0);
|
|
12394
|
+
loadWorkspaceOrganization(workspaceId, request, controller.signal).then(
|
|
12395
|
+
(owner2) => {
|
|
12396
|
+
if (!controller.signal.aborted) setResult({ workspaceId, owner: owner2 });
|
|
12397
|
+
},
|
|
12398
|
+
() => {
|
|
12399
|
+
if (!controller.signal.aborted) setResult({ workspaceId, error: true });
|
|
12400
|
+
}
|
|
12401
|
+
);
|
|
12402
|
+
return () => controller.abort();
|
|
12403
|
+
}, [workspaceId, request, enabled]);
|
|
12404
|
+
if (!workspaceId || !enabled) return {};
|
|
12405
|
+
if (result?.workspaceId !== workspaceId) return { organizationStatus: "loading" };
|
|
12406
|
+
if (result.error) return { organizationStatus: "error" };
|
|
12407
|
+
const owner = result.owner;
|
|
12408
|
+
const canOpen = owner?.role === "admin" || owner?.role === "member";
|
|
12409
|
+
return {
|
|
12410
|
+
organizationName: owner?.name ?? null,
|
|
12411
|
+
organizationRole: owner?.role,
|
|
12412
|
+
onOrganizationClick: owner && canOpen && onOpenOrganization ? () => onOpenOrganization(owner._id) : void 0
|
|
12413
|
+
};
|
|
12414
|
+
}
|
|
12344
12415
|
export {
|
|
12345
12416
|
APP_KEYS,
|
|
12346
12417
|
BillingContent,
|
|
@@ -12378,7 +12449,9 @@ export {
|
|
|
12378
12449
|
WorkspaceModal,
|
|
12379
12450
|
WorkspaceTab,
|
|
12380
12451
|
countLabel,
|
|
12452
|
+
loadWorkspaceOrganization,
|
|
12381
12453
|
resolveSettingsTabFromPath,
|
|
12382
12454
|
useSettingsAdapters,
|
|
12455
|
+
useWorkspaceOrganization,
|
|
12383
12456
|
userLanguageLabel
|
|
12384
12457
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamoid/settings",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
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": {
|