@kelpie/ui 0.3.0 → 0.4.0

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.
Files changed (102) hide show
  1. package/dist/api/ApiProvider.d.ts +3 -3
  2. package/dist/api/ApiProvider.d.ts.map +1 -1
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +4 -1
  5. package/dist/api/client.js.map +1 -1
  6. package/dist/api/resources/agentTasks.d.ts +2 -2
  7. package/dist/api/resources/agentTasks.d.ts.map +1 -1
  8. package/dist/api/resources/candidates.d.ts +4 -4
  9. package/dist/api/resources/candidates.d.ts.map +1 -1
  10. package/dist/api/resources/companies.d.ts +4 -4
  11. package/dist/api/resources/companies.d.ts.map +1 -1
  12. package/dist/api/resources/deals.d.ts +6 -6
  13. package/dist/api/resources/deals.d.ts.map +1 -1
  14. package/dist/api/resources/decisions.d.ts +3 -3
  15. package/dist/api/resources/decisions.d.ts.map +1 -1
  16. package/dist/api/resources/forms.d.ts +3 -3
  17. package/dist/api/resources/forms.d.ts.map +1 -1
  18. package/dist/api/resources/handbookPages.d.ts +3 -3
  19. package/dist/api/resources/handbookPages.d.ts.map +1 -1
  20. package/dist/api/resources/notes.d.ts +2 -2
  21. package/dist/api/resources/notes.d.ts.map +1 -1
  22. package/dist/api/resources/opportunities.d.ts +6 -6
  23. package/dist/api/resources/opportunities.d.ts.map +1 -1
  24. package/dist/api/resources/partnerships.d.ts +7 -7
  25. package/dist/api/resources/partnerships.d.ts.map +1 -1
  26. package/dist/api/resources/people.d.ts +4 -4
  27. package/dist/api/resources/people.d.ts.map +1 -1
  28. package/dist/api/resources/planItems.d.ts +6 -6
  29. package/dist/api/resources/planItems.d.ts.map +1 -1
  30. package/dist/api/resources/positions.d.ts +3 -3
  31. package/dist/api/resources/positions.d.ts.map +1 -1
  32. package/dist/api/resources/raises.d.ts +6 -6
  33. package/dist/api/resources/raises.d.ts.map +1 -1
  34. package/dist/api/resources/roles.d.ts +3 -3
  35. package/dist/api/resources/roles.d.ts.map +1 -1
  36. package/dist/api/resources/webhooks.d.ts +2 -2
  37. package/dist/api/resources/webhooks.d.ts.map +1 -1
  38. package/dist/app/KelpieApp.d.ts.map +1 -1
  39. package/dist/app/KelpieApp.js +16 -1
  40. package/dist/app/KelpieApp.js.map +1 -1
  41. package/dist/components/DataTable.d.ts +10 -10
  42. package/dist/components/DataTable.d.ts.map +1 -1
  43. package/dist/components/EntitySearch.d.ts +10 -10
  44. package/dist/components/EntitySearch.d.ts.map +1 -1
  45. package/dist/components/KanbanBoard.d.ts +2 -2
  46. package/dist/components/KanbanBoard.d.ts.map +1 -1
  47. package/dist/components/Shell.d.ts.map +1 -1
  48. package/dist/components/Shell.js +3 -16
  49. package/dist/components/Shell.js.map +1 -1
  50. package/dist/index.d.ts +3 -3
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +2 -2
  53. package/dist/index.js.map +1 -1
  54. package/dist/pages/account/AccountLayout.d.ts.map +1 -1
  55. package/dist/pages/account/AccountLayout.js +15 -7
  56. package/dist/pages/account/AccountLayout.js.map +1 -1
  57. package/dist/registry/context.d.ts +1 -2
  58. package/dist/registry/context.d.ts.map +1 -1
  59. package/dist/registry/context.js +0 -3
  60. package/dist/registry/context.js.map +1 -1
  61. package/dist/registry/contributions.d.ts +1 -12
  62. package/dist/registry/contributions.d.ts.map +1 -1
  63. package/dist/registry/contributions.js +0 -7
  64. package/dist/registry/contributions.js.map +1 -1
  65. package/dist/registry/registry.d.ts +1 -3
  66. package/dist/registry/registry.d.ts.map +1 -1
  67. package/dist/registry/registry.js +0 -6
  68. package/dist/registry/registry.js.map +1 -1
  69. package/dist/registry/visibleNav.d.ts +3 -0
  70. package/dist/registry/visibleNav.d.ts.map +1 -0
  71. package/dist/registry/visibleNav.js +27 -0
  72. package/dist/registry/visibleNav.js.map +1 -0
  73. package/package.json +2 -2
  74. package/src/api/ApiProvider.tsx +3 -3
  75. package/src/api/client.ts +4 -1
  76. package/src/api/resources/agentTasks.ts +2 -2
  77. package/src/api/resources/candidates.ts +4 -4
  78. package/src/api/resources/companies.ts +4 -4
  79. package/src/api/resources/deals.ts +6 -6
  80. package/src/api/resources/decisions.ts +3 -3
  81. package/src/api/resources/forms.ts +3 -3
  82. package/src/api/resources/handbookPages.ts +3 -3
  83. package/src/api/resources/notes.ts +2 -2
  84. package/src/api/resources/opportunities.ts +6 -6
  85. package/src/api/resources/partnerships.ts +7 -7
  86. package/src/api/resources/people.ts +4 -4
  87. package/src/api/resources/planItems.ts +6 -6
  88. package/src/api/resources/positions.ts +3 -3
  89. package/src/api/resources/raises.ts +6 -6
  90. package/src/api/resources/roles.ts +3 -3
  91. package/src/api/resources/webhooks.ts +2 -2
  92. package/src/app/KelpieApp.tsx +26 -1
  93. package/src/components/DataTable.tsx +12 -12
  94. package/src/components/EntitySearch.tsx +10 -10
  95. package/src/components/KanbanBoard.tsx +2 -2
  96. package/src/components/Shell.tsx +3 -22
  97. package/src/index.ts +1 -4
  98. package/src/pages/account/AccountLayout.tsx +20 -9
  99. package/src/registry/context.ts +0 -5
  100. package/src/registry/contributions.ts +1 -20
  101. package/src/registry/registry.ts +0 -11
  102. package/src/registry/visibleNav.ts +38 -0
