Settings-01 - Platform Settings

v0.5.0

Platform settings page with organization profile, roles, users, and custom models. Fully controlled — all state and handlers passed via props.

View as Markdown

Preview

Open full page ↗

Install & usage

npx shadcn@latest add @signalos/settings-01

Pulls the page source plus its widget dependencies (@signalos/tokens, @signalos/utils, @signalos/page-header, @signalos/button, @signalos/card, @signalos/dialog, @signalos/dropdown-menu, @signalos/input, @signalos/label, @signalos/skeleton, @signalos/badge, @signalos/data-table, @signalos/form-dialog, @signalos/text-field, @signalos/select, @signalos/icon-button, @signalos/textarea, @signalos/combobox, @signalos/data-primitives) into your app - you own the copy. Requires access.

usage
// after: npx shadcn@latest add @signalos/settings-01
// mount the pulled page in a route, e.g. src/app/settings/page.tsx
import Settings01 from "@/components/blocks/settings-01/Settings01"

export default function Page() {
  return <Settings01 />
}

Props

OrgProfile

PropTypeDefaultDescription
name*string-
email*string-
role*string-

OrgProfileFormValues

PropTypeDefaultDescription
name*string-
email*string-

AdminRole

PropTypeDefaultDescription
idstring | undefined-
name*string-
descriptionstring | undefined-

PlatformUser

PropTypeDefaultDescription
id*string-
full_name*string-
email*string-
role*{ readonly id: string; readonly name: string; }-
active*boolean-

SelectOption

PropTypeDefaultDescription
label*string-
value*string-

ManagerOption

PropTypeDefaultDescription
emailstring | undefined-
value*string-
label*ReactNode-
iconReactNode-
disabledboolean | undefined-
keywordsstring[] | undefined-

UserFormValues

PropTypeDefaultDescription
fullName*string-
escalationManager*string-
role*string-
email*string-
password*string-

UpdatePasswordFormValues

PropTypeDefaultDescription
password*string-

CustomModel

PropTypeDefaultDescription
id*string-
name*string-
provider_kind*CustomModelProviderKind-
model_idstring | null | undefined-
endpoint_urlstring | null | undefined-
api_versionstring | null | undefined-
configRecord<string, unknown> | null | undefined-
has_api_key*boolean-
status*CustomModelStatus-
error_messagestring | null | undefined-
created_at*string-
last_checked_atstring | null | undefined-

Settings01Props

