Skip to content

Commit 360e7da

Browse files
committed
refactor(setup): reorganize admin nav, demote join tables & metadata
1 parent 6554183 commit 360e7da

13 files changed

Lines changed: 284 additions & 35 deletions

apps/cloud/wrangler.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ compatibility_flags = ["nodejs_compat"]
4545
# rebuild + re-push to ship a new version, then run `wrangler deploy`.
4646
[[containers]]
4747
class_name = "CloudContainer"
48-
image = "registry.cloudflare.com/2846eb40a60f4738e292b90dcd8cce10/objectstack-cloud:acea9591"
48+
image = "registry.cloudflare.com/2846eb40a60f4738e292b90dcd8cce10/objectstack-cloud:1e8014c2"
4949
max_instances = 3
5050
instance_type = "standard-1"
5151

apps/objectos/wrangler.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ compatibility_flags = ["nodejs_compat"]
4444
# rebuild + re-push to ship a new version, then run `wrangler deploy`.
4545
[[containers]]
4646
class_name = "ObjectOSContainer"
47-
image = "registry.cloudflare.com/2846eb40a60f4738e292b90dcd8cce10/objectos:acea9591"
47+
image = "registry.cloudflare.com/2846eb40a60f4738e292b90dcd8cce10/objectos:1e8014c2"
4848
max_instances = 5
4949
instance_type = "standard-1"
5050