@@ -1,17 +1,26 @@
1
1
  import { NavLink, Outlet } from 'react-router'
2
2
 
3
+ import type { NavItem } from '../../registry/contributions.ts'
4
+ import { useNavItems } from '../../registry/context.ts'
5
+ import { useVisibleNavItems } from '../../registry/visibleNav.ts'
6
+
3
7
  /**
4
8
  * Tabs across the account's own settings, from the mockup's `AccountNav`.
5
9
  *
6
- * Three of its five tabs are here. Personal API keys and integrations arrive
7
- * with the features behind them, the same rule the shell's sidebar follows.
10
+ * Three of its five tabs are core's. The rest come from `nav.account`, which is
11
+ * where a module's own account page announces itself: a module route mounts as
12
+ * a sibling of `/account` rather than a child of it, so without this the page
13
+ * would render with no tab strip and nothing anywhere pointing at it.
14
+ *
15
+ * Core numbers itself in hundreds, the same convention the shell's sidebar
16
+ * uses, so a module can land between two core tabs without core renumbering.
8
17
  */
9
18
 
10
- const TABS = [
11
- { to: '/account/profile', label: 'Profile' },
12
- { to: '/account/security', label: 'Security' },
13
- { to: '/account/preferences', label: 'Preferences' },
14
- ] as const
19
+ const CORE_TABS: readonly NavItem[] = [
20
+ { id: 'profile', to: '/account/profile', label: 'Profile', order: 100 },
21
+ { id: 'security', to: '/account/security', label: 'Security', order: 200 },
22
+ { id: 'preferences', to: '/account/preferences', label: 'Preferences', order: 300 },
23
+ ]
15
24
 
