@streamoid/settings 0.4.7 → 0.6.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/dist/index.mjs CHANGED
@@ -7,7 +7,6 @@ import {
7
7
  } from "react";
8
8
  import {
9
9
  ScSidebarMenu,
10
- ScVDivider,
11
10
  ScHDivider,
12
11
  ScMenuOptions
13
12
  } from "@streamoid/ui";
@@ -1476,7 +1475,11 @@ var TAB_LABELS = {
1476
1475
  organizationWorkspaces: "Workspaces",
1477
1476
  organizationDomains: "Domains & requests",
1478
1477
  referral: "Referral",
1479
- billing: "Billing",
1478
+ /* "Billing & usage", not "Billing". The tab has held usage history as well
1479
+ as the plan and invoices since the credits work, and hosts had started
1480
+ saying "Billing & usage" in their own rails while this said "Billing" —
1481
+ so the nav item and the thing it opened disagreed by a word. */
1482
+ billing: "Billing & usage",
1480
1483
  apikey: "API Keys"
1481
1484
  };
1482
1485
  var TAB_DESCRIPTIONS = {
@@ -1564,7 +1567,7 @@ function ScopeHeader({
1564
1567
  }) {
1565
1568
  const displayName = name?.trim() || (kind === "workspace" ? "Workspace" : "Organization");
1566
1569
  const ScopeIcon = kind === "workspace" ? SiconWorkspace : SiconGlobe;
1567
- const roleLabel = role === "admin" ? "You're an admin" : role ? "You're a member" : null;
1570
+ const roleLabel = role === "admin" ? "You're an admin" : role === "member" ? "You're a member" : role === "guest" ? "You're a guest" : null;
1568
1571
  const detail = [roleLabel, ...facts].filter((part) => typeof part === "string" && part.length > 0).join(" \xB7 ");
1569
1572
  return /* @__PURE__ */ jsxs5(
1570
1573
  "div",
@@ -2062,8 +2065,9 @@ function OrganizationAffiliationCard({
2062
2065
  let cancelled = false;
2063
2066
  organizationAdapter.list().then((orgs) => {
2064
2067
  if (cancelled) return;
2065
- setAvailableOrgs(orgs);
2066
- setSelectedOrgId((prev) => prev || orgs[0]?._id || "");
2068
+ const joinable = orgs.filter((org) => org.role !== "guest");
2069
+ setAvailableOrgs(joinable);
2070
+ setSelectedOrgId((prev) => prev || joinable[0]?._id || "");
2067
2071
  }).catch(() => {
2068
2072
  if (!cancelled) setAvailableOrgs([]);
2069
2073
  });
@@ -2564,12 +2568,19 @@ function InviteUpdateModal({
2564
2568
  onSave,
2565
2569
  onRemove,
2566
2570
  canRemove = true,
2571
+ showOrganizationStanding = false,
2572
+ organizationName,
2573
+ allowGuestStanding = true,
2574
+ initialOrganizationStanding = "guest",
2567
2575
  onInvite
2568
2576
  }) {
2569
2577
  useOverlayOpen(open, onClose);
2570
2578
  const [emailValue, setEmailValue] = useState5("");
2571
2579
  const [hasChanges, setHasChanges] = useState5(false);
2572
2580
  const [role, setRole] = useState5("admin");
2581
+ const [orgStanding, setOrgStanding] = useState5(
2582
+ initialOrganizationStanding
2583
+ );
2573
2584
  const [canUseCredits, setCanUseCredits] = useState5(false);
2574
2585
  const [canInviteUser, setCanInviteUser] = useState5(false);
2575
2586
  const [artifaxOn, setArtifaxOn] = useState5(!hiddenApps.includes("artifax"));
@@ -2606,6 +2617,7 @@ function InviteUpdateModal({
2606
2617
  setEmailValue("");
2607
2618
  setHasChanges(false);
2608
2619
  setRole("admin");
2620
+ setOrgStanding(initialOrganizationStanding);
2609
2621
  setCanUseCredits(true);
2610
2622
  setCanInviteUser(true);
2611
2623
  setArtifaxOn(!hidden.has("artifax"));
@@ -2615,7 +2627,7 @@ function InviteUpdateModal({
2615
2627
  setStoreSearch("");
2616
2628
  setSelectedStores(/* @__PURE__ */ new Set());
2617
2629
  }
2618
- }, [open, initialPermissions, hiddenKey]);
2630
+ }, [open, initialPermissions, hiddenKey, initialOrganizationStanding]);
2619
2631
  if (!open) return null;
2620
2632
  const isInvite = mode === "invite";
2621
2633
  const hasEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue.trim());
@@ -2991,6 +3003,95 @@ function InviteUpdateModal({
2991
3003
  ]
2992
3004
  }
2993
3005
  ),
3006
+ showOrganizationStanding && mode === "invite" && /* @__PURE__ */ jsxs8(
3007
+ "div",
3008
+ {
3009
+ className: "flex flex-col items-start justify-center shrink-0 w-full",
3010
+ style: { gap: T6.spXs },
3011
+ children: [
3012
+ /* @__PURE__ */ jsx10(FieldLabel2, { text: "Organization access" }),
3013
+ /* @__PURE__ */ jsxs8(
3014
+ "div",
3015
+ {
3016
+ className: "shrink-0 w-full relative",
3017
+ style: { borderRadius: T6.rXl },
3018
+ children: [
3019
+ /* @__PURE__ */ jsx10(
3020
+ "div",
3021
+ {
3022
+ "aria-hidden": true,
3023
+ className: "absolute inset-0 pointer-events-none",
3024
+ style: {
3025
+ border: `0.5px solid ${T6.borderSubtle}`,
3026
+ borderRadius: T6.rXl
3027
+ }
3028
+ }
3029
+ ),
3030
+ /* @__PURE__ */ jsx10("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsx10(
3031
+ "div",
3032
+ {
3033
+ className: "flex items-center w-full",
3034
+ style: { padding: T6.spXs },
3035
+ children: [
3036
+ ["colleague", "Colleague"],
3037
+ ...allowGuestStanding ? [["guest", "Guest"]] : []
3038
+ ].map(([value, label]) => /* @__PURE__ */ jsx10(
3039
+ "div",
3040
+ {
3041
+ className: "flex-1 min-w-0 cursor-pointer",
3042
+ style: {
3043
+ background: orgStanding === value ? T6.neutral300 : "transparent",
3044
+ borderRadius: T6.rMd
3045
+ },
3046
+ onClick: () => {
3047
+ setOrgStanding(value);
3048
+ markChanged();
3049
+ },
3050
+ children: /* @__PURE__ */ jsx10("div", { className: "flex flex-row items-center justify-center size-full", children: /* @__PURE__ */ jsx10(
3051
+ "div",
3052
+ {
3053
+ className: "flex items-center justify-center w-full",
3054
+ style: { padding: T6.spMd },
3055
+ children: /* @__PURE__ */ jsx10(
3056
+ "span",
3057
+ {
3058
+ style: {
3059
+ fontFamily: T6.font,
3060
+ fontSize: T6.fsSm,
3061
+ fontWeight: orgStanding === value ? 500 : 400,
3062
+ lineHeight: T6.lhSm,
3063
+ color: orgStanding === value ? T6.inverse : T6.muted,
3064
+ textAlign: "center"
3065
+ },
3066
+ children: label
3067
+ }
3068
+ )
3069
+ }
3070
+ ) })
3071
+ },
3072
+ value
3073
+ ))
3074
+ }
3075
+ ) })
3076
+ ]
3077
+ }
3078
+ ),
3079
+ /* @__PURE__ */ jsx10(
3080
+ "span",
3081
+ {
3082
+ style: {
3083
+ fontFamily: T6.font,
3084
+ fontSize: T6.fsXs,
3085
+ fontWeight: 400,
3086
+ lineHeight: T6.lhXs,
3087
+ color: T6.tertiary
3088
+ },
3089
+ children: orgStanding === "colleague" ? `Joins ${organizationName || "the organization"} as a member \u2014 they'll also see its shared workspaces.` : `This workspace only. They see nothing else in ${organizationName || "the organization"}.`
3090
+ }
3091
+ )
3092
+ ]
3093
+ }
3094
+ ),
2994
3095
  role !== "admin" && shownApps.length > 0 && /* @__PURE__ */ jsxs8(
2995
3096
  "div",
2996
3097
  {
@@ -3623,7 +3724,11 @@ function InviteUpdateModal({
3623
3724
  catalogixStores: role === "admin" || showsApp("catalogix") ? Array.from(selectedStores) : []
3624
3725
  };
3625
3726
  if (isInvite && onInvite) {
3626
- onInvite(perms, emailValue.trim());
3727
+ onInvite(
3728
+ perms,
3729
+ emailValue.trim(),
3730
+ showOrganizationStanding ? orgStanding : void 0
3731
+ );
3627
3732
  } else if (onSave) {
3628
3733
  onSave(perms);
3629
3734
  }
@@ -4353,7 +4458,7 @@ function TeamsContent({
4353
4458
  organizationName,
4354
4459
  hiddenApps
4355
4460
  } = {}) {
4356
- const { auth, api, workspace, toast } = useSettingsAdapters();
4461
+ const { auth, api, workspace, organization, toast } = useSettingsAdapters();
4357
4462
  const user = auth.user;
4358
4463
  const [activeTab, setActiveTab] = useState6("active");
4359
4464
  const [activeMembers, setActiveMembers] = useState6([]);
@@ -4655,7 +4760,7 @@ function TeamsContent({
4655
4760
  toast.error(msg);
4656
4761
  }
4657
4762
  };
4658
- const handleInvite = async (permissions, email) => {
4763
+ const handleInvite = async (permissions, email, organizationStanding) => {
4659
4764
  if (highestRole === "member") {
4660
4765
  toast.error("You do not have permission to invite users");
4661
4766
  closeModal();
@@ -4669,7 +4774,12 @@ function TeamsContent({
4669
4774
  inviteAccess: permissions.canInviteUser,
4670
4775
  role: permissions.role,
4671
4776
  serviceIds,
4672
- storeIds: permissions.catalogixStores || []
4777
+ storeIds: permissions.catalogixStores || [],
4778
+ // Omitted when the control was never shown, which leaves the backend
4779
+ // deriving the standing from the invitee's email domain as before.
4780
+ ...organizationStanding ? {
4781
+ organizationRole: organizationStanding === "colleague" ? "member" : "guest"
4782
+ } : {}
4673
4783
  });
4674
4784
  toast.success(`Invitation sent to ${email}`);
4675
4785
  await fetchData();
@@ -4690,6 +4800,9 @@ function TeamsContent({
4690
4800
  const members = activeTab === "active" ? filteredActive : filteredPending;
4691
4801
  const workspaceCurrent = workspace.current;
4692
4802
  const orgVisibility = workspaceCurrent?.orgVisibility ?? "private";
4803
+ const workspaceOrgId = workspaceCurrent?.organizationId;
4804
+ const orgCurrent = organization.current;
4805
+ const mayGrantOrgMembership = !!workspaceOrgId && orgCurrent?.id === workspaceOrgId && orgCurrent?.role !== "guest" && (orgCurrent?.role === "admin" || orgCurrent?.inviteAccess === true);
4693
4806
  const teamInnerContent = /* @__PURE__ */ jsxs10(Fragment6, { children: [
4694
4807
  /* @__PURE__ */ jsx12(
4695
4808
  ScopeHeader,
@@ -4797,6 +4910,8 @@ function TeamsContent({
4797
4910
  // Must be admin or have invite permission, AND cannot remove yourself
4798
4911
  (highestRole === "admin" || currentMemberPermissions?.canInviteUser === true) && modal.target?.userId !== user?.id
4799
4912
  ),
4913
+ showOrganizationStanding: mayGrantOrgMembership,
4914
+ organizationName: organizationName ?? orgCurrent?.name,
4800
4915
  onInvite: handleInvite
4801
4916
  }
4802
4917
  )
@@ -5005,6 +5120,10 @@ function OrganizationInviteModal({
5005
5120
  mode,
5006
5121
  userEmail = "email@domain.in",
5007
5122
  initialRole,
5123
+ lockRole,
5124
+ canClaimDomain = true,
5125
+ claimableDomain,
5126
+ lockedRoleLabel,
5008
5127
  initialInviteAccess,
5009
5128
  allowSubmitWithoutChanges = false,
5010
5129
  canRemove = true,
@@ -5017,7 +5136,7 @@ function OrganizationInviteModal({
5017
5136
  useOverlayOpen(open, onClose);
5018
5137
  const [inviteMode, setInviteMode] = useState7("email");
5019
5138
  const [emailValue, setEmailValue] = useState7("");
5020
- const [domainValue, setDomainValue] = useState7("");
5139
+ const [domainValue, setDomainValue] = useState7(claimableDomain ?? "");
5021
5140
  const [hasChanges, setHasChanges] = useState7(false);
5022
5141
  const [role, setRole] = useState7("admin");
5023
5142
  const [inviteAccess, setInviteAccess] = useState7(false);
@@ -5029,19 +5148,22 @@ function OrganizationInviteModal({
5029
5148
  if (!open) {
5030
5149
  setInviteMode("email");
5031
5150
  setEmailValue("");
5032
- setDomainValue("");
5151
+ setDomainValue(claimableDomain ?? "");
5033
5152
  setHasChanges(false);
5034
5153
  setRole("admin");
5035
5154
  setInviteAccess(true);
5036
5155
  }
5037
- }, [open, mode, initialRole, initialInviteAccess]);
5156
+ }, [open, mode, initialRole, initialInviteAccess, claimableDomain]);
5038
5157
  if (!open) return null;
5039
5158
  const isInvite = mode === "invite";
5040
5159
  const isEmailInvite = isInvite && inviteMode === "email";
5041
5160
  const isDomainInvite = isInvite && inviteMode === "domain";
5042
5161
  const hasEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue.trim());
5043
5162
  const hasDomain = /^[^\s@]+\.[^\s@]+$/.test(domainValue.trim());
5044
- const isSubmitDisabled = isEmailInvite ? !hasEmail : isDomainInvite ? !hasDomain : !(allowSubmitWithoutChanges || hasChanges);
5163
+ const isSubmitDisabled = isEmailInvite ? !hasEmail : isDomainInvite ? !hasDomain : (
5164
+ // A locked role has nothing this modal can legitimately submit.
5165
+ lockRole || !(allowSubmitWithoutChanges || hasChanges)
5166
+ );
5045
5167
  function markChanged() {
5046
5168
  setHasChanges(true);
5047
5169
  }
@@ -5116,7 +5238,7 @@ function OrganizationInviteModal({
5116
5238
  className: "flex flex-col items-start w-full",
5117
5239
  style: { padding: `${T9.sp3xl} ${T9.sp6xl}`, gap: T9.sp3xl },
5118
5240
  children: [
5119
- isInvite && /* @__PURE__ */ jsxs11(
5241
+ isInvite && canClaimDomain && /* @__PURE__ */ jsxs11(
5120
5242
  "div",
5121
5243
  {
5122
5244
  className: "flex flex-col items-start justify-center shrink-0 w-full",
@@ -5177,9 +5299,9 @@ function OrganizationInviteModal({
5177
5299
  }
5178
5300
  ),
5179
5301
  isDomainInvite && /* @__PURE__ */ jsx13(
5180
- "input",
5302
+ "span",
5181
5303
  {
5182
- className: "flex-1 min-w-0 bg-transparent border-none outline-none",
5304
+ className: "flex-1 min-w-0 truncate",
5183
5305
  style: {
5184
5306
  fontFamily: T9.font,
5185
5307
  fontSize: T9.fsSm,
@@ -5187,9 +5309,7 @@ function OrganizationInviteModal({
5187
5309
  lineHeight: T9.lhSm,
5188
5310
  color: T9.primary
5189
5311
  },
5190
- placeholder: "streamoid.com",
5191
- value: domainValue,
5192
- onChange: (e) => setDomainValue(e.target.value)
5312
+ children: domainValue
5193
5313
  }
5194
5314
  ),
5195
5315
  !isInvite && /* @__PURE__ */ jsx13(
@@ -5222,9 +5342,10 @@ function OrganizationInviteModal({
5222
5342
  color: T9.muted
5223
5343
  },
5224
5344
  children: [
5225
- "Anyone signing up or logging in with a verified ",
5226
- domainValue.trim() || "this",
5227
- " email address will automatically join this organization going forward."
5345
+ "Anyone who signs up or logs in with an @",
5346
+ domainValue.trim(),
5347
+ " ",
5348
+ "address will automatically join this organization from now on."
5228
5349
  ]
5229
5350
  }
5230
5351
  )
@@ -5238,7 +5359,21 @@ function OrganizationInviteModal({
5238
5359
  style: { gap: T9.spXs },
5239
5360
  children: [
5240
5361
  /* @__PURE__ */ jsx13(FieldLabel3, { text: isDomainInvite ? "Auto-join role" : "Role" }),
5241
- /* @__PURE__ */ jsx13(
5362
+ lockRole ? /* @__PURE__ */ jsxs11(
5363
+ "span",
5364
+ {
5365
+ style: {
5366
+ fontFamily: T9.font,
5367
+ fontSize: T9.fsSm,
5368
+ lineHeight: T9.lhSm,
5369
+ color: T9.muted
5370
+ },
5371
+ children: [
5372
+ lockedRoleLabel || "Guest",
5373
+ " \u2014 invited to specific workspaces only, with no access to the rest of the organization. Remove them to end that access."
5374
+ ]
5375
+ }
5376
+ ) : /* @__PURE__ */ jsx13(
5242
5377
  SegmentedToggle,
5243
5378
  {
5244
5379
  options: [
@@ -5256,7 +5391,7 @@ function OrganizationInviteModal({
5256
5391
  ]
5257
5392
  }
5258
5393
  ),
5259
- !isDomainInvite && role === "member" && /* @__PURE__ */ jsxs11(
5394
+ !isDomainInvite && !lockRole && role === "member" && /* @__PURE__ */ jsxs11(
5260
5395
  "div",
5261
5396
  {
5262
5397
  className: "flex items-center shrink-0 w-full cursor-pointer",
@@ -5770,6 +5905,12 @@ function OrganizationModal({
5770
5905
 
5771
5906
  // src/organization-content.tsx
5772
5907
  import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
5908
+ function orgRoleLabel(role) {
5909
+ if (role === "admin") return "Org admin";
5910
+ if (role === "member") return "Member";
5911
+ if (role === "guest") return "Guest";
5912
+ return role || "Member";
5913
+ }
5773
5914
  var T11 = {
5774
5915
  primary: "var(--alias-text---icons-primary)",
5775
5916
  inverse: "var(--alias-text---icons-inverse)",
@@ -5913,7 +6054,7 @@ function MemberRow({
5913
6054
  RoleChip,
5914
6055
  {
5915
6056
  role: member.role === "admin" ? "admin" : "member",
5916
- label: member.role === "admin" ? "Org admin" : "Member"
6057
+ label: orgRoleLabel(member.role)
5917
6058
  }
5918
6059
  ),
5919
6060
  /* @__PURE__ */ jsx15(
@@ -6021,7 +6162,7 @@ function InviteRow({
6021
6162
  RoleChip,
6022
6163
  {
6023
6164
  role: role === "admin" ? "admin" : "member",
6024
- label: role === "admin" ? "Org admin" : "Member"
6165
+ label: orgRoleLabel(role)
6025
6166
  }
6026
6167
  ),
6027
6168
  /* @__PURE__ */ jsx15(
@@ -6168,7 +6309,8 @@ function JoinRequestRow({
6168
6309
  function Section({
6169
6310
  title,
6170
6311
  children,
6171
- empty
6312
+ empty,
6313
+ emptyText
6172
6314
  }) {
6173
6315
  return /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-start shrink-0 w-full", style: { gap: T11.spMd }, children: [
6174
6316
  /* @__PURE__ */ jsx15(
@@ -6203,7 +6345,7 @@ function Section({
6203
6345
  lineHeight: T11.lhSm,
6204
6346
  color: T11.muted
6205
6347
  },
6206
- children: "Nothing here yet"
6348
+ children: emptyText ?? "Nothing here yet"
6207
6349
  }
6208
6350
  ) }) : children
6209
6351
  }
@@ -6223,7 +6365,9 @@ function OrganizationContent({
6223
6365
  const [invites, setInvites] = useState9([]);
6224
6366
  const [workspaces, setWorkspaces] = useState9([]);
6225
6367
  const [joinRequests, setJoinRequests] = useState9([]);
6226
- const [highestRole, setHighestRole] = useState9("admin");
6368
+ const [highestRole, setHighestRole] = useState9("guest");
6369
+ const [emailDomain, setEmailDomain] = useState9(null);
6370
+ const [canClaimEmailDomain, setCanClaimEmailDomain] = useState9(true);
6227
6371
  const [searchQuery, setSearchQuery] = useState9("");
6228
6372
  const [loadingData, setLoadingData] = useState9(false);
6229
6373
  const [modal, setModal] = useState9({ open: false, mode: "invite" });
@@ -6238,6 +6382,12 @@ function OrganizationContent({
6238
6382
  organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null)
6239
6383
  ]);
6240
6384
  if (highestRoleRes?.role) setHighestRole(highestRoleRes.role);
6385
+ if (highestRoleRes?.emailDomain !== void 0) {
6386
+ setEmailDomain(highestRoleRes.emailDomain ?? null);
6387
+ }
6388
+ if (highestRoleRes?.canClaimEmailDomain !== void 0) {
6389
+ setCanClaimEmailDomain(highestRoleRes.canClaimEmailDomain);
6390
+ }
6241
6391
  if (membersRes) setMembers(membersRes.filter((m) => m?.user));
6242
6392
  if (invitesRes) setInvites(invitesRes);
6243
6393
  if (workspacesRes) setWorkspaces(workspacesRes);
@@ -6328,7 +6478,7 @@ function OrganizationContent({
6328
6478
  const openUpdateModal = (member) => setModal({ open: true, mode: "update", target: member });
6329
6479
  const closeModal = () => setModal({ open: false, mode: "invite" });
6330
6480
  const handleInviteEmail = async (input) => {
6331
- if (highestRole === "member") {
6481
+ if (highestRole !== "admin") {
6332
6482
  toast.error("You do not have permission to invite members");
6333
6483
  closeModal();
6334
6484
  return;
@@ -6343,7 +6493,7 @@ function OrganizationContent({
6343
6493
  }
6344
6494
  };
6345
6495
  const handleInviteDomain = async (input) => {
6346
- if (highestRole === "member") {
6496
+ if (highestRole !== "admin") {
6347
6497
  toast.error("You do not have permission to invite members");
6348
6498
  closeModal();
6349
6499
  return;
@@ -6363,7 +6513,7 @@ function OrganizationContent({
6363
6513
  closeModal();
6364
6514
  return;
6365
6515
  }
6366
- if (highestRole === "member") {
6516
+ if (highestRole !== "admin") {
6367
6517
  toast.error("You do not have permission to manage members");
6368
6518
  closeModal();
6369
6519
  return;
@@ -6396,7 +6546,7 @@ function OrganizationContent({
6396
6546
  closeModal();
6397
6547
  return;
6398
6548
  }
6399
- if (highestRole === "member") {
6549
+ if (highestRole !== "admin") {
6400
6550
  toast.error("You do not have permission to manage members");
6401
6551
  closeModal();
6402
6552
  return;
@@ -6415,7 +6565,7 @@ function OrganizationContent({
6415
6565
  closeModal();
6416
6566
  };
6417
6567
  const handleCancelInvite = async (invite) => {
6418
- if (highestRole === "member") {
6568
+ if (highestRole !== "admin") {
6419
6569
  toast.error("You do not have permission to manage invites");
6420
6570
  return;
6421
6571
  }
@@ -6440,7 +6590,7 @@ function OrganizationContent({
6440
6590
  };
6441
6591
  const handleResendInvite = async (invite) => {
6442
6592
  if (invite.kind !== "email") return;
6443
- if (highestRole === "member") {
6593
+ if (highestRole !== "admin") {
6444
6594
  toast.error("You do not have permission to invite members");
6445
6595
  return;
6446
6596
  }
@@ -6656,14 +6806,22 @@ function OrganizationContent({
6656
6806
  }
6657
6807
  );
6658
6808
  const domainsView = /* @__PURE__ */ jsxs13(Fragment9, { children: [
6659
- /* @__PURE__ */ jsx15(Section, { title: "Auto-join by email domain", empty: domainInvites.length === 0, children: domainInvites.map((inv) => /* @__PURE__ */ jsx15(
6660
- InviteRow,
6809
+ /* @__PURE__ */ jsx15(
6810
+ Section,
6661
6811
  {
6662
- invite: inv,
6663
- onCancel: () => void handleCancelInvite(inv)
6664
- },
6665
- inv._id
6666
- )) }),
6812
+ title: "Auto-join by email domain",
6813
+ empty: domainInvites.length === 0,
6814
+ emptyText: canClaimEmailDomain ? void 0 : `Auto-join needs a company email domain.${emailDomain ? ` ${emailDomain} is a public email provider, so it` : " A public email provider"} can't be claimed \u2014 invite people by email instead.`,
6815
+ children: domainInvites.map((inv) => /* @__PURE__ */ jsx15(
6816
+ InviteRow,
6817
+ {
6818
+ invite: inv,
6819
+ onCancel: () => void handleCancelInvite(inv)
6820
+ },
6821
+ inv._id
6822
+ ))
6823
+ }
6824
+ ),
6667
6825
  /* @__PURE__ */ jsx15(
6668
6826
  Section,
6669
6827
  {
@@ -6693,10 +6851,14 @@ function OrganizationContent({
6693
6851
  open: modal.open,
6694
6852
  mode: modal.mode,
6695
6853
  userEmail: modal.target?.user.email,
6696
- initialRole: modal.target?.role,
6854
+ initialRole: modal.target?.role === "admin" || modal.target?.role === "member" ? modal.target.role : void 0,
6697
6855
  initialInviteAccess: modal.target?.inviteAccess,
6698
6856
  allowSubmitWithoutChanges: false,
6857
+ lockRole: modal.target?.role === "guest",
6858
+ lockedRoleLabel: orgRoleLabel(modal.target?.role),
6699
6859
  canRemove: highestRole === "admin",
6860
+ canClaimDomain: canClaimEmailDomain,
6861
+ claimableDomain: emailDomain,
6700
6862
  onClose: closeModal,
6701
6863
  onInviteEmail: handleInviteEmail,
6702
6864
  onInviteDomain: handleInviteDomain,
@@ -6766,7 +6928,7 @@ function OrganizationContent({
6766
6928
  variant: "primary",
6767
6929
  size: "md",
6768
6930
  styleVariant: "icon-left",
6769
- state: highestRole === "member" ? "disabled" : "default",
6931
+ state: highestRole !== "admin" ? "disabled" : "default",
6770
6932
  icon: /* @__PURE__ */ jsx15(SiconUserAdd2, { className: "w-5 h-5", color: "var(--alias-text---icons-inverse)" }),
6771
6933
  onClick: openInviteModal
6772
6934
  }
@@ -10818,194 +10980,202 @@ function ProfileTab() {
10818
10980
  }
10819
10981
  auth.clearAuth();
10820
10982
  };
10821
- return /* @__PURE__ */ jsx20(
10983
+ return /* @__PURE__ */ jsxs18(
10822
10984
  "div",
10823
10985
  {
10824
10986
  className: "flex flex-col items-start flex-1 min-w-0",
10825
10987
  style: { gap: "var(--spacing-3xl)" },
10826
- children: /* @__PURE__ */ jsxs18(
10827
- "div",
10828
- {
10829
- className: "flex items-start w-full",
10830
- style: {
10831
- backgroundColor: "var(--alias-surface-base)",
10832
- borderRadius: "var(--radius-3xl)",
10833
- border: "1px solid var(--alias-border-subtle)",
10834
- padding: "var(--spacing-6xl)",
10835
- gap: "var(--spacing-6xl)"
10836
- },
10837
- children: [
10838
- /* @__PURE__ */ jsxs18(
10839
- "div",
10840
- {
10841
- className: "flex flex-col items-center shrink-0",
10842
- style: { gap: "var(--spacing-md)", width: 120 },
10843
- children: [
10844
- profileImage ? /* @__PURE__ */ jsx20(
10845
- "img",
10846
- {
10847
- src: profileImage,
10848
- alt: "Profile",
10849
- style: {
10850
- width: 100,
10851
- height: 100,
10852
- borderRadius: "var(--radius-full)",
10853
- objectFit: "cover",
10854
- flexShrink: 0
10855
- }
10856
- }
10857
- ) : /* @__PURE__ */ jsx20(
10858
- "div",
10859
- {
10860
- "aria-label": "Profile",
10861
- className: "flex items-center justify-center",
10862
- style: {
10863
- width: 100,
10864
- height: 100,
10865
- borderRadius: "var(--radius-full)",
10866
- backgroundColor: "var(--alias-surface-raised)",
10867
- border: "1px solid var(--alias-border-subtle)",
10868
- flexShrink: 0
10869
- },
10870
- children: /* @__PURE__ */ jsx20(
10871
- "span",
10872
- {
10873
- style: {
10874
- color: "var(--alias-text---icons-primary)",
10875
- fontFamily: "var(--font-family-font-family-display)",
10876
- fontSize: 34,
10877
- fontWeight: 600,
10878
- lineHeight: "34px"
10879
- },
10880
- children: profileInitial
10988
+ children: [
10989
+ /* @__PURE__ */ jsxs18(
10990
+ "div",
10991
+ {
10992
+ className: "flex items-start w-full",
10993
+ style: {
10994
+ backgroundColor: "var(--alias-surface-base)",
10995
+ borderRadius: "var(--radius-3xl)",
10996
+ border: "1px solid var(--alias-border-subtle)",
10997
+ padding: "var(--spacing-6xl)",
10998
+ gap: "var(--spacing-6xl)"
10999
+ },
11000
+ children: [
11001
+ /* @__PURE__ */ jsxs18(
11002
+ "div",
11003
+ {
11004
+ className: "flex flex-col items-center shrink-0",
11005
+ style: { gap: "var(--spacing-md)", width: 120 },
11006
+ children: [
11007
+ profileImage ? /* @__PURE__ */ jsx20(
11008
+ "img",
11009
+ {
11010
+ src: profileImage,
11011
+ alt: "Profile",
11012
+ style: {
11013
+ width: 100,
11014
+ height: 100,
11015
+ borderRadius: "var(--radius-full)",
11016
+ objectFit: "cover",
11017
+ flexShrink: 0
10881
11018
  }
10882
- )
10883
- }
10884
- ),
10885
- /* @__PURE__ */ jsx20(
10886
- "input",
10887
- {
10888
- ref: fileInputRef,
10889
- type: "file",
10890
- accept: "image/*",
10891
- style: { display: "none" },
10892
- onChange: handleImageChange
10893
- }
10894
- ),
10895
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-center", style: { gap: 10 }, children: [
10896
- /* @__PURE__ */ jsx20(
10897
- ScButton7,
11019
+ }
11020
+ ) : /* @__PURE__ */ jsx20(
11021
+ "div",
10898
11022
  {
10899
- icon: /* @__PURE__ */ jsx20(SiconUpload2, { className: "w-5 h-5", color: PRIMARY_COLOR3 }),
10900
- styleVariant: "icon-only",
10901
- variant: "tertiary",
10902
- size: "md",
10903
- state: disableAllActions ? "disabled" : "default",
10904
- onClick: handleUploadClick
11023
+ "aria-label": "Profile",
11024
+ className: "flex items-center justify-center",
11025
+ style: {
11026
+ width: 100,
11027
+ height: 100,
11028
+ borderRadius: "var(--radius-full)",
11029
+ backgroundColor: "var(--alias-surface-raised)",
11030
+ border: "1px solid var(--alias-border-subtle)",
11031
+ flexShrink: 0
11032
+ },
11033
+ children: /* @__PURE__ */ jsx20(
11034
+ "span",
11035
+ {
11036
+ style: {
11037
+ color: "var(--alias-text---icons-primary)",
11038
+ fontFamily: "var(--font-family-font-family-display)",
11039
+ fontSize: 34,
11040
+ fontWeight: 600,
11041
+ lineHeight: "34px"
11042
+ },
11043
+ children: profileInitial
11044
+ }
11045
+ )
10905
11046
  }
10906
11047
  ),
10907
- /* @__PURE__ */ jsx20(ScVDivider, {}),
10908
11048
  /* @__PURE__ */ jsx20(
10909
- ScButton7,
11049
+ "input",
10910
11050
  {
10911
- icon: /* @__PURE__ */ jsx20(
10912
- SiconDelete,
10913
- {
10914
- className: "w-5 h-5",
10915
- color: "var(--primitives-error-500)"
10916
- }
10917
- ),
10918
- styleVariant: "icon-only",
10919
- variant: "tertiary",
10920
- size: "md",
10921
- state: disableAllActions || !profileImage ? "disabled" : "default",
10922
- onClick: handleDeleteImage
11051
+ ref: fileInputRef,
11052
+ type: "file",
11053
+ accept: "image/*",
11054
+ style: { display: "none" },
11055
+ onChange: handleImageChange
11056
+ }
11057
+ ),
11058
+ /* @__PURE__ */ jsxs18(
11059
+ "div",
11060
+ {
11061
+ className: "flex flex-col items-stretch w-full",
11062
+ style: { gap: "var(--spacing-md)" },
11063
+ children: [
11064
+ /* @__PURE__ */ jsx20(
11065
+ ScButton7,
11066
+ {
11067
+ text: "Upload photo",
11068
+ icon: /* @__PURE__ */ jsx20(SiconUpload2, { className: "w-5 h-5", color: PRIMARY_COLOR3 }),
11069
+ styleVariant: "icon-left",
11070
+ variant: "outline",
11071
+ size: "md",
11072
+ state: disableAllActions ? "disabled" : "default",
11073
+ onClick: handleUploadClick
11074
+ }
11075
+ ),
11076
+ /* @__PURE__ */ jsx20(
11077
+ ScButton7,
11078
+ {
11079
+ text: "Remove photo",
11080
+ icon: /* @__PURE__ */ jsx20(
11081
+ SiconDelete,
11082
+ {
11083
+ className: "w-5 h-5",
11084
+ color: PRIMARY_COLOR3
11085
+ }
11086
+ ),
11087
+ styleVariant: "icon-left",
11088
+ variant: "outline",
11089
+ size: "md",
11090
+ state: disableAllActions || !profileImage ? "disabled" : "default",
11091
+ onClick: handleDeleteImage
11092
+ }
11093
+ )
11094
+ ]
10923
11095
  }
10924
11096
  )
10925
- ] })
10926
- ]
10927
- }
10928
- ),
10929
- /* @__PURE__ */ jsx20(
10930
- "div",
10931
- {
10932
- className: "shrink-0",
10933
- style: {
10934
- width: 0,
10935
- alignSelf: "stretch",
10936
- borderLeft: "0.5px solid var(--alias-border-divider)"
11097
+ ]
10937
11098
  }
10938
- }
10939
- ),
10940
- /* @__PURE__ */ jsxs18(
10941
- "div",
10942
- {
10943
- className: "flex flex-col flex-1 min-w-0",
10944
- style: { gap: "var(--spacing-3xl)" },
10945
- children: [
10946
- /* @__PURE__ */ jsxs18("div", { className: "flex items-start w-full", style: { gap: "var(--spacing-3xl)" }, children: [
10947
- /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx20(
11099
+ ),
11100
+ /* @__PURE__ */ jsx20(
11101
+ "div",
11102
+ {
11103
+ className: "shrink-0",
11104
+ style: {
11105
+ width: 0,
11106
+ alignSelf: "stretch",
11107
+ borderLeft: "0.5px solid var(--alias-border-divider)"
11108
+ }
11109
+ }
11110
+ ),
11111
+ /* @__PURE__ */ jsxs18(
11112
+ "div",
11113
+ {
11114
+ className: "flex flex-col flex-1 min-w-0",
11115
+ style: { gap: "var(--spacing-3xl)" },
11116
+ children: [
11117
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-start w-full", style: { gap: "var(--spacing-3xl)" }, children: [
11118
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx20(
11119
+ ScTextField,
11120
+ {
11121
+ label: "Full Name",
11122
+ labelGroup: "label",
11123
+ state: "filled",
11124
+ placeholderFilled: "Enter your name",
11125
+ tfGroup: "none",
11126
+ className: "sc-text-field-full-width",
11127
+ style: { width: "100%" },
11128
+ value: fullName,
11129
+ onChange: (e) => setFullName(e.target.value)
11130
+ }
11131
+ ) }),
11132
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx20(
11133
+ SpecializationDropdown,
11134
+ {
11135
+ value: selectedSpec,
11136
+ onChange: setSelectedSpec,
11137
+ disabled: disableAllActions
11138
+ }
11139
+ ) })
11140
+ ] }),
11141
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-start w-full", style: { gap: "var(--spacing-3xl)" }, children: [
11142
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx20(
11143
+ LanguageDropdown,
11144
+ {
11145
+ value: selectedLanguage,
11146
+ onChange: setSelectedLanguage,
11147
+ disabled: disableAllActions
11148
+ }
11149
+ ) }),
11150
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0" })
11151
+ ] }),
11152
+ /* @__PURE__ */ jsx20("div", { className: "w-full", style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx20(
10948
11153
  ScTextField,
10949
11154
  {
10950
- label: "Full Name",
11155
+ label: "Email ID",
10951
11156
  labelGroup: "label",
10952
- state: "filled",
10953
- placeholderFilled: "Enter your name",
10954
- tfGroup: "none",
11157
+ state: "default",
11158
+ value: user?.email ?? "",
11159
+ placeholderFilled: user?.email ?? "chris@kepler.com",
11160
+ tfGroup: "icon-right",
11161
+ tfRightIcon: /* @__PURE__ */ jsx20(
11162
+ SiconLock,
11163
+ {
11164
+ className: "w-6 h-6",
11165
+ color: "var(--alias-text---icons-primary)"
11166
+ }
11167
+ ),
10955
11168
  className: "sc-text-field-full-width",
10956
11169
  style: { width: "100%" },
10957
- value: fullName,
10958
- onChange: (e) => setFullName(e.target.value)
11170
+ readOnly: true
10959
11171
  }
10960
11172
  ) }),
10961
- /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx20(
10962
- SpecializationDropdown,
10963
- {
10964
- value: selectedSpec,
10965
- onChange: setSelectedSpec,
10966
- disabled: disableAllActions
10967
- }
10968
- ) })
10969
- ] }),
10970
- /* @__PURE__ */ jsxs18("div", { className: "flex items-start w-full", style: { gap: "var(--spacing-3xl)" }, children: [
10971
- /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx20(
10972
- LanguageDropdown,
11173
+ /* @__PURE__ */ jsx20(
11174
+ "div",
10973
11175
  {
10974
- value: selectedLanguage,
10975
- onChange: setSelectedLanguage,
10976
- disabled: disableAllActions
10977
- }
10978
- ) }),
10979
- /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0" })
10980
- ] }),
10981
- /* @__PURE__ */ jsx20("div", { className: "w-full", style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx20(
10982
- ScTextField,
10983
- {
10984
- label: "Email ID",
10985
- labelGroup: "label",
10986
- state: "default",
10987
- value: user?.email ?? "",
10988
- placeholderFilled: user?.email ?? "chris@kepler.com",
10989
- tfGroup: "icon-right",
10990
- tfRightIcon: /* @__PURE__ */ jsx20(
10991
- SiconLock,
10992
- {
10993
- className: "w-6 h-6",
10994
- color: "var(--alias-text---icons-primary)"
10995
- }
10996
- ),
10997
- className: "sc-text-field-full-width",
10998
- style: { width: "100%" },
10999
- readOnly: true
11000
- }
11001
- ) }),
11002
- /* @__PURE__ */ jsxs18(
11003
- "div",
11004
- {
11005
- className: "flex items-center w-full",
11006
- style: { gap: "var(--spacing-3xl)", justifyContent: "flex-end", paddingTop: "var(--spacing-md)" },
11007
- children: [
11008
- /* @__PURE__ */ jsx20(
11176
+ className: "flex items-center w-full",
11177
+ style: { justifyContent: "flex-end", paddingTop: "var(--spacing-md)" },
11178
+ children: /* @__PURE__ */ jsx20(
11009
11179
  ScButton7,
11010
11180
  {
11011
11181
  text: saving ? "Saving..." : "Save changes",
@@ -11014,25 +11184,69 @@ function ProfileTab() {
11014
11184
  state: saving || !dirty ? "disabled" : "default",
11015
11185
  onClick: handleSave
11016
11186
  }
11017
- ),
11018
- /* @__PURE__ */ jsx20(
11019
- ScButton7,
11020
- {
11021
- text: "Logout",
11022
- variant: "error",
11023
- size: "md",
11024
- onClick: handleLogout
11025
- }
11026
11187
  )
11027
- ]
11028
- }
11029
- )
11030
- ]
11031
- }
11032
- )
11033
- ]
11034
- }
11035
- )
11188
+ }
11189
+ )
11190
+ ]
11191
+ }
11192
+ )
11193
+ ]
11194
+ }
11195
+ ),
11196
+ /* @__PURE__ */ jsxs18(
11197
+ "div",
11198
+ {
11199
+ className: "flex items-center w-full",
11200
+ style: {
11201
+ backgroundColor: "var(--alias-surface-base)",
11202
+ borderRadius: "var(--radius-3xl)",
11203
+ border: "1px solid var(--alias-border-subtle)",
11204
+ padding: "var(--spacing-6xl)",
11205
+ gap: "var(--spacing-3xl)"
11206
+ },
11207
+ children: [
11208
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col min-w-0 flex-1", style: { gap: "var(--spacing-xs)" }, children: [
11209
+ /* @__PURE__ */ jsx20(
11210
+ "span",
11211
+ {
11212
+ style: {
11213
+ fontFamily: "var(--font-family-font-family-body)",
11214
+ fontSize: "var(--font-size-font-size-md)",
11215
+ fontWeight: 600,
11216
+ lineHeight: "var(--line-height-line-height-md)",
11217
+ color: "var(--alias-text---icons-primary)"
11218
+ },
11219
+ children: "Session"
11220
+ }
11221
+ ),
11222
+ /* @__PURE__ */ jsx20(
11223
+ "span",
11224
+ {
11225
+ className: "truncate",
11226
+ style: {
11227
+ fontFamily: "var(--font-family-font-family-body)",
11228
+ fontSize: "var(--font-size-font-size-sm)",
11229
+ lineHeight: "var(--line-height-line-height-sm)",
11230
+ color: "var(--alias-text---icons-muted)"
11231
+ },
11232
+ title: user?.email ?? void 0,
11233
+ children: user?.email ? `Signed in as ${user.email}` : "Signed in"
11234
+ }
11235
+ )
11236
+ ] }),
11237
+ /* @__PURE__ */ jsx20(
11238
+ ScButton7,
11239
+ {
11240
+ text: "Log out",
11241
+ variant: "outline",
11242
+ size: "md",
11243
+ onClick: handleLogout
11244
+ }
11245
+ )
11246
+ ]
11247
+ }
11248
+ )
11249
+ ]
11036
11250
  }
11037
11251
  );
11038
11252
  }
@@ -11251,6 +11465,7 @@ function SettingsContent({
11251
11465
  adapters,
11252
11466
  activeTab = "profile",
11253
11467
  onClose,
11468
+ onBack,
11254
11469
  hiddenApps
11255
11470
  }) {
11256
11471
  return /* @__PURE__ */ jsx20(SettingsAdaptersProvider, { adapters, children: /* @__PURE__ */ jsx20(
@@ -11258,6 +11473,7 @@ function SettingsContent({
11258
11473
  {
11259
11474
  activeTab,
11260
11475
  onClose: onClose ?? adapters.navigation.close,
11476
+ onBack: onBack === null ? null : onBack ?? adapters.navigation.back,
11261
11477
  hiddenApps
11262
11478
  }
11263
11479
  ) });
@@ -11265,6 +11481,7 @@ function SettingsContent({
11265
11481
  function SettingsContentInner({
11266
11482
  activeTab,
11267
11483
  onClose,
11484
+ onBack,
11268
11485
  hiddenApps
11269
11486
  }) {
11270
11487
  const {
@@ -11635,6 +11852,33 @@ function SettingsContentInner({
11635
11852
  width: "100%"
11636
11853
  },
11637
11854
  children: /* @__PURE__ */ jsxs18("div", { className: "flex flex-col w-full flex-1 min-h-0", style: { gap: 20, paddingTop: 16 }, children: [
11855
+ onBack !== null && /* @__PURE__ */ jsx20("div", { className: "flex items-center shrink-0", style: { paddingLeft: 20 }, children: /* @__PURE__ */ jsxs18(
11856
+ "button",
11857
+ {
11858
+ type: "button",
11859
+ "aria-label": "Back to previous screen",
11860
+ className: "flex items-center cursor-pointer",
11861
+ style: {
11862
+ gap: "var(--spacing-sm)",
11863
+ padding: "var(--spacing-xs) var(--spacing-md)",
11864
+ marginLeft: "calc(var(--spacing-md) * -1)",
11865
+ border: "1px solid transparent",
11866
+ borderRadius: "var(--radius-xl)",
11867
+ background: "transparent",
11868
+ height: 32,
11869
+ color: "var(--alias-text---icons-muted)",
11870
+ fontFamily: "var(--font-family-font-family-body)",
11871
+ fontSize: "var(--font-size-font-size-sm)",
11872
+ fontWeight: 500,
11873
+ lineHeight: "var(--line-height-line-height-sm)"
11874
+ },
11875
+ onClick: () => onBack ? onBack() : window.history.back(),
11876
+ children: [
11877
+ /* @__PURE__ */ jsx20(SiconLeft3, { className: "w-4 h-4 shrink-0", color: "var(--alias-text---icons-muted)" }),
11878
+ "Back"
11879
+ ]
11880
+ }
11881
+ ) }),
11638
11882
  /* @__PURE__ */ jsxs18(
11639
11883
  "div",
11640
11884
  {