packages/platform-objects/src/apps/setup.app.ts

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ export const SETUP_APP: App = {
5757
// and which tenants/teams they belong to. `sys_department` is the
5858
// platform-owned org skeleton (M10.17.1); `sys_team` is better-auth's
5959
// flat collaboration grouping.
60+
//
61+
// M10.30b: removed top-level Department Members / Team Members /
62+
// Org Members entries — they are M:N join tables and the natural
63+
// entry point is the parent record's detail page.
6064
{ id: 'nav_users', type: 'object', label: 'Users', objectName: 'sys_user', icon: 'user' },
6165
{ id: 'nav_departments', type: 'object', label: 'Departments', objectName: 'sys_department', icon: 'building', requiresObject: 'sys_department' },
62-
{ id: 'nav_department_members', type: 'object', label: 'Department Members', objectName: 'sys_department_member', icon: 'user-cog', requiresObject: 'sys_department_member' },
6366
{ id: 'nav_teams', type: 'object', label: 'Teams', objectName: 'sys_team', icon: 'users-round' },
64-
{ id: 'nav_team_members', type: 'object', label: 'Team Members', objectName: 'sys_team_member', icon: 'users' },
6567
{ id: 'nav_organizations', type: 'object', label: 'Organizations', objectName: 'sys_organization', icon: 'building-2' },
66-
{ id: 'nav_members', type: 'object', label: 'Org Members', objectName: 'sys_member', icon: 'user-check' },
6768
{ id: 'nav_invitations', type: 'object', label: 'Invitations', objectName: 'sys_invitation', icon: 'mail' },
6869
],
6970
},
@@ -73,10 +74,11 @@ export const SETUP_APP: App = {
7374
label: 'Access Control',
7475
icon: 'shield',
7576
children: [
77+
// M10.30b: removed top-level User Permission Sets / Role Permission
78+
// Sets entries — same M:N → parent-detail-tab argument as the
79+
// People & Org cleanup.
7680
{ id: 'nav_roles', type: 'object', label: 'Roles', objectName: 'sys_role', icon: 'shield-check' },
7781
{ id: 'nav_permission_sets', type: 'object', label: 'Permission Sets', objectName: 'sys_permission_set', icon: 'lock' },
78-
{ id: 'nav_user_permission_sets', type: 'object', label: 'User Permission Sets', objectName: 'sys_user_permission_set', icon: 'user-check' },
79-
{ id: 'nav_role_permission_sets', type: 'object', label: 'Role Permission Sets', objectName: 'sys_role_permission_set', icon: 'shield-plus' },
8082
{ id: 'nav_sharing_rules', type: 'object', label: 'Sharing Rules', objectName: 'sys_sharing_rule', icon: 'share-2', requiresObject: 'sys_sharing_rule' },
8183
{ id: 'nav_record_shares', type: 'object', label: 'Record Shares', objectName: 'sys_record_share', icon: 'link', requiresObject: 'sys_record_share' },
8284
{ id: 'nav_api_keys', type: 'object', label: 'API Keys', objectName: 'sys_api_key', icon: 'key' },
@@ -93,36 +95,18 @@ export const SETUP_APP: App = {
9395
{ id: 'nav_approval_actions', type: 'object', label: 'Action History', objectName: 'sys_approval_action', icon: 'history', requiresObject: 'sys_approval_action' },
9496
],
9597
},
96-
{
97-
id: 'group_platform',
98-
type: 'group',
99-
label: 'Platform',
100-
icon: 'layers',
101-
children: [
102-
// `sys_app` / `sys_package` / `sys_package_installation` are
103-
// contributed by `@objectstack/service-tenant` (control-plane scope).
104-
// Single-project runtimes do not register them — the `requiresObject`
105-
// capability flag tells the frontend to hide these entries when the
106-
// backing object is not in the SchemaRegistry, avoiding the
107-
// 404-when-clicked trap.
108-
{ id: 'nav_apps', type: 'object', label: 'Apps', objectName: 'sys_app', icon: 'layout-grid', requiresObject: 'sys_app' },
109-
{ id: 'nav_packages', type: 'object', label: 'Packages', objectName: 'sys_package', icon: 'package', requiresObject: 'sys_package' },
110-
{ id: 'nav_package_installations', type: 'object', label: 'Installations', objectName: 'sys_package_installation', icon: 'package-check', requiresObject: 'sys_package_installation' },
111-
{ id: 'nav_metadata', type: 'object', label: 'All Metadata', objectName: 'sys_metadata', icon: 'file-cog' },
112-
],
113-
},
11498
{
11599
id: 'group_diagnostics',
116100
type: 'group',
117101
label: 'Diagnostics',
118102
icon: 'stethoscope',
119103
children: [
120-
// Day-to-day observability surfaces.
104+
// Day-to-day observability surfaces. M10.30b removed `sys_activity`
105+
// and `sys_comment` — both are CRM operational data authored from
106+
// record pages, not platform admin surfaces.
121107
{ id: 'nav_sessions', type: 'object', label: 'Sessions', objectName: 'sys_session', icon: 'monitor' },
122108
{ id: 'nav_audit_logs', type: 'object', label: 'Audit Logs', objectName: 'sys_audit_log', icon: 'scroll-text' },
123-
{ id: 'nav_activity', type: 'object', label: 'Activity', objectName: 'sys_activity', icon: 'activity' },
124109
{ id: 'nav_notifications', type: 'object', label: 'Notifications', objectName: 'sys_notification', icon: 'bell', requiresObject: 'sys_notification' },
125-
{ id: 'nav_comments', type: 'object', label: 'Comments', objectName: 'sys_comment', icon: 'message-square' },
126110
],
127111
},
128112
{
@@ -137,16 +121,26 @@ export const SETUP_APP: App = {
137121
// to SQL. The objectui sidebar collapses this group by default;
138122
// edits should hit the read-only banner since these are all
139123
// `managedBy: 'better-auth'`.
140-
{ id: 'nav_oauth_apps', type: 'object', label: 'OAuth Apps', objectName: 'sys_oauth_application', icon: 'app-window' },
141-
{ id: 'nav_oauth_access_tokens', type: 'object', label: 'OAuth Access Tokens', objectName: 'sys_oauth_access_token', icon: 'key-square' },
142-
{ id: 'nav_oauth_refresh_tokens', type: 'object', label: 'OAuth Refresh Tokens', objectName: 'sys_oauth_refresh_token', icon: 'refresh-cw' },
143-
{ id: 'nav_oauth_consents', type: 'object', label: 'OAuth Consents', objectName: 'sys_oauth_consent', icon: 'check-square' },
124+
//
125+
// M10.30b changes:
126+
// - Removed the 3 OAuth satellite menus (access tokens / refresh
127+
// tokens / consents). They live under their parent OAuth App.
128+
// - Renamed "Linked Accounts" → "Identity Links" to distinguish
129+
// from sys_user / org members.
130+
// - Demoted "All Metadata" from the (now-deleted) Platform group
131+
// to this Advanced/debug bucket.
132+
// - The marketplace-only `sys_app` / `sys_package` /
133+
// `sys_package_installation` menus have been removed entirely;
134+
// they are contributed by `@objectstack/service-tenant`
135+
// (control-plane) and are not present in single-project runtimes.
136+
{ id: 'nav_oauth_apps', type: 'object', label: 'OAuth Applications', objectName: 'sys_oauth_application', icon: 'app-window' },
144137
{ id: 'nav_jwks', type: 'object', label: 'Signing Keys (JWKS)', objectName: 'sys_jwks', icon: 'key-round' },
145138
{ id: 'nav_verifications', type: 'object', label: 'Verifications', objectName: 'sys_verification', icon: 'mail-check' },
146139
{ id: 'nav_two_factor', type: 'object', label: 'Two-Factor', objectName: 'sys_two_factor', icon: 'smartphone' },
147140
{ id: 'nav_device_codes', type: 'object', label: 'Device Codes', objectName: 'sys_device_code', icon: 'qr-code' },
148-
{ id: 'nav_accounts', type: 'object', label: 'Linked Accounts', objectName: 'sys_account', icon: 'link-2' },
141+
{ id: 'nav_accounts', type: 'object', label: 'Identity Links', objectName: 'sys_account', icon: 'link-2' },
149142
{ id: 'nav_user_preferences', type: 'object', label: 'User Preferences', objectName: 'sys_user_preference', icon: 'sliders' },
143+
{ id: 'nav_metadata', type: 'object', label: 'All Metadata', objectName: 'sys_metadata', icon: 'file-cog' },
150144
],
151145
},
152146
],