16
25
  function tabClass({ isActive }: { isActive: boolean }): string {
17
26
  return [
@@ -23,11 +32,13 @@ function tabClass({ isActive }: { isActive: boolean }): string {
23
32
  }
24
33
 
25
34
  export function AccountLayout(): React.JSX.Element {
35
+ const tabs = useVisibleNavItems(CORE_TABS, useNavItems('account'))
36
+
26
37
  return (
27
38
  <div className="animate-fade-in mx-auto max-w-4xl">
28
39
  <nav className="mb-6 flex flex-wrap gap-1 border-b border-border pb-3">
29
- {TABS.map((tab) => (
30
- <NavLink key={tab.to} to={tab.to} className={tabClass}>
40
+ {tabs.map((tab) => (
41
+ <NavLink key={tab.id} to={tab.to} className={tabClass}>
31
42
  {tab.label}
32
43
  </NavLink>
33
44
  ))}
@@ -4,7 +4,6 @@ import type { ComponentType } from 'react'
4
4
  import type {
5
5
  DashboardCard,
6
6
  ExtensibleRecordType,
7
- IntegrationProvider,
8
7
  NavItem,
9
8
  NavSlot,
10
9
  RecordSidebarCard,
@@ -54,10 +53,6 @@ export function useDashboardCards(): readonly DashboardCard[] {
54
53
  return useUiExtensions().dashboardCards()
55
54
  }
56
55
 
57
- export function useIntegrationProviders(): readonly IntegrationProvider[] {
58
- return useUiExtensions().integrationProviders()
59
- }
60
-
61
56
  /**
62
57
  * The component to render for an overridable: a module's replacement, or core's
63
58
  * own. Core calls this instead of rendering its component directly.
@@ -1,5 +1,5 @@
1
1
  import type { ExtensibleRecordType } from '@kelpie/schemas'
2
- import type { ComponentType, ReactNode } from 'react'
2
+ import type { ReactNode } from 'react'
3
3
 
4
4
  /**
5
5
  * What a UI module may add to the shell, per the slot table in `modules.md`.
@@ -68,22 +68,3 @@ export interface DashboardCard {
68
68
  readonly render: () => ReactNode
69
69
  }
70
70
 
71
- export const INTEGRATION_CATEGORIES = [
72
- 'messaging',
73
- 'identity',
74
- 'enrichment',
75
- 'email',
76
- 'calendar',
77
- ] as const
78
-
79
- export type IntegrationCategory = (typeof INTEGRATION_CATEGORIES)[number]
80
-
81
- /** A catalog entry on the admin integrations page. Core owns the page and the connection lifecycle. */
82
- export interface IntegrationProvider {
83
- readonly id: string
84
- readonly name: string
85
- readonly category: IntegrationCategory
86
- readonly description: string
87
- /** Rendered on the provider's own settings panel once connected. */
88
- readonly settings?: ComponentType<Record<string, never>>
89
- }
@@ -3,7 +3,6 @@ import type { ComponentType } from 'react'
3
3
  import type {
4
4
  DashboardCard,
5
5
  ExtensibleRecordType,
6
- IntegrationProvider,
7
6
  NavItem,
8
7
  NavSlot,
9
8
  RecordSidebarCard,
@@ -32,7 +31,6 @@ export interface UiModuleContext {
32
31
  recordTab(objectType: ExtensibleRecordType, tab: RecordTab): void
33
32
  recordSidebarCard(objectType: ExtensibleRecordType, card: RecordSidebarCard): void
34
33
  dashboardCard(card: DashboardCard): void
35
- integrationProvider(provider: IntegrationProvider): void
36
34
  /** Replaces a core component. Prefer a slot; see `modules.md`. */
37
35
  override<Props>(token: Overridable<Props>, component: ComponentType<Props>): void
38
36
  }
@@ -49,7 +47,6 @@ export interface UiExtensions {
49
47
  recordTabs(objectType: ExtensibleRecordType): readonly RecordTab[]
50
48
  recordSidebarCards(objectType: ExtensibleRecordType): readonly RecordSidebarCard[]
51
49
  dashboardCards(): readonly DashboardCard[]
52
- integrationProviders(): readonly IntegrationProvider[]
53
50
  componentFor<Props>(token: Overridable<Props>): ComponentType<Props>
54
51
  }
55
52
 
@@ -73,7 +70,6 @@ interface Accumulator {
73
70
  readonly recordTabs: Map<ExtensibleRecordType, RecordTab[]>
74
71
  readonly recordSidebarCards: Map<ExtensibleRecordType, RecordSidebarCard[]>
75
72
  readonly dashboardCards: DashboardCard[]
76
- readonly integrationProviders: IntegrationProvider[]
77
73
  readonly overrides: OverrideStore
78
74
  }
79
75
 
@@ -138,11 +134,6 @@ function createModuleContext(
138
134
  accumulator.dashboardCards.push(card)
139
135
  },
140
136
 
141
- integrationProvider(provider) {
142
- claim(taken, module.id, 'admin.integrations.catalog', provider.id)
143
- accumulator.integrationProviders.push(provider)
144
- },
145
-
146
137
  override(token, component) {
147
138
  if (accumulator.overrides.has(token.key)) {
148
139
  throw new UiModuleError(
@@ -167,7 +158,6 @@ export function registerUiModules(modules: readonly UiModule[]): UiExtensions {
167
158
  recordTabs: new Map(),
168
159
  recordSidebarCards: new Map(),
169
160
  dashboardCards: [],
170
- integrationProviders: [],
171
161
  overrides: createOverrideStore(),
172
162
  }
173
163
  const taken = new Set<string>()
@@ -189,7 +179,6 @@ export function registerUiModules(modules: readonly UiModule[]): UiExtensions {
189
179
  recordSidebarCards: (objectType) =>
190
180
  inSlotOrder(accumulator.recordSidebarCards.get(objectType) ?? []),
191
181
  dashboardCards: () => inSlotOrder(accumulator.dashboardCards),
192
- integrationProviders: () => accumulator.integrationProviders,
193
182
  componentFor: (token) => accumulator.overrides.get(token),
194
183
  }
195
184
  }
@@ -0,0 +1,38 @@
1
+ import { useModuleSettings } from '../api/resources/moduleSettings.ts'
2
+ import type { NavItem } from './contributions.ts'
3
+ import { inSlotOrder } from './registry.ts'
4
+
5
+ /**
6
+ * Core's nav items merged with a slot's module contributions, ordered, with the
7
+ * entries belonging to a disabled module removed.
8
+ *
9
+ * One hook rather than the rule written out at each nav surface. The shell's
10
+ * sidebar and the account tab strip both render a slot, and a workspace that
11
+ * switched a module off should stop seeing it in both. Two copies of this
12
+ * filter is exactly the sort of pair that drifts, and the symptom is a tab that
13
+ * survives its module being disabled and leads to a page answering 403.
14
+ */
15
+
16
+ /**
17
+ * A nav item whose id does not match its module id. Everything else looks itself
18
+ * up directly, which is what keeps a toggleable module's own nav entry working
19
+ * with no change here when one is added later.
20
+ */
21
+ const NAV_ID_TO_MODULE_ID: Readonly<Record<string, string>> = {
22
+ fundraising: 'raises',
23
+ data: 'import-export',
24
+ }
25
+
26
+ export function useVisibleNavItems(
27
+ coreItems: readonly NavItem[],
28
+ moduleItems: readonly NavItem[],
29
+ ): readonly NavItem[] {
30
+ const { settings } = useModuleSettings()
31
+ const disabledModuleIds = new Set(
32
+ settings.filter((setting) => !setting.enabled).map((setting) => setting.moduleId),
33
+ )
34
+
35
+ return inSlotOrder([...coreItems, ...moduleItems]).filter(
36
+ (item) => !disabledModuleIds.has(NAV_ID_TO_MODULE_ID[item.id] ?? item.id),
37
+ )
38
+ }