PropTypeDefaultDescription
titlestring | undefined"Platform Settings"
descriptionstring | undefined"Configure global operational parameters, manage organizational identity, and orchestrate external data flow within the SignalOS ecosystem."
headerMetaReactNode-Optional content rendered above the title (e.g. an environment or version banner). Omit to render nothing - the block ships no default value here since there is no environment/version string that is correct for every consumer.
usersTitlestring | undefined"Users List"
usersDescriptionstring | undefined"Manage users and their access permissions"
customModelsTitlestring | undefined"Custom Models"
customModelsDescriptionstring | undefined"Bring your own LLM providers and keys for use across pipelines."
profile*OrgProfile-
dialogOpen*boolean-
onDialogOpenChange*(open: boolean) => void-
formValues*OrgProfileFormValues-
onFormChange*(field: keyof OrgProfileFormValues, value: string) => void-
onSave*() => void-
isSavingboolean | undefined-Shared saving flag for the organization and role dialogs.
orgFormErrorsPartial<Record<keyof OrgProfileFormValues, string>> | undefined-
rolesAdminRole[] | undefined-
isLoadingRolesboolean | undefined-
deletingRoleIdstring | null | undefined-Id of the role currently being deleted (shows the row spinner).
deleteLoadingboolean | undefined-
onAddRole(() => void) | undefined-
onEditRole((role: AdminRole) => void) | undefined-
onDeleteRole((id: string) => void) | undefined-
roleDialogOpen*boolean-
roleDialogMode"edit" | "create" | undefined"create"Whether the role dialog is creating a new role or editing `onEditRole`'s role.
onRoleDialogOpenChange*(open: boolean) => void-
roleForm*{ name: string; description: string; }-
onRoleFormChange*(field: "name" | "description", value: string) => void-
onRoleSave*() => void-
roleFormErrorsPartial<Record<"name" | "description", string>> | undefined-
isRolesSavingboolean | undefined-Saving flag for the role dialog only. Falls back to `isSaving` when omitted, so callers that don't distinguish the two keep today's behavior.
usersPlatformUser[] | undefined-
isLoadingUsersboolean | undefined-
userSearchstring | undefined-
onUserSearchChange((value: string) => void) | undefined-
selectedUserPlatformUser | null | undefined-
onSelectUser((user: PlatformUser | null) => void) | undefined-
onAddUser(() => void) | undefined-
userDialogOpen*boolean-
onUserDialogOpenChange*(open: boolean) => void-
userDialogMode*UserDialogMode-
userForm*UserFormValues-
managerOptions*ManagerOption[]-
onManagerSearchChange((value: string) => void) | undefined-Called as the user types in the escalation-manager combobox search box.
isLoadingManagerOptionsboolean | undefinedfalseShows a loading state in the manager combobox while options are fetched.
roleOptions*SelectOption[]-
onUserFormChange*(field: keyof UserFormValues, value: string) => void-
onUserSave*() => void-
isSavingUserboolean | undefined-
userFormErrorsPartial<Record<"role" | "email" | "password" | "fullName", string>> | undefined-
updatePasswordDialogOpen*boolean-
onUpdatePasswordDialogOpenChange*(open: boolean) => void-
updatePasswordForm*UpdatePasswordFormValues-
onUpdatePasswordChange*(value: string) => void-
onUpdatePasswordSave*() => void-
isSavingPasswordboolean | undefined-
updatePasswordErrors{ password?: string | undefined; } | undefined-
userColumns*ColumnDef<PlatformUser>[]-Column definitions for the users table - the caller owns row actions.
userPagination{ page: number; pageSize: number; total: number; totalPages: number; pageSizeOptions?: number[] | undefined; onPageChange: (page: number) => void; onRowsPerPageChange: (pageSize: number) => void; } | undefined-
customModelsCustomModel[] | undefined-
isLoadingModelsboolean | undefined-
selectedModelCustomModel | null | undefined-
onSelectModel((model: CustomModel | null) => void) | undefined-
onAddModel(() => void) | undefined-
modelColumns*ColumnDef<CustomModel>[]-Column definitions for the models table - the caller owns row actions.
customModelDialogOpenboolean | undefined-
onCustomModelDialogOpenChange((open: boolean) => void) | undefined-
customModelDialogContentClassNamestring | undefined-Overrides the custom-model dialog's content classes (e.g. to widen it for long provider forms).
providersCustomModelProvider[] | undefined-Providers available in the model dialog's provider select.
isLoadingProvidersboolean | undefined-
editingModelboolean | undefined-True when the dialog is editing an existing model (vs creating one).
editingModelHasStoredSecretsboolean | undefined-True when the model being edited has a stored API key (has_api_key).
modelName*string-
providerKind*"" | CustomModelProviderKind-
fields*CustomModelFields-Dynamic field values keyed by `ProviderField.key`.
selectedProviderCustomModelProvider | undefined-
isProviderMissing*boolean-True when the chosen provider's package is not installed server-side.
isTesting*boolean-
isTestSuccessboolean | undefined-
testFeedback{ ok: boolean; message: string; } | null | undefined-
canTest*boolean-True once the form is complete enough to attempt a connection test.
onNameChange*(value: string) => void-
onProviderChange*(value: CustomModelProviderKind) => void-
onFieldChange*(key: string, value: string) => void-
onTest*() => void-
onCustomModelSave(() => void) | undefined-
isSavingModel*boolean-

ProviderField

PropTypeDefaultDescription
key*string-
label*string-
required*boolean-
secret*boolean-
type*ProviderFieldType-
placeholderstring | undefined-

CustomModelProvider

PropTypeDefaultDescription
provider_kind*CustomModelProviderKind-
label*string-
package*string-
installed*boolean-
temperature_max*number-
fields*ProviderField[]-

