@stigmer/react 3.39.1-dev.20260928194002 → 3.40.1
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/billing/AutoRechargeCard.js +1 -1
- package/billing/AutoRechargeCard.js.map +1 -1
- package/billing/BillingSection.d.ts +18 -1
- package/billing/BillingSection.d.ts.map +1 -1
- package/billing/BillingSection.js +21 -11
- package/billing/BillingSection.js.map +1 -1
- package/billing/ChangePlanDialog.d.ts +46 -0
- package/billing/ChangePlanDialog.d.ts.map +1 -0
- package/billing/ChangePlanDialog.js +90 -0
- package/billing/ChangePlanDialog.js.map +1 -0
- package/billing/CreditPackGrid.d.ts +1 -1
- package/billing/CreditPackGrid.js +1 -1
- package/billing/LowBalanceBanner.js +1 -1
- package/billing/LowBalanceBanner.js.map +1 -1
- package/billing/PaymentMethodCard.d.ts +9 -1
- package/billing/PaymentMethodCard.d.ts.map +1 -1
- package/billing/PaymentMethodCard.js +2 -2
- package/billing/PaymentMethodCard.js.map +1 -1
- package/billing/PlanCard.d.ts +27 -0
- package/billing/PlanCard.d.ts.map +1 -0
- package/billing/PlanCard.js +68 -0
- package/billing/PlanCard.js.map +1 -0
- package/billing/PlanPicker.d.ts +34 -0
- package/billing/PlanPicker.d.ts.map +1 -0
- package/billing/PlanPicker.js +46 -0
- package/billing/PlanPicker.js.map +1 -0
- package/billing/PlanSection.d.ts +45 -0
- package/billing/PlanSection.d.ts.map +1 -0
- package/billing/PlanSection.js +136 -0
- package/billing/PlanSection.js.map +1 -0
- package/billing/UpgradeNotice.d.ts +47 -0
- package/billing/UpgradeNotice.d.ts.map +1 -0
- package/billing/UpgradeNotice.js +49 -0
- package/billing/UpgradeNotice.js.map +1 -0
- package/billing/credit-packs.d.ts.map +1 -1
- package/billing/credit-packs.js +4 -1
- package/billing/credit-packs.js.map +1 -1
- package/billing/index.d.ts +26 -1
- package/billing/index.d.ts.map +1 -1
- package/billing/index.js +12 -0
- package/billing/index.js.map +1 -1
- package/billing/plan-features.d.ts +60 -0
- package/billing/plan-features.d.ts.map +1 -0
- package/billing/plan-features.js +128 -0
- package/billing/plan-features.js.map +1 -0
- package/billing/plan-state.d.ts +43 -0
- package/billing/plan-state.d.ts.map +1 -0
- package/billing/plan-state.js +69 -0
- package/billing/plan-state.js.map +1 -0
- package/billing/redirect.d.ts +31 -0
- package/billing/redirect.d.ts.map +1 -0
- package/billing/redirect.js +30 -0
- package/billing/redirect.js.map +1 -0
- package/billing/useBillingAccount.d.ts +10 -1
- package/billing/useBillingAccount.d.ts.map +1 -1
- package/billing/useBillingAccount.js +2 -2
- package/billing/useBillingAccount.js.map +1 -1
- package/billing/useChangePlan.d.ts +51 -0
- package/billing/useChangePlan.d.ts.map +1 -0
- package/billing/useChangePlan.js +61 -0
- package/billing/useChangePlan.js.map +1 -0
- package/billing/useCreateBillingPortalSession.d.ts +6 -3
- package/billing/useCreateBillingPortalSession.d.ts.map +1 -1
- package/billing/useCreateBillingPortalSession.js +11 -4
- package/billing/useCreateBillingPortalSession.js.map +1 -1
- package/billing/useCreateCheckoutSession.d.ts +7 -5
- package/billing/useCreateCheckoutSession.d.ts.map +1 -1
- package/billing/useCreateCheckoutSession.js +5 -3
- package/billing/useCreateCheckoutSession.js.map +1 -1
- package/billing/useCreatePaymentMethodSetupSession.d.ts +28 -0
- package/billing/useCreatePaymentMethodSetupSession.d.ts.map +1 -0
- package/billing/useCreatePaymentMethodSetupSession.js +50 -0
- package/billing/useCreatePaymentMethodSetupSession.js.map +1 -0
- package/billing/useEntitlements.d.ts +46 -0
- package/billing/useEntitlements.d.ts.map +1 -0
- package/billing/useEntitlements.js +37 -0
- package/billing/useEntitlements.js.map +1 -0
- package/billing/usePeriodEstimate.d.ts +35 -0
- package/billing/usePeriodEstimate.d.ts.map +1 -0
- package/billing/usePeriodEstimate.js +29 -0
- package/billing/usePeriodEstimate.js.map +1 -0
- package/billing/usePlans.d.ts +38 -0
- package/billing/usePlans.d.ts.map +1 -0
- package/billing/usePlans.js +33 -0
- package/billing/usePlans.js.map +1 -0
- package/billing/useSubscription.d.ts +39 -0
- package/billing/useSubscription.d.ts.map +1 -0
- package/billing/useSubscription.js +40 -0
- package/billing/useSubscription.js.map +1 -0
- package/channel-app/ChannelAppDetailPanel.d.ts +5 -0
- package/channel-app/ChannelAppDetailPanel.d.ts.map +1 -1
- package/channel-app/ChannelAppDetailPanel.js +9 -3
- package/channel-app/ChannelAppDetailPanel.js.map +1 -1
- package/channel-app/ChannelAppListPanel.d.ts +13 -4
- package/channel-app/ChannelAppListPanel.d.ts.map +1 -1
- package/channel-app/ChannelAppListPanel.js +5 -5
- package/channel-app/ChannelAppListPanel.js.map +1 -1
- package/channel-app/copy.d.ts +15 -0
- package/channel-app/copy.d.ts.map +1 -0
- package/channel-app/copy.js +15 -0
- package/channel-app/copy.js.map +1 -0
- package/index.d.ts +4 -2
- package/index.d.ts.map +1 -1
- package/index.js +4 -1
- package/index.js.map +1 -1
- package/internal/features.d.ts +11 -0
- package/internal/features.d.ts.map +1 -0
- package/internal/features.js +42 -0
- package/internal/features.js.map +1 -0
- package/licenses/license-format.d.ts +5 -3
- package/licenses/license-format.d.ts.map +1 -1
- package/licenses/license-format.js +10 -19
- package/licenses/license-format.js.map +1 -1
- package/package.json +5 -5
- package/plan-catalog/PlanCatalogConsole.d.ts +22 -0
- package/plan-catalog/PlanCatalogConsole.d.ts.map +1 -0
- package/plan-catalog/PlanCatalogConsole.js +90 -0
- package/plan-catalog/PlanCatalogConsole.js.map +1 -0
- package/plan-catalog/PlanCreateForm.d.ts +17 -0
- package/plan-catalog/PlanCreateForm.d.ts.map +1 -0
- package/plan-catalog/PlanCreateForm.js +52 -0
- package/plan-catalog/PlanCreateForm.js.map +1 -0
- package/plan-catalog/PlansAccessNotice.d.ts +10 -0
- package/plan-catalog/PlansAccessNotice.d.ts.map +1 -0
- package/plan-catalog/PlansAccessNotice.js +13 -0
- package/plan-catalog/PlansAccessNotice.js.map +1 -0
- package/plan-catalog/index.d.ts +8 -0
- package/plan-catalog/index.d.ts.map +1 -0
- package/plan-catalog/index.js +10 -0
- package/plan-catalog/index.js.map +1 -0
- package/plan-catalog/plan-draft.d.ts +30 -0
- package/plan-catalog/plan-draft.d.ts.map +1 -0
- package/plan-catalog/plan-draft.js +91 -0
- package/plan-catalog/plan-draft.js.map +1 -0
- package/plan-catalog/usePlanMutations.d.ts +42 -0
- package/plan-catalog/usePlanMutations.d.ts.map +1 -0
- package/plan-catalog/usePlanMutations.js +57 -0
- package/plan-catalog/usePlanMutations.js.map +1 -0
- package/settings/ChannelAppsSection.d.ts +7 -0
- package/settings/ChannelAppsSection.d.ts.map +1 -1
- package/settings/ChannelAppsSection.js +15 -2
- package/settings/ChannelAppsSection.js.map +1 -1
- package/settings/TeamsSection.d.ts.map +1 -1
- package/settings/TeamsSection.js +19 -2
- package/settings/TeamsSection.js.map +1 -1
- package/settings/settings-nav.d.ts.map +1 -1
- package/settings/settings-nav.js +7 -1
- package/settings/settings-nav.js.map +1 -1
- package/settings/useSettingsNavGroups.d.ts.map +1 -1
- package/settings/useSettingsNavGroups.js +4 -1
- package/settings/useSettingsNavGroups.js.map +1 -1
- package/src/billing/AutoRechargeCard.tsx +2 -2
- package/src/billing/BillingSection.tsx +68 -11
- package/src/billing/ChangePlanDialog.tsx +221 -0
- package/src/billing/CreditPackGrid.tsx +1 -1
- package/src/billing/LowBalanceBanner.tsx +1 -1
- package/src/billing/PaymentMethodCard.tsx +28 -2
- package/src/billing/PlanCard.tsx +171 -0
- package/src/billing/PlanPicker.tsx +178 -0
- package/src/billing/PlanSection.tsx +234 -0
- package/src/billing/UpgradeNotice.tsx +95 -0
- package/src/billing/credit-packs.ts +4 -1
- package/src/billing/index.ts +26 -1
- package/src/billing/plan-features.ts +162 -0
- package/src/billing/plan-state.ts +92 -0
- package/src/billing/redirect.ts +45 -0
- package/src/billing/useBillingAccount.ts +12 -0
- package/src/billing/useChangePlan.ts +115 -0
- package/src/billing/useCreateBillingPortalSession.ts +17 -6
- package/src/billing/useCreateCheckoutSession.ts +12 -7
- package/src/billing/useCreatePaymentMethodSetupSession.ts +77 -0
- package/src/billing/useEntitlements.ts +80 -0
- package/src/billing/usePeriodEstimate.ts +59 -0
- package/src/billing/usePlans.ts +65 -0
- package/src/billing/useSubscription.ts +70 -0
- package/src/channel-app/ChannelAppDetailPanel.tsx +179 -158
- package/src/channel-app/ChannelAppListPanel.tsx +14 -4
- package/src/channel-app/copy.ts +16 -0
- package/src/index.ts +54 -0
- package/src/internal/features.ts +49 -0
- package/src/licenses/license-format.ts +10 -19
- package/src/plan-catalog/PlanCatalogConsole.tsx +197 -0
- package/src/plan-catalog/PlanCreateForm.tsx +167 -0
- package/src/plan-catalog/PlansAccessNotice.tsx +20 -0
- package/src/plan-catalog/index.ts +14 -0
- package/src/plan-catalog/plan-draft.ts +116 -0
- package/src/plan-catalog/usePlanMutations.ts +94 -0
- package/src/settings/ChannelAppsSection.tsx +19 -2
- package/src/settings/TeamsSection.tsx +20 -2
- package/src/settings/settings-nav.ts +7 -0
- package/src/settings/useSettingsNavGroups.ts +8 -1
- package/src/team/CreateTeamForm.tsx +12 -3
- package/src/team/TeamMembersPanel.tsx +6 -2
- package/team/CreateTeamForm.d.ts +6 -1
- package/team/CreateTeamForm.d.ts.map +1 -1
- package/team/CreateTeamForm.js +4 -2
- package/team/CreateTeamForm.js.map +1 -1
- package/team/TeamMembersPanel.d.ts.map +1 -1
- package/team/TeamMembersPanel.js +3 -1
- package/team/TeamMembersPanel.js.map +1 -1
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
whatsappChannelAppWebhookUrl,
|
|
19
19
|
} from "./whatsappAppSetup.js";
|
|
20
20
|
import { CopyBlock, CopyRow, FormField } from "./internal.js";
|
|
21
|
+
import { PermissionGate } from "../iam-policy/PermissionGate.js";
|
|
21
22
|
import { SpinnerIcon } from "../internal/SpinnerIcon.js";
|
|
22
23
|
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
@@ -66,6 +67,11 @@ export interface ChannelAppDetailPanelProps {
|
|
|
66
67
|
* untouched preserves the stored values (rotate one secret without
|
|
67
68
|
* re-entering the others). Deletion is refused server-side while any
|
|
68
69
|
* agent channel still installs through this app.
|
|
70
|
+
*
|
|
71
|
+
* The credentials form is offered to a caller who may edit the app
|
|
72
|
+
* (`can_edit`) and the deletion section to one who may delete it
|
|
73
|
+
* (`can_delete`): its creator and the organization's admins. Someone
|
|
74
|
+
* granted viewer on an app sees its setup values with no actions.
|
|
69
75
|
*/
|
|
70
76
|
export function ChannelAppDetailPanel({
|
|
71
77
|
channelApp,
|
|
@@ -127,50 +133,55 @@ export function ChannelAppDetailPanel({
|
|
|
127
133
|
) : null}
|
|
128
134
|
|
|
129
135
|
{/* Deletion */}
|
|
130
|
-
<
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
<p className="stg:text-xs stg:text-foreground">
|
|
139
|
-
Delete this channel app? Channels installing through it must be
|
|
140
|
-
disconnected first.
|
|
136
|
+
<PermissionGate
|
|
137
|
+
resource={{ kind: "channel_app", id: appId }}
|
|
138
|
+
relation="can_delete"
|
|
139
|
+
>
|
|
140
|
+
<section className="stg:border-t stg:border-border stg:pt-3" aria-label="Danger zone">
|
|
141
|
+
{deleteError && (
|
|
142
|
+
<p className="stg:text-destructive stg:mb-2 stg:text-[0.65rem]" role="alert">
|
|
143
|
+
{getUserMessage(deleteError)}
|
|
141
144
|
</p>
|
|
145
|
+
)}
|
|
146
|
+
{confirmingDelete ? (
|
|
147
|
+
<div className="stg:flex stg:items-center stg:gap-2">
|
|
148
|
+
<p className="stg:text-xs stg:text-foreground">
|
|
149
|
+
Delete this channel app? Channels installing through it must be
|
|
150
|
+
disconnected first.
|
|
151
|
+
</p>
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
onClick={handleDelete}
|
|
155
|
+
disabled={isDeleting}
|
|
156
|
+
className={cn(
|
|
157
|
+
"stg:inline-flex stg:items-center stg:gap-1.5 stg:rounded-md stg:px-2.5 stg:py-1 stg:text-xs stg:font-medium",
|
|
158
|
+
"stg:bg-destructive stg:text-destructive-foreground stg:hover:opacity-90",
|
|
159
|
+
"stg:disabled:pointer-events-none stg:disabled:opacity-40",
|
|
160
|
+
)}
|
|
161
|
+
>
|
|
162
|
+
{isDeleting && <SpinnerIcon size={12} />}
|
|
163
|
+
Delete
|
|
164
|
+
</button>
|
|
165
|
+
<button
|
|
166
|
+
type="button"
|
|
167
|
+
onClick={() => setConfirmingDelete(false)}
|
|
168
|
+
disabled={isDeleting}
|
|
169
|
+
className="stg:text-muted-foreground stg:hover:text-foreground stg:text-xs stg:transition-colors"
|
|
170
|
+
>
|
|
171
|
+
Keep
|
|
172
|
+
</button>
|
|
173
|
+
</div>
|
|
174
|
+
) : (
|
|
142
175
|
<button
|
|
143
176
|
type="button"
|
|
144
|
-
onClick={
|
|
145
|
-
|
|
146
|
-
className={cn(
|
|
147
|
-
"stg:inline-flex stg:items-center stg:gap-1.5 stg:rounded-md stg:px-2.5 stg:py-1 stg:text-xs stg:font-medium",
|
|
148
|
-
"stg:bg-destructive stg:text-destructive-foreground stg:hover:opacity-90",
|
|
149
|
-
"stg:disabled:pointer-events-none stg:disabled:opacity-40",
|
|
150
|
-
)}
|
|
151
|
-
>
|
|
152
|
-
{isDeleting && <SpinnerIcon size={12} />}
|
|
153
|
-
Delete
|
|
154
|
-
</button>
|
|
155
|
-
<button
|
|
156
|
-
type="button"
|
|
157
|
-
onClick={() => setConfirmingDelete(false)}
|
|
158
|
-
disabled={isDeleting}
|
|
159
|
-
className="stg:text-muted-foreground stg:hover:text-foreground stg:text-xs stg:transition-colors"
|
|
177
|
+
onClick={() => setConfirmingDelete(true)}
|
|
178
|
+
className="stg:text-destructive stg:text-xs stg:font-medium stg:hover:opacity-80"
|
|
160
179
|
>
|
|
161
|
-
|
|
180
|
+
Delete channel app
|
|
162
181
|
</button>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
type="button"
|
|
167
|
-
onClick={() => setConfirmingDelete(true)}
|
|
168
|
-
className="stg:text-destructive stg:text-xs stg:font-medium stg:hover:opacity-80"
|
|
169
|
-
>
|
|
170
|
-
Delete channel app
|
|
171
|
-
</button>
|
|
172
|
-
)}
|
|
173
|
-
</section>
|
|
182
|
+
)}
|
|
183
|
+
</section>
|
|
184
|
+
</PermissionGate>
|
|
174
185
|
</div>
|
|
175
186
|
);
|
|
176
187
|
}
|
|
@@ -270,63 +281,68 @@ function SlackAppDetail({
|
|
|
270
281
|
</section>
|
|
271
282
|
|
|
272
283
|
{/* Credential rotation */}
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
label="Client ID"
|
|
284
|
-
value={clientId}
|
|
285
|
-
onChange={setClientId}
|
|
286
|
-
placeholder="1234567890.0987654321"
|
|
287
|
-
disabled={isUpdating}
|
|
288
|
-
required
|
|
289
|
-
/>
|
|
290
|
-
<FormField
|
|
291
|
-
id={`${baseId}-client-secret`}
|
|
292
|
-
label="Client secret"
|
|
293
|
-
value={clientSecret}
|
|
294
|
-
onChange={setClientSecret}
|
|
295
|
-
placeholder="Client secret"
|
|
296
|
-
type="password"
|
|
297
|
-
disabled={isUpdating}
|
|
298
|
-
required
|
|
299
|
-
/>
|
|
300
|
-
<FormField
|
|
301
|
-
id={`${baseId}-signing-secret`}
|
|
302
|
-
label="Signing secret"
|
|
303
|
-
value={signingSecret}
|
|
304
|
-
onChange={setSigningSecret}
|
|
305
|
-
placeholder="Signing secret"
|
|
306
|
-
type="password"
|
|
307
|
-
disabled={isUpdating}
|
|
308
|
-
required
|
|
309
|
-
/>
|
|
310
|
-
|
|
311
|
-
{updateError && (
|
|
312
|
-
<p className="stg:text-destructive stg:text-[0.65rem]" role="alert">
|
|
313
|
-
{getUserMessage(updateError)}
|
|
284
|
+
<PermissionGate
|
|
285
|
+
resource={{ kind: "channel_app", id: appId }}
|
|
286
|
+
relation="can_edit"
|
|
287
|
+
>
|
|
288
|
+
<form onSubmit={handleSave} className="stg:space-y-3" aria-label="Credentials">
|
|
289
|
+
<p className="stg:text-xs stg:font-medium stg:text-foreground">Credentials</p>
|
|
290
|
+
<p className="stg:-mt-2 stg:text-[0.65rem] stg:text-muted-foreground">
|
|
291
|
+
Secrets show as <code className="stg:font-mono">***REDACTED***</code>;
|
|
292
|
+
leave a field untouched to keep its stored value, or paste a new
|
|
293
|
+
one to rotate it.
|
|
314
294
|
</p>
|
|
315
|
-
)}
|
|
316
295
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
"
|
|
323
|
-
|
|
296
|
+
<FormField
|
|
297
|
+
id={`${baseId}-client-id`}
|
|
298
|
+
label="Client ID"
|
|
299
|
+
value={clientId}
|
|
300
|
+
onChange={setClientId}
|
|
301
|
+
placeholder="1234567890.0987654321"
|
|
302
|
+
disabled={isUpdating}
|
|
303
|
+
required
|
|
304
|
+
/>
|
|
305
|
+
<FormField
|
|
306
|
+
id={`${baseId}-client-secret`}
|
|
307
|
+
label="Client secret"
|
|
308
|
+
value={clientSecret}
|
|
309
|
+
onChange={setClientSecret}
|
|
310
|
+
placeholder="Client secret"
|
|
311
|
+
type="password"
|
|
312
|
+
disabled={isUpdating}
|
|
313
|
+
required
|
|
314
|
+
/>
|
|
315
|
+
<FormField
|
|
316
|
+
id={`${baseId}-signing-secret`}
|
|
317
|
+
label="Signing secret"
|
|
318
|
+
value={signingSecret}
|
|
319
|
+
onChange={setSigningSecret}
|
|
320
|
+
placeholder="Signing secret"
|
|
321
|
+
type="password"
|
|
322
|
+
disabled={isUpdating}
|
|
323
|
+
required
|
|
324
|
+
/>
|
|
325
|
+
|
|
326
|
+
{updateError && (
|
|
327
|
+
<p className="stg:text-destructive stg:text-[0.65rem]" role="alert">
|
|
328
|
+
{getUserMessage(updateError)}
|
|
329
|
+
</p>
|
|
324
330
|
)}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
331
|
+
|
|
332
|
+
<button
|
|
333
|
+
type="submit"
|
|
334
|
+
disabled={!canSave}
|
|
335
|
+
className={cn(
|
|
336
|
+
"stg:inline-flex stg:items-center stg:gap-1.5 stg:rounded-md stg:px-3 stg:py-1.5 stg:text-xs stg:font-medium",
|
|
337
|
+
"stg:bg-primary stg:text-primary-foreground stg:hover:bg-primary-hover",
|
|
338
|
+
"stg:disabled:pointer-events-none stg:disabled:opacity-40",
|
|
339
|
+
)}
|
|
340
|
+
>
|
|
341
|
+
{isUpdating && <SpinnerIcon size={12} />}
|
|
342
|
+
Save credentials
|
|
343
|
+
</button>
|
|
344
|
+
</form>
|
|
345
|
+
</PermissionGate>
|
|
330
346
|
</>
|
|
331
347
|
);
|
|
332
348
|
}
|
|
@@ -440,74 +456,79 @@ function WhatsAppAppDetail({
|
|
|
440
456
|
</section>
|
|
441
457
|
|
|
442
458
|
{/* Credential rotation */}
|
|
443
|
-
<
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
label="App ID"
|
|
454
|
-
value={metaAppId}
|
|
455
|
-
onChange={setMetaAppId}
|
|
456
|
-
placeholder="1234567890123456"
|
|
457
|
-
disabled={isUpdating}
|
|
458
|
-
required
|
|
459
|
-
/>
|
|
460
|
-
<FormField
|
|
461
|
-
id={`${baseId}-app-secret`}
|
|
462
|
-
label="App secret"
|
|
463
|
-
value={appSecret}
|
|
464
|
-
onChange={setAppSecret}
|
|
465
|
-
placeholder="App secret"
|
|
466
|
-
type="password"
|
|
467
|
-
disabled={isUpdating}
|
|
468
|
-
required
|
|
469
|
-
/>
|
|
470
|
-
<FormField
|
|
471
|
-
id={`${baseId}-access-token`}
|
|
472
|
-
label="Access token"
|
|
473
|
-
value={accessToken}
|
|
474
|
-
onChange={setAccessToken}
|
|
475
|
-
placeholder="Long-lived system-user access token"
|
|
476
|
-
type="password"
|
|
477
|
-
disabled={isUpdating}
|
|
478
|
-
required
|
|
479
|
-
/>
|
|
480
|
-
<FormField
|
|
481
|
-
id={`${baseId}-verify-token`}
|
|
482
|
-
label="Verify token"
|
|
483
|
-
value={verifyToken}
|
|
484
|
-
onChange={setVerifyToken}
|
|
485
|
-
placeholder="Verify token"
|
|
486
|
-
type="password"
|
|
487
|
-
hint="Rotating it? Update Meta's webhook configuration to the same value."
|
|
488
|
-
disabled={isUpdating}
|
|
489
|
-
required
|
|
490
|
-
/>
|
|
491
|
-
|
|
492
|
-
{updateError && (
|
|
493
|
-
<p className="stg:text-destructive stg:text-[0.65rem]" role="alert">
|
|
494
|
-
{getUserMessage(updateError)}
|
|
459
|
+
<PermissionGate
|
|
460
|
+
resource={{ kind: "channel_app", id: appId }}
|
|
461
|
+
relation="can_edit"
|
|
462
|
+
>
|
|
463
|
+
<form onSubmit={handleSave} className="stg:space-y-3" aria-label="Credentials">
|
|
464
|
+
<p className="stg:text-xs stg:font-medium stg:text-foreground">Credentials</p>
|
|
465
|
+
<p className="stg:-mt-2 stg:text-[0.65rem] stg:text-muted-foreground">
|
|
466
|
+
Secrets show as <code className="stg:font-mono">***REDACTED***</code>;
|
|
467
|
+
leave a field untouched to keep its stored value, or paste a new
|
|
468
|
+
one to rotate it.
|
|
495
469
|
</p>
|
|
496
|
-
)}
|
|
497
470
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
"
|
|
504
|
-
|
|
471
|
+
<FormField
|
|
472
|
+
id={`${baseId}-app-id`}
|
|
473
|
+
label="App ID"
|
|
474
|
+
value={metaAppId}
|
|
475
|
+
onChange={setMetaAppId}
|
|
476
|
+
placeholder="1234567890123456"
|
|
477
|
+
disabled={isUpdating}
|
|
478
|
+
required
|
|
479
|
+
/>
|
|
480
|
+
<FormField
|
|
481
|
+
id={`${baseId}-app-secret`}
|
|
482
|
+
label="App secret"
|
|
483
|
+
value={appSecret}
|
|
484
|
+
onChange={setAppSecret}
|
|
485
|
+
placeholder="App secret"
|
|
486
|
+
type="password"
|
|
487
|
+
disabled={isUpdating}
|
|
488
|
+
required
|
|
489
|
+
/>
|
|
490
|
+
<FormField
|
|
491
|
+
id={`${baseId}-access-token`}
|
|
492
|
+
label="Access token"
|
|
493
|
+
value={accessToken}
|
|
494
|
+
onChange={setAccessToken}
|
|
495
|
+
placeholder="Long-lived system-user access token"
|
|
496
|
+
type="password"
|
|
497
|
+
disabled={isUpdating}
|
|
498
|
+
required
|
|
499
|
+
/>
|
|
500
|
+
<FormField
|
|
501
|
+
id={`${baseId}-verify-token`}
|
|
502
|
+
label="Verify token"
|
|
503
|
+
value={verifyToken}
|
|
504
|
+
onChange={setVerifyToken}
|
|
505
|
+
placeholder="Verify token"
|
|
506
|
+
type="password"
|
|
507
|
+
hint="Rotating it? Update Meta's webhook configuration to the same value."
|
|
508
|
+
disabled={isUpdating}
|
|
509
|
+
required
|
|
510
|
+
/>
|
|
511
|
+
|
|
512
|
+
{updateError && (
|
|
513
|
+
<p className="stg:text-destructive stg:text-[0.65rem]" role="alert">
|
|
514
|
+
{getUserMessage(updateError)}
|
|
515
|
+
</p>
|
|
505
516
|
)}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
517
|
+
|
|
518
|
+
<button
|
|
519
|
+
type="submit"
|
|
520
|
+
disabled={!canSave}
|
|
521
|
+
className={cn(
|
|
522
|
+
"stg:inline-flex stg:items-center stg:gap-1.5 stg:rounded-md stg:px-3 stg:py-1.5 stg:text-xs stg:font-medium",
|
|
523
|
+
"stg:bg-primary stg:text-primary-foreground stg:hover:bg-primary-hover",
|
|
524
|
+
"stg:disabled:pointer-events-none stg:disabled:opacity-40",
|
|
525
|
+
)}
|
|
526
|
+
>
|
|
527
|
+
{isUpdating && <SpinnerIcon size={12} />}
|
|
528
|
+
Save credentials
|
|
529
|
+
</button>
|
|
530
|
+
</form>
|
|
531
|
+
</PermissionGate>
|
|
511
532
|
</>
|
|
512
533
|
);
|
|
513
534
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import type { ReactNode } from "react";
|
|
3
4
|
import { cn } from "@stigmer/theme";
|
|
4
5
|
import { getUserMessage } from "@stigmer/sdk";
|
|
5
6
|
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
|
@@ -22,14 +23,22 @@ export interface ChannelAppListPanelProps {
|
|
|
22
23
|
readonly onEdit?: (app: ChannelApp) => void;
|
|
23
24
|
/** Re-expose refetch so parents can trigger a list refresh. */
|
|
24
25
|
readonly onRefetchRef?: (refetch: () => void) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Shown when the list is empty. Defaults to "No channel apps registered
|
|
28
|
+
* yet." The list holds only the apps the caller may view (their creator,
|
|
29
|
+
* anyone granted viewer on one, and the organization's admins), so a host
|
|
30
|
+
* that knows the caller may not manage channel apps should say who does
|
|
31
|
+
* instead.
|
|
32
|
+
*/
|
|
33
|
+
readonly emptyState?: ReactNode;
|
|
25
34
|
/** Additional CSS class names for the root container. */
|
|
26
35
|
readonly className?: string;
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
/**
|
|
30
|
-
* Displays the {@link ChannelApp} resources
|
|
31
|
-
* the customer's own provider apps (Slack,
|
|
32
|
-
* channels can install through.
|
|
39
|
+
* Displays the {@link ChannelApp} resources of an organization that the
|
|
40
|
+
* caller may view — the customer's own provider apps (Slack,
|
|
41
|
+
* Meta/WhatsApp) that agent channels can install through.
|
|
33
42
|
*
|
|
34
43
|
* Each row shows the app name, provider, the provider's non-secret app
|
|
35
44
|
* identifier, and creation date. Secret fields never appear (they
|
|
@@ -49,6 +58,7 @@ export function ChannelAppListPanel({
|
|
|
49
58
|
org,
|
|
50
59
|
onEdit,
|
|
51
60
|
onRefetchRef,
|
|
61
|
+
emptyState = "No channel apps registered yet.",
|
|
52
62
|
className,
|
|
53
63
|
}: ChannelAppListPanelProps) {
|
|
54
64
|
const { channelApps, isLoading, error, refetch } = useChannelAppList(org);
|
|
@@ -87,7 +97,7 @@ export function ChannelAppListPanel({
|
|
|
87
97
|
className,
|
|
88
98
|
)}
|
|
89
99
|
>
|
|
90
|
-
|
|
100
|
+
{emptyState}
|
|
91
101
|
</p>
|
|
92
102
|
);
|
|
93
103
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel-app copy shared by more than one surface, so the settings section
|
|
3
|
+
* and anything else that lists an organization's channel apps say the same
|
|
4
|
+
* thing.
|
|
5
|
+
*
|
|
6
|
+
* A channel app carries its organization's Slack or Meta app secrets, so the
|
|
7
|
+
* model shows it to its creator, anyone granted viewer on it and the
|
|
8
|
+
* organization's admins, and plain members and viewers may not see it at all
|
|
9
|
+
* (stigmer/stigmer#1384). An empty list is therefore not evidence that none
|
|
10
|
+
* is registered, so a caller who may not create channel apps is told who
|
|
11
|
+
* manages them instead of being told that nothing exists.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Shown in place of the empty state to a caller who may not create channel apps. */
|
|
15
|
+
export const CHANNEL_APPS_MANAGED_BY_ADMINS =
|
|
16
|
+
"Channel apps are managed by your organization's admins.";
|
package/src/index.ts
CHANGED
|
@@ -1160,6 +1160,25 @@ export {
|
|
|
1160
1160
|
useCreateCheckoutSession,
|
|
1161
1161
|
useCreateBillingPortalSession,
|
|
1162
1162
|
useSetAutoRechargeConfig,
|
|
1163
|
+
usePlans,
|
|
1164
|
+
useSubscription,
|
|
1165
|
+
useEntitlements,
|
|
1166
|
+
usePeriodEstimate,
|
|
1167
|
+
useChangePlan,
|
|
1168
|
+
useCancelSubscription,
|
|
1169
|
+
useCreatePaymentMethodSetupSession,
|
|
1170
|
+
planStanding,
|
|
1171
|
+
planMove,
|
|
1172
|
+
PlanSection,
|
|
1173
|
+
PlanCard,
|
|
1174
|
+
PlanPicker,
|
|
1175
|
+
ENTERPRISE_CONTACT_URL,
|
|
1176
|
+
ChangePlanDialog,
|
|
1177
|
+
PAYMENT_METHOD_REQUIRED,
|
|
1178
|
+
UpgradeNotice,
|
|
1179
|
+
planUpgradeFeature,
|
|
1180
|
+
PLAN_UPGRADE_REQUIRED,
|
|
1181
|
+
DEFAULT_BILLING_HREF,
|
|
1163
1182
|
BillingSection,
|
|
1164
1183
|
CreditBalanceCard,
|
|
1165
1184
|
PaymentMethodCard,
|
|
@@ -1178,7 +1197,26 @@ export {
|
|
|
1178
1197
|
formatLedgerDate,
|
|
1179
1198
|
} from "./billing/index.js";
|
|
1180
1199
|
export type {
|
|
1200
|
+
UseBillingAccountOptions,
|
|
1181
1201
|
UseBillingAccountReturn,
|
|
1202
|
+
UsePlansOptions,
|
|
1203
|
+
UsePlansReturn,
|
|
1204
|
+
UseSubscriptionReturn,
|
|
1205
|
+
UseEntitlementsOptions,
|
|
1206
|
+
UseEntitlementsReturn,
|
|
1207
|
+
UsePeriodEstimateOptions,
|
|
1208
|
+
UsePeriodEstimateReturn,
|
|
1209
|
+
UseChangePlanReturn,
|
|
1210
|
+
UseCancelSubscriptionReturn,
|
|
1211
|
+
UseCreatePaymentMethodSetupSessionReturn,
|
|
1212
|
+
BillingRedirect,
|
|
1213
|
+
PlanStanding,
|
|
1214
|
+
PlanMove,
|
|
1215
|
+
PlanSectionProps,
|
|
1216
|
+
PlanCardProps,
|
|
1217
|
+
PlanPickerProps,
|
|
1218
|
+
ChangePlanDialogProps,
|
|
1219
|
+
UpgradeNoticeProps,
|
|
1182
1220
|
UseCreditLedgerReturn,
|
|
1183
1221
|
UseCreditLedgerOptions,
|
|
1184
1222
|
UseBillingUsageReportReturn,
|
|
@@ -1285,6 +1323,22 @@ export type {
|
|
|
1285
1323
|
LicensesConsoleProps,
|
|
1286
1324
|
} from "./licenses/index.js";
|
|
1287
1325
|
|
|
1326
|
+
// Plan catalog — platform-operator management of the Stigmer Cloud plans
|
|
1327
|
+
// organizations subscribe to (gated on can_manage_plans)
|
|
1328
|
+
export {
|
|
1329
|
+
useCreatePlan,
|
|
1330
|
+
useRetirePlan,
|
|
1331
|
+
PlanCatalogConsole,
|
|
1332
|
+
PlanCreateForm,
|
|
1333
|
+
PlansAccessNotice,
|
|
1334
|
+
} from "./plan-catalog/index.js";
|
|
1335
|
+
export type {
|
|
1336
|
+
UseCreatePlanReturn,
|
|
1337
|
+
UseRetirePlanReturn,
|
|
1338
|
+
PlanCatalogConsoleProps,
|
|
1339
|
+
PlanCreateFormProps,
|
|
1340
|
+
} from "./plan-catalog/index.js";
|
|
1341
|
+
|
|
1288
1342
|
// Settings — navigation structure + section components shared across app shells
|
|
1289
1343
|
export {
|
|
1290
1344
|
SETTINGS_NAV_GROUPS,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The one vocabulary for entitlement features: a label and a line per
|
|
2
|
+
// feature, shared by every surface that names one (the licenses console,
|
|
3
|
+
// the plan comparison, the upgrade notice), so a feature reads the same
|
|
4
|
+
// wherever it appears.
|
|
5
|
+
//
|
|
6
|
+
// Keyed by every feature that grants something, so a value added to the
|
|
7
|
+
// contract fails to compile here until it has words. `platform_client` is
|
|
8
|
+
// not one: it gates nothing (platform/v1/entitlement.proto), so no surface
|
|
9
|
+
// names it.
|
|
10
|
+
|
|
11
|
+
import { Feature } from "@stigmer/protos/ai/stigmer/platform/v1/entitlement_pb";
|
|
12
|
+
|
|
13
|
+
/** A feature that grants something: every value but the zero value and `platform_client`. */
|
|
14
|
+
export type NamedFeature = Exclude<Feature, Feature.feature_unspecified | Feature.platform_client>;
|
|
15
|
+
|
|
16
|
+
/** Label and one-line explanation per named feature. */
|
|
17
|
+
export const FEATURE_COPY: Readonly<
|
|
18
|
+
Record<NamedFeature, { readonly label: string; readonly description: string }>
|
|
19
|
+
> = {
|
|
20
|
+
[Feature.sso_enforcement]: {
|
|
21
|
+
label: "SSO enforcement",
|
|
22
|
+
description: "Require members to sign in through a registered identity provider.",
|
|
23
|
+
},
|
|
24
|
+
[Feature.byo_provider_keys]: {
|
|
25
|
+
label: "Bring your own provider keys",
|
|
26
|
+
description: "Use the customer's own LLM provider keys instead of the metered proxy.",
|
|
27
|
+
},
|
|
28
|
+
[Feature.channels]: {
|
|
29
|
+
label: "Channels",
|
|
30
|
+
description: "Deliver agents over messaging channels through a channel runtime.",
|
|
31
|
+
},
|
|
32
|
+
[Feature.sharing]: {
|
|
33
|
+
label: "Sharing",
|
|
34
|
+
description: "Share agents with individuals and guests through hosted links.",
|
|
35
|
+
},
|
|
36
|
+
[Feature.teams]: {
|
|
37
|
+
label: "Teams",
|
|
38
|
+
description: "Group members into teams and grant access to a team at once.",
|
|
39
|
+
},
|
|
40
|
+
[Feature.managed_organizations]: {
|
|
41
|
+
label: "Managed organizations",
|
|
42
|
+
description: "Run organizations for your own customers under your identity provider.",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Whether a stored feature value is one the vocabulary names. */
|
|
47
|
+
export function isNamedFeature(feature: number): feature is NamedFeature {
|
|
48
|
+
return feature in FEATURE_COPY;
|
|
49
|
+
}
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type Entitlements,
|
|
21
21
|
} from "@stigmer/protos/ai/stigmer/platform/v1/entitlement_pb";
|
|
22
22
|
import { LicenseTerm } from "@stigmer/protos/ai/stigmer/platform/v1/license_pb";
|
|
23
|
+
import { FEATURE_COPY } from "../internal/features.js";
|
|
23
24
|
|
|
24
25
|
/** A term an operator can issue; the unspecified zero value is not one. */
|
|
25
26
|
export type IssuableTerm = LicenseTerm.trial | LicenseTerm.paid;
|
|
@@ -59,29 +60,19 @@ export const TERM_LABELS: Readonly<Record<IssuableTerm, string>> = {
|
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
/**
|
|
62
|
-
* Label and one-line explanation per grantable feature
|
|
63
|
-
*
|
|
64
|
-
*
|
|
63
|
+
* Label and one-line explanation per grantable feature: the shared
|
|
64
|
+
* vocabulary (../internal/features.ts), narrowed to what a license may
|
|
65
|
+
* carry. Keyed by every grantable `Feature` value, so a feature added to
|
|
66
|
+
* the contract fails to compile here until it has words an operator can
|
|
67
|
+
* read.
|
|
65
68
|
*/
|
|
66
69
|
export const FEATURE_LABELS: Readonly<
|
|
67
70
|
Record<GrantableFeature, { readonly label: string; readonly description: string }>
|
|
68
71
|
> = {
|
|
69
|
-
[Feature.sso_enforcement]:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
[Feature.byo_provider_keys]: {
|
|
74
|
-
label: "Bring your own provider keys",
|
|
75
|
-
description: "Use the customer's own LLM provider keys instead of the metered proxy.",
|
|
76
|
-
},
|
|
77
|
-
[Feature.channels]: {
|
|
78
|
-
label: "Channels",
|
|
79
|
-
description: "Deliver agents over messaging channels through a channel runtime.",
|
|
80
|
-
},
|
|
81
|
-
[Feature.sharing]: {
|
|
82
|
-
label: "Sharing",
|
|
83
|
-
description: "Share agents with individuals and guests through hosted links.",
|
|
84
|
-
},
|
|
72
|
+
[Feature.sso_enforcement]: FEATURE_COPY[Feature.sso_enforcement],
|
|
73
|
+
[Feature.byo_provider_keys]: FEATURE_COPY[Feature.byo_provider_keys],
|
|
74
|
+
[Feature.channels]: FEATURE_COPY[Feature.channels],
|
|
75
|
+
[Feature.sharing]: FEATURE_COPY[Feature.sharing],
|
|
85
76
|
};
|
|
86
77
|
|
|
87
78
|
/** Every grantable feature, in contract order (derived from the label map). */
|