packages/platform-objects/src/identity/sys-department.object.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,48 @@ export const SysDepartment = ObjectSchema.create({
3232
titleFormat: '{name}',
3333
compactLayout: ['name', 'kind', 'parent_department_id', 'manager_user_id'],
3434

35+
listViews: {
36+
active: {
37+
type: 'grid',
38+
name: 'active',
39+
label: 'Active',
40+
data: { provider: 'object', object: 'sys_department' },
41+
columns: ['name', 'code', 'kind', 'parent_department_id', 'manager_user_id', 'effective_from'],
42+
filter: [{ field: 'active', operator: 'equals', value: true }],
43+
sort: [{ field: 'name', order: 'asc' }],
44+
pagination: { pageSize: 100 },
45+
},
46+
inactive: {
47+
type: 'grid',
48+
name: 'inactive',
49+
label: 'Inactive',
50+
data: { provider: 'object', object: 'sys_department' },
51+
columns: ['name', 'code', 'kind', 'effective_to'],
52+
filter: [{ field: 'active', operator: 'equals', value: false }],
53+
sort: [{ field: 'effective_to', order: 'desc' }],
54+
pagination: { pageSize: 50 },
55+
},
56+
by_kind: {
57+
type: 'grid',
58+
name: 'by_kind',
59+
label: 'By Kind',
60+
data: { provider: 'object', object: 'sys_department' },
61+
columns: ['kind', 'name', 'code', 'parent_department_id', 'manager_user_id', 'active'],
62+
sort: [{ field: 'kind', order: 'asc' }, { field: 'name', order: 'asc' }],
63+
grouping: { fields: [{ field: 'kind', order: 'asc', collapsed: false }] },
64+
pagination: { pageSize: 100 },
65+
},
66+
all_departments: {
67+
type: 'grid',
68+
name: 'all_departments',
69+
label: 'All',
70+
data: { provider: 'object', object: 'sys_department' },
71+
columns: ['name', 'code', 'kind', 'parent_department_id', 'manager_user_id', 'active'],
72+
sort: [{ field: 'name', order: 'asc' }],
73+
pagination: { pageSize: 100 },
74+
},
75+
},
76+
3577
fields: {
3678
// ── Identity ─────────────────────────────────────────────────
3779
name: Field.text({

packages/platform-objects/src/identity/sys-invitation.object.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,48 @@ export const SysInvitation = ObjectSchema.create({
2020
description: 'Organization invitations for user onboarding',
2121
titleFormat: 'Invitation to {organization_id}',
2222
compactLayout: ['email', 'organization_id', 'status'],
23+
24+
listViews: {
25+
pending: {
26+
type: 'grid',
27+
name: 'pending',
28+
label: 'Pending',
29+
data: { provider: 'object', object: 'sys_invitation' },
30+
columns: ['email', 'role', 'organization_id', 'inviter_id', 'expires_at'],
31+
filter: [{ field: 'status', operator: 'equals', value: 'pending' }],
32+
sort: [{ field: 'expires_at', order: 'asc' }],
33+
pagination: { pageSize: 50 },
34+
},
35+
accepted: {
36+
type: 'grid',
37+
name: 'accepted',
38+
label: 'Accepted',
39+
data: { provider: 'object', object: 'sys_invitation' },
40+
columns: ['email', 'role', 'organization_id', 'inviter_id', 'created_at'],
41+
filter: [{ field: 'status', operator: 'equals', value: 'accepted' }],
42+
sort: [{ field: 'created_at', order: 'desc' }],
43+
pagination: { pageSize: 50 },
44+
},
45+
expired: {
46+
type: 'grid',
47+
name: 'expired',
48+
label: 'Expired / Canceled',
49+
data: { provider: 'object', object: 'sys_invitation' },
50+
columns: ['email', 'status', 'organization_id', 'expires_at'],
51+
filter: [{ field: 'status', operator: 'in', value: ['expired', 'rejected', 'canceled'] }],
52+
sort: [{ field: 'expires_at', order: 'desc' }],
53+
pagination: { pageSize: 50 },
54+
},
55+
all_invitations: {
56+
type: 'grid',
57+
name: 'all_invitations',
58+
label: 'All',
59+
data: { provider: 'object', object: 'sys_invitation' },
60+
columns: ['email', 'status', 'role', 'organization_id', 'inviter_id', 'created_at'],
61+
sort: [{ field: 'created_at', order: 'desc' }],
62+
pagination: { pageSize: 50 },
63+
},
64+
},
2365

2466
fields: {
2567
id: Field.text({

packages/platform-objects/src/identity/sys-organization.object.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ export const SysOrganization = ObjectSchema.create({
2222
titleFormat: '{name}',
2323
compactLayout: ['name', 'slug'],
2424

25+
listViews: {
26+
all_orgs: {
27+
type: 'grid',
28+
name: 'all_orgs',
29+
label: 'All',
30+
data: { provider: 'object', object: 'sys_organization' },
31+
columns: ['name', 'slug', 'created_at', 'updated_at'],
32+
sort: [{ field: 'name', order: 'asc' }],
33+
pagination: { pageSize: 50 },
34+
},
35+
},
36+
2537
fields: {
2638
// ── Identity ─────────────────────────────────────────────────
2739
name: Field.text({

packages/platform-objects/src/identity/sys-session.object.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,28 @@ export const SysSession = ObjectSchema.create({
2626
titleFormat: 'Session — {user_id}',
2727
compactLayout: ['user_id', 'ip_address', 'expires_at'],
2828

29+
listViews: {
30+
mine: {
31+
type: 'grid',
32+
name: 'mine',
33+
label: 'My Sessions',
34+
data: { provider: 'object', object: 'sys_session' },
35+
columns: ['ip_address', 'active_organization_id', 'created_at', 'expires_at'],
36+
filter: [{ field: 'user_id', operator: 'equals', value: '{current_user_id}' }],
37+
sort: [{ field: 'created_at', order: 'desc' }],
38+
pagination: { pageSize: 50 },
39+
},
40+
all_sessions: {
41+
type: 'grid',
42+
name: 'all_sessions',
43+
label: 'All',
44+
data: { provider: 'object', object: 'sys_session' },
45+
columns: ['user_id', 'ip_address', 'active_organization_id', 'created_at', 'expires_at'],
46+
sort: [{ field: 'created_at', order: 'desc' }],
47+
pagination: { pageSize: 50 },
48+
},
49+
},
50+
2951
fields: {
3052
// ── Session owner & expiry ──────────────────────────────────
3153
user_id: Field.lookup('sys_user', {

packages/platform-objects/src/identity/sys-team.object.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,28 @@ export const SysTeam = ObjectSchema.create({
2222
titleFormat: '{name}',
2323
compactLayout: ['name', 'organization_id'],
2424

25+
listViews: {
26+
by_org: {
27+
type: 'grid',
28+
name: 'by_org',
29+
label: 'By Organization',
30+
data: { provider: 'object', object: 'sys_team' },
31+
columns: ['organization_id', 'name', 'created_at', 'updated_at'],
32+
sort: [{ field: 'organization_id', order: 'asc' }, { field: 'name', order: 'asc' }],
33+
grouping: { fields: [{ field: 'organization_id', order: 'asc', collapsed: false }] },
34+
pagination: { pageSize: 100 },
35+
},
36+
all_teams: {
37+
type: 'grid',
38+
name: 'all_teams',
39+
label: 'All',
40+
data: { provider: 'object', object: 'sys_team' },
41+
columns: ['name', 'organization_id', 'created_at', 'updated_at'],
42+
sort: [{ field: 'name', order: 'asc' }],
43+
pagination: { pageSize: 50 },
44+
},
45+
},
46+
2547
fields: {
2648
// ── Identity ─────────────────────────────────────────────────
2749
name: Field.text({

packages/platform-objects/src/identity/sys-user-preference.object.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ export const SysUserPreference = ObjectSchema.create({
2222
pluralLabel: 'User Preferences',
2323
icon: 'settings',
2424
isSystem: true,
25-
managedBy: 'platform',
25+
// managedBy: 'system' — preferences are per-user state authored from
26+
// the user's own settings page, never created by an admin. The list
27+
// surface in Setup is a support/diagnostic view only.
28+
managedBy: 'system',
2629
description: 'Per-user key-value preferences (theme, locale, etc.)',
2730
titleFormat: '{key}',
2831
compactLayout: ['user_id', 'key'],

packages/platform-objects/src/identity/sys-user.object.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,38 @@ export const SysUser = ObjectSchema.create({
2525
titleFormat: '{name}',
2626
compactLayout: ['name', 'email', 'email_verified'],
2727

28+
listViews: {
29+
all_users: {
30+
type: 'grid',
31+
name: 'all_users',
32+
label: 'All Users',
33+
data: { provider: 'object', object: 'sys_user' },
34+
columns: ['name', 'email', 'email_verified', 'two_factor_enabled', 'created_at'],
35+
sort: [{ field: 'name', order: 'asc' }],
36+
pagination: { pageSize: 50 },
37+
},
38+
unverified: {
39+
type: 'grid',
40+
name: 'unverified',
41+
label: 'Unverified',
42+
data: { provider: 'object', object: 'sys_user' },
43+
columns: ['name', 'email', 'created_at'],
44+
filter: [{ field: 'email_verified', operator: 'equals', value: false }],
45+
sort: [{ field: 'created_at', order: 'desc' }],
46+
pagination: { pageSize: 50 },
47+
},
48+
two_factor: {
49+
type: 'grid',
50+
name: 'two_factor',
51+
label: '2FA Enabled',
52+
data: { provider: 'object', object: 'sys_user' },
53+
columns: ['name', 'email', 'two_factor_enabled', 'updated_at'],
54+
filter: [{ field: 'two_factor_enabled', operator: 'equals', value: true }],
55+
sort: [{ field: 'name', order: 'asc' }],
56+
pagination: { pageSize: 50 },
57+
},
58+
},
59+
2860
fields: {
2961
// ── Identity (primary business fields) ───────────────────────
3062
name: Field.text({

0 commit comments

Comments
 (0)