Supporting types

export type UserDialogMode = "create" | "edit"
export type CustomModelProviderKind =
  | "openai_compatible"
  | "azure_openai"
  | "bedrock"
  | "vertex"
  | "openai"
  | "anthropic"
  | "google_genai"
  | "groq"
  | "mistral"
  | "deepseek"
export type CustomModelStatus = "active" | "error" | "inactive"
export type ProviderFieldType = "text" | "url" | "textarea" | "keyvalue"
export type CustomModelFields = Record<string, string>

Changelog

settings-01

0.5.0

  • Add title/description overrides for the page header, usersTitle/ usersDescription for the Users List section, and customModelsTitle/ customModelsDescription for the Custom Models section - all default to today's copy.
  • Breaking: remove the hardcoded "Console v2.4 / Environment: Production" banner. It was fake data baked into every install with no way to override or remove it. Replaced with an optional headerMeta?: ReactNode slot that renders nothing when omitted - pass your own environment/version content if you need one.
  • Add roleDialogMode?: "create" | "edit" (default "create", matching today's behavior) so RoleDialog can show "Edit Role" copy when editing an existing role via onEditRole. Add isRolesSaving to decouple the role dialog's saving state from the organization dialog's isSaving.
  • managerOptions is now typed ManagerOption[] (a ComboboxOption with an optional email) instead of the plain SelectOption[] - existing SelectOption[] values still satisfy the new type. The escalation-manager combobox now renders an initials avatar + name + email per option instead of a plain label. Add onManagerSearchChange and isLoadingManagerOptions, wired into the combobox's search and loading state.
  • Add customModelDialogContentClassName to override the custom-model dialog's sizing (defaults to today's size).
  • Add stable data-testids: users-section, org-profile-email-value, org-profile-role-value, and the role-modal-*/user-modal-* family on the role and user dialogs' fields, submit, and cancel actions.
  • Wrap the organization-profile card and roles section in self-start containers so the sticky profile card no longer stretches to the roles column's height.

0.4.0

  • Decompose the block: role cards move to components/RoleCard.tsx + components/RolesSection.tsx and the custom-model dialog to components/CustomModelDialog.tsx; the misspelled componets/ folder is renamed to components/ (consumer paths change accordingly).
  • Role card section labels now use the shared SectionLabel from @signalos/data-primitives; the inline SVG header icon is replaced with a lucide icon.
  • Add the missing "use client" directive and remove non-token bg-gray-300 skeleton overrides.
  • Page titles now come from page-header defaults (local overrides removed).
  • API cleanup (breaking): remove unused props onCancel, onEditUser, customModelForm, onCustomModelNameChange, onCustomModelProviderChange, onCustomModelFieldChange, onTestConnection, isTestingModel, and the backend payload types that belonged in the app's API layer. All props are documented and readonly now; RoleDialog/OrganizationDialog switch to named exports. Fix the clear-search button's accessible label.

0.3.13

  • Add validation for all form fields.

0.3.11

  • Add Textarea primitive (@signalos/textarea) and wire it into RoleDialog description field.

0.3.3

  • Version alignment release (no content change recorded).

0.3.0

  • Replace Users and Custom Models list views with the DataTable widget.
  • Add @signalos/data-table registry dependency and @tanstack/react-table npm dependency.

0.2.0

  • Add Users section with search field, Add User button, user rows, and selected-user detail panel.
  • Add Custom Models section with Add Model button, model cards, and selected-model detail panel.
  • Add PlatformUser and CustomModel types; extend Settings01Props with users/models props.
  • All new sections fully controlled via props — no internal state.

0.1.2

  • Fix: add missing imports (lucide-react icons, DropdownMenu sub-components).
  • Fix: remove all internal state from component — roles, loading, and delete state now fully controlled via props.
  • Add AdminRole type and roles-related props to Settings01Props.
  • Update preview to wire up roles state and handlers.

0.1.1

  • Content sync fix to bring source in line with published registry payload.

0.1.0

  • Initial release: organization profile card, roles grid, and settings page scaffolding composed from shared widgets.