@flamingo-stack/openframe-frontend-core 0.0.312 → 0.0.313-snapshot.20260623203621

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 (118) hide show
  1. package/dist/{chunk-7KKIACLD.cjs → chunk-2LFQJYLQ.cjs} +7 -7
  2. package/dist/{chunk-7KKIACLD.cjs.map → chunk-2LFQJYLQ.cjs.map} +1 -1
  3. package/dist/{chunk-UFJVTOGS.cjs → chunk-46UZAYUT.cjs} +29 -29
  4. package/dist/{chunk-UFJVTOGS.cjs.map → chunk-46UZAYUT.cjs.map} +1 -1
  5. package/dist/{chunk-G56GYN7Z.cjs → chunk-5ATH263N.cjs} +4 -1
  6. package/dist/chunk-5ATH263N.cjs.map +1 -0
  7. package/dist/{chunk-52MEECZB.cjs → chunk-AD7TII2A.cjs} +5 -5
  8. package/dist/{chunk-52MEECZB.cjs.map → chunk-AD7TII2A.cjs.map} +1 -1
  9. package/dist/{chunk-AHVG5CFA.cjs → chunk-BHOGI57O.cjs} +38 -38
  10. package/dist/{chunk-AHVG5CFA.cjs.map → chunk-BHOGI57O.cjs.map} +1 -1
  11. package/dist/{chunk-CGR2DPPQ.js → chunk-BJ6JXN5Z.js} +5 -5
  12. package/dist/{chunk-7G7QJNLY.cjs → chunk-DD35H7HA.cjs} +40 -40
  13. package/dist/{chunk-7G7QJNLY.cjs.map → chunk-DD35H7HA.cjs.map} +1 -1
  14. package/dist/{chunk-F45P357Q.js → chunk-E2LC43T3.js} +2 -2
  15. package/dist/{chunk-JQ2EYXWR.js → chunk-E4CQ4RUG.js} +4 -1
  16. package/dist/chunk-E4CQ4RUG.js.map +1 -0
  17. package/dist/{chunk-NQDC366J.cjs → chunk-EC4DGRN6.cjs} +88 -63
  18. package/dist/chunk-EC4DGRN6.cjs.map +1 -0
  19. package/dist/{chunk-GRBFBBSX.js → chunk-JWX6NIQ4.js} +2 -2
  20. package/dist/{chunk-PH2RLC4E.js → chunk-L7BROXZ7.js} +2 -2
  21. package/dist/{chunk-MI6TET5N.js → chunk-NH2RY6VM.js} +38 -13
  22. package/dist/{chunk-MI6TET5N.js.map → chunk-NH2RY6VM.js.map} +1 -1
  23. package/dist/{chunk-GZPOUZAY.js → chunk-OD3BEWDQ.js} +3 -3
  24. package/dist/{chunk-JQLC2FVM.js → chunk-TRSDXD23.js} +2 -2
  25. package/dist/{chunk-64JGK22Q.cjs → chunk-UNKIRZVY.cjs} +19 -19
  26. package/dist/{chunk-64JGK22Q.cjs.map → chunk-UNKIRZVY.cjs.map} +1 -1
  27. package/dist/{chunk-DJBMLHN7.js → chunk-UO27TVAO.js} +3 -3
  28. package/dist/{chunk-SPFV5TFS.cjs → chunk-VCJOLKED.cjs} +12 -12
  29. package/dist/{chunk-SPFV5TFS.cjs.map → chunk-VCJOLKED.cjs.map} +1 -1
  30. package/dist/{chunk-6GKJXZZM.cjs → chunk-WJCOWYAP.cjs} +14 -14
  31. package/dist/{chunk-6GKJXZZM.cjs.map → chunk-WJCOWYAP.cjs.map} +1 -1
  32. package/dist/{chunk-BX4MDVBL.js → chunk-XKVSR3IV.js} +4 -4
  33. package/dist/{chunk-2ZHDP22R.cjs → chunk-ZPK5HW7B.cjs} +3 -3
  34. package/dist/{chunk-2ZHDP22R.cjs.map → chunk-ZPK5HW7B.cjs.map} +1 -1
  35. package/dist/{chunk-IHCOTCIG.js → chunk-ZW3NHMG7.js} +3 -3
  36. package/dist/components/case-studies/index.cjs +9 -9
  37. package/dist/components/case-studies/index.js +3 -3
  38. package/dist/components/chat/index.cjs +3 -3
  39. package/dist/components/chat/index.js +2 -2
  40. package/dist/components/contact/index.cjs +4 -4
  41. package/dist/components/contact/index.js +3 -3
  42. package/dist/components/docs/index.cjs +6 -6
  43. package/dist/components/docs/index.js +5 -5
  44. package/dist/components/embeds/index.cjs +4 -4
  45. package/dist/components/embeds/index.js +3 -3
  46. package/dist/components/faq/index.cjs +5 -5
  47. package/dist/components/faq/index.js +4 -4
  48. package/dist/components/features/index.cjs +3 -3
  49. package/dist/components/features/index.js +2 -2
  50. package/dist/components/features/time-tracker/time-tracker-panel.d.ts +1 -1
  51. package/dist/components/features/time-tracker/time-tracker-panel.d.ts.map +1 -1
  52. package/dist/components/features/time-tracker/types.d.ts +2 -2
  53. package/dist/components/features/time-tracker/types.d.ts.map +1 -1
  54. package/dist/components/index.cjs +190 -188
  55. package/dist/components/index.cjs.map +1 -1
  56. package/dist/components/index.js +12 -10
  57. package/dist/components/index.js.map +1 -1
  58. package/dist/components/layout/page-layout.d.ts +1 -1
  59. package/dist/components/layout/page-layout.d.ts.map +1 -1
  60. package/dist/components/layout/title-block.d.ts +10 -0
  61. package/dist/components/layout/title-block.d.ts.map +1 -1
  62. package/dist/components/navigation/index.cjs +3 -3
  63. package/dist/components/navigation/index.js +2 -2
  64. package/dist/components/onboarding-guides/index.cjs +29 -29
  65. package/dist/components/onboarding-guides/index.js +5 -5
  66. package/dist/components/related-content/index.cjs +5 -5
  67. package/dist/components/related-content/index.js +4 -4
  68. package/dist/components/tickets/help-center-list.d.ts +5 -1
  69. package/dist/components/tickets/help-center-list.d.ts.map +1 -1
  70. package/dist/components/tickets/index.cjs +84 -73
  71. package/dist/components/tickets/index.cjs.map +1 -1
  72. package/dist/components/tickets/index.js +21 -10
  73. package/dist/components/tickets/index.js.map +1 -1
  74. package/dist/components/tool-icon.d.ts.map +1 -1
  75. package/dist/components/ui/dashboard-info-card.d.ts +3 -1
  76. package/dist/components/ui/dashboard-info-card.d.ts.map +1 -1
  77. package/dist/components/ui/index.cjs +5 -3
  78. package/dist/components/ui/index.cjs.map +1 -1
  79. package/dist/components/ui/index.js +4 -2
  80. package/dist/hooks/index.cjs +2 -2
  81. package/dist/hooks/index.js +1 -1
  82. package/dist/index.cjs +5 -3
  83. package/dist/index.cjs.map +1 -1
  84. package/dist/index.js +4 -2
  85. package/dist/types/index.cjs +2 -0
  86. package/dist/types/index.cjs.map +1 -1
  87. package/dist/types/index.js +2 -0
  88. package/dist/types/index.js.map +1 -1
  89. package/dist/types/tool.types.d.ts +1 -0
  90. package/dist/types/tool.types.d.ts.map +1 -1
  91. package/dist/utils/index.cjs +11 -0
  92. package/dist/utils/index.cjs.map +1 -1
  93. package/dist/utils/index.js +11 -0
  94. package/dist/utils/index.js.map +1 -1
  95. package/dist/utils/tool-utils.d.ts.map +1 -1
  96. package/package.json +1 -1
  97. package/src/components/features/time-tracker/time-tracker-panel.tsx +27 -9
  98. package/src/components/features/time-tracker/types.ts +2 -2
  99. package/src/components/layout/page-layout.tsx +1 -1
  100. package/src/components/layout/title-block.tsx +12 -1
  101. package/src/components/tickets/help-center-list.tsx +16 -4
  102. package/src/components/tool-icon.tsx +1 -0
  103. package/src/components/ui/dashboard-info-card.tsx +9 -1
  104. package/src/stories/TimeTracker.stories.tsx +10 -10
  105. package/src/types/tool.types.ts +2 -0
  106. package/src/utils/tool-utils.ts +11 -0
  107. package/dist/chunk-G56GYN7Z.cjs.map +0 -1
  108. package/dist/chunk-JQ2EYXWR.js.map +0 -1
  109. package/dist/chunk-NQDC366J.cjs.map +0 -1
  110. /package/dist/{chunk-CGR2DPPQ.js.map → chunk-BJ6JXN5Z.js.map} +0 -0
  111. /package/dist/{chunk-F45P357Q.js.map → chunk-E2LC43T3.js.map} +0 -0
  112. /package/dist/{chunk-GRBFBBSX.js.map → chunk-JWX6NIQ4.js.map} +0 -0
  113. /package/dist/{chunk-PH2RLC4E.js.map → chunk-L7BROXZ7.js.map} +0 -0
  114. /package/dist/{chunk-GZPOUZAY.js.map → chunk-OD3BEWDQ.js.map} +0 -0
  115. /package/dist/{chunk-JQLC2FVM.js.map → chunk-TRSDXD23.js.map} +0 -0
  116. /package/dist/{chunk-DJBMLHN7.js.map → chunk-UO27TVAO.js.map} +0 -0
  117. /package/dist/{chunk-BX4MDVBL.js.map → chunk-XKVSR3IV.js.map} +0 -0
  118. /package/dist/{chunk-IHCOTCIG.js.map → chunk-ZW3NHMG7.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"tool-utils.d.ts","sourceRoot":"","sources":["../../src/utils/tool-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAc,MAAM,qBAAqB,CAAA;AA2E1D;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAgBtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAEtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAI/D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEvD"}
1
+ {"version":3,"file":"tool-utils.d.ts","sourceRoot":"","sources":["../../src/utils/tool-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAc,MAAM,qBAAqB,CAAA;AAsF1D;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAgBtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAEtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAI/D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEvD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.312",
3
+ "version": "0.0.313-snapshot.20260623203621",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,8 +30,8 @@ export function TimeTrackerPanel({
30
30
  runningSince,
31
31
  accumulatedMs,
32
32
  ticketOptions,
33
- selectedTicketIds,
34
- onSelectedTicketsChange,
33
+ selectedTicketId,
34
+ onSelectedTicketChange,
35
35
  onTicketSearch,
36
36
  ticketsLoading,
37
37
  notes,
@@ -57,7 +57,7 @@ export function TimeTrackerPanel({
57
57
 
58
58
  const isRunning = status === 'tracking'
59
59
  const isActive = status !== 'ready'
60
- const hasContent = selectedTicketIds.length > 0 || notes.trim() !== ''
60
+ const hasContent = selectedTicketId != null || notes.trim() !== ''
61
61
  const showFieldError = isActive && showValidationError && !hasContent
62
62
 
63
63
  // Reset the validation flag once a session ends so the next one starts clean.
@@ -73,6 +73,25 @@ export function TimeTrackerPanel({
73
73
  onSubmit()
74
74
  }
75
75
 
76
+ const handleManualEntry = onManualEntry
77
+ ? () => {
78
+ onClose()
79
+ onManualEntry()
80
+ }
81
+ : undefined
82
+ const handleEntryClick = onEntryClick
83
+ ? (entry: TimeTrackerEntry) => {
84
+ onClose()
85
+ onEntryClick(entry)
86
+ }
87
+ : undefined
88
+ const handleOpenMyTime = onOpenMyTime
89
+ ? () => {
90
+ onClose()
91
+ onOpenMyTime()
92
+ }
93
+ : undefined
94
+
76
95
  const ticketAutocompleteOptions: AutocompleteOption[] = ticketOptions.map((t) => ({
77
96
  label: t.label,
78
97
  value: t.id,
@@ -150,9 +169,8 @@ export function TimeTrackerPanel({
150
169
  </div>
151
170
 
152
171
  <Autocomplete
153
- multiple
154
- value={selectedTicketIds}
155
- onChange={onSelectedTicketsChange}
172
+ value={selectedTicketId}
173
+ onChange={onSelectedTicketChange}
156
174
  options={ticketAutocompleteOptions}
157
175
  placeholder="Assign Ticket"
158
176
  loading={ticketsLoading}
@@ -185,7 +203,7 @@ export function TimeTrackerPanel({
185
203
  </div>
186
204
  ) : (
187
205
  visibleEntries.map((entry) => (
188
- <LastEntryRow key={entry.id} entry={entry} onClick={onEntryClick} />
206
+ <LastEntryRow key={entry.id} entry={entry} onClick={handleEntryClick} />
189
207
  ))
190
208
  )}
191
209
  </div>
@@ -195,7 +213,7 @@ export function TimeTrackerPanel({
195
213
  <Button
196
214
  variant="outline"
197
215
  className="min-w-0 flex-1"
198
- onClick={onManualEntry}
216
+ onClick={handleManualEntry}
199
217
  disabled={!onManualEntry}
200
218
  leftIcon={<PlusCircleIcon className="text-ods-text-secondary" />}
201
219
  >
@@ -203,7 +221,7 @@ export function TimeTrackerPanel({
203
221
  </Button>
204
222
  <SplitButton
205
223
  variant="outline"
206
- onClick={onOpenMyTime}
224
+ onClick={handleOpenMyTime}
207
225
  disabled={!onOpenMyTime && !onOpenMyTimeMenu}
208
226
  mainDisabled={!onOpenMyTime}
209
227
  groupAriaLabel="Open my time"
@@ -32,8 +32,8 @@ export interface TimeTrackerData {
32
32
  accumulatedMs?: number
33
33
 
34
34
  ticketOptions: TimeTrackerTicketOption[]
35
- selectedTicketIds: string[]
36
- onSelectedTicketsChange: (ids: string[]) => void
35
+ selectedTicketId: string | null
36
+ onSelectedTicketChange: (id: string | null) => void
37
37
  /** Called as the user types in the ticket field; host performs the search. */
38
38
  onTicketSearch?: (query: string) => void
39
39
  ticketsLoading?: boolean
@@ -99,6 +99,6 @@ export function PageLayout({
99
99
  }
100
100
 
101
101
  export type { PageActionButton } from '../ui/page-actions'
102
- export { TitleBlock } from './title-block'
102
+ export { TitleBlock, TITLE_BLOCK_MIN_HEIGHT } from './title-block'
103
103
  export type { TitleBlockProps } from './title-block'
104
104
  export default PageLayout
@@ -31,6 +31,17 @@ import { EntityImage } from '../ui/entity-image'
31
31
  import { PageActions, type PageActionButton } from '../ui/page-actions'
32
32
  import { BackButton } from './back-button'
33
33
 
34
+ /**
35
+ * Minimum height of the title block's content column, matched to the action
36
+ * button height: the icon button on mobile (`h-11` → 44px) and the default
37
+ * button on desktop (`md:h-12` → 48px). Applied to the inner title column (which
38
+ * has no padding) rather than the root — the root's `pt`/`mb` are box-sizing
39
+ * border-box and would otherwise absorb the floor. Keeps the header a consistent
40
+ * height across pages whether or not they render action buttons, so the content
41
+ * below starts at the same baseline. Exported so other page chrome can reuse it.
42
+ */
43
+ export const TITLE_BLOCK_MIN_HEIGHT = 'min-h-11 md:min-h-12'
44
+
34
45
  export interface TitleBlockProps {
35
46
  title?: string
36
47
  subtitle?: string
@@ -83,7 +94,7 @@ export function TitleBlock({
83
94
  className,
84
95
  )}
85
96
  >
86
- <div className="flex flex-col gap-[var(--spacing-system-xs)] flex-1 min-w-0">
97
+ <div className={cn('flex flex-col justify-center gap-[var(--spacing-system-xs)] flex-1 min-w-0', TITLE_BLOCK_MIN_HEIGHT)}>
87
98
  {backButton && (
88
99
  <BackButton
89
100
  onClick={backButton.onClick}
@@ -55,9 +55,13 @@ export interface HelpCenterListProps {
55
55
  * to hide). Omit ⇒ `DevSectionPage`'s default (`Back to home` → `/`), which
56
56
  * embedders whose home isn't `/` MUST override. */
57
57
  backButton?: { label?: string; href?: string } | false
58
+ /** Override the hero title (forwarded to `DevSectionPage.title`). Defaults to
59
+ * the `tickets` section copy ("Help Center"). Set this to brand the surface
60
+ * for an embed that wants its own label (e.g. "Support Tickets"). */
61
+ title?: string
58
62
  }
59
63
 
60
- export function HelpCenterList({ toast = defaultToast, backButton }: HelpCenterListProps = {}) {
64
+ export function HelpCenterList({ toast = defaultToast, backButton, title }: HelpCenterListProps = {}) {
61
65
  const identity = useChatIdentity()
62
66
  const searchParams = useSearchParams()
63
67
  const router = useRouter()
@@ -85,14 +89,19 @@ export function HelpCenterList({ toast = defaultToast, backButton }: HelpCenterL
85
89
  // mounts in the `preControls` slot.
86
90
  if (identity.isLoading) {
87
91
  return (
88
- <DevSectionPage sectionKey="tickets" backButton={backButton} preControls={<HelpCenterCreateFormSkeleton />}>
92
+ <DevSectionPage
93
+ sectionKey="tickets"
94
+ backButton={backButton}
95
+ title={title}
96
+ preControls={<HelpCenterCreateFormSkeleton />}
97
+ >
89
98
  <DevCardRowSkeletonList />
90
99
  </DevSectionPage>
91
100
  )
92
101
  }
93
102
  if (identity.authTier === 'anon' || !identity.user?.email) {
94
103
  return (
95
- <DevSectionPage sectionKey="tickets" backButton={backButton}>
104
+ <DevSectionPage sectionKey="tickets" backButton={backButton} title={title}>
96
105
  <EmptyState
97
106
  type="generic"
98
107
  title="Sign in to manage tickets"
@@ -128,6 +137,7 @@ export function HelpCenterList({ toast = defaultToast, backButton }: HelpCenterL
128
137
  sessionName={sessionName}
129
138
  sessionEmail={sessionEmail}
130
139
  backButton={backButton}
140
+ title={title}
131
141
  />
132
142
  )
133
143
  }
@@ -145,6 +155,7 @@ interface AuthedProps {
145
155
  sessionName: string
146
156
  sessionEmail: string
147
157
  backButton?: { label?: string; href?: string } | false
158
+ title?: string
148
159
  }
149
160
 
150
161
  function HelpCenterListAuthed({
@@ -159,6 +170,7 @@ function HelpCenterListAuthed({
159
170
  sessionName,
160
171
  sessionEmail,
161
172
  backButton,
173
+ title,
162
174
  }: AuthedProps) {
163
175
  const queryClient = useQueryClient()
164
176
  const [optimisticTickets, setOptimisticTickets] = useState<OptimisticTicket[]>([])
@@ -386,7 +398,7 @@ function HelpCenterListAuthed({
386
398
  )
387
399
 
388
400
  return (
389
- <DevSectionPage sectionKey="tickets" backButton={backButton} preControls={form}>
401
+ <DevSectionPage sectionKey="tickets" backButton={backButton} title={title} preControls={form}>
390
402
  {body}
391
403
  </DevSectionPage>
392
404
  )
@@ -25,6 +25,7 @@ const toolIconMap: Record<ToolType, (size: number, className?: string) => React.
25
25
  [ToolTypeValues.OPENFRAME]: renderOpenFrameLogo,
26
26
  [ToolTypeValues.OPENFRAME_CHAT]: renderOpenFrameLogo,
27
27
  [ToolTypeValues.OPENFRAME_CLIENT]: renderOpenFrameLogo,
28
+ [ToolTypeValues.OPENFRAME_RMM]: renderOpenFrameLogo,
28
29
  [ToolTypeValues.AUTHENTIK]: (size, className) => <AuthentikLogoGreyIcon size={size} className={className} />,
29
30
  [ToolTypeValues.OSQUERY]: (size, className) => <OsqueryLogoGreyIcon size={size} className={className} />,
30
31
  [ToolTypeValues.SYSTEM]: () => null,
@@ -30,6 +30,8 @@ export interface DashboardInfoCardProps {
30
30
  tooltip?: React.ReactNode
31
31
  /** Override the value text className (default: text-h2) */
32
32
  valueClassName?: string
33
+ /** Secondary text rendered beside the value (e.g. an entry/item count). */
34
+ subValue?: React.ReactNode
33
35
  }
34
36
 
35
37
  export function DashboardInfoCard({
@@ -43,7 +45,8 @@ export function DashboardInfoCard({
43
45
  className,
44
46
  href,
45
47
  tooltip,
46
- valueClassName
48
+ valueClassName,
49
+ subValue
47
50
  }: DashboardInfoCardProps) {
48
51
  const formattedValue = typeof value === 'number'
49
52
  ? value.toLocaleString()
@@ -65,6 +68,11 @@ export function DashboardInfoCard({
65
68
  <p className={cn("text-h2 text-ods-text-primary", valueClassName)}>
66
69
  {formattedValue}
67
70
  </p>
71
+ {subValue && (
72
+ <p className="text-h6 text-ods-text-secondary">
73
+ {subValue}
74
+ </p>
75
+ )}
68
76
  {percentage !== undefined && (
69
77
  progressVariant === 'warning' || progressVariant === 'error' ? (
70
78
  <Tag variant={progressVariant} label={`${percentage}%`} />
@@ -78,8 +78,8 @@ const meta = {
78
78
  args: {
79
79
  status: 'ready',
80
80
  ticketOptions: ALL_TICKETS,
81
- selectedTicketIds: [],
82
- onSelectedTicketsChange: () => {},
81
+ selectedTicketId: null,
82
+ onSelectedTicketChange: () => {},
83
83
  notes: '',
84
84
  onNotesChange: () => {},
85
85
  lastEntries: SEED_ENTRIES,
@@ -99,7 +99,7 @@ interface HostInit {
99
99
  status?: TimeTrackerStatus
100
100
  runningSince?: number | null
101
101
  accumulatedMs?: number
102
- selectedTicketIds?: string[]
102
+ selectedTicketId?: string | null
103
103
  notes?: string
104
104
  lastEntries?: TimeTrackerEntry[]
105
105
  /** When true, ticket options are filtered asynchronously (server-search simulation). */
@@ -110,7 +110,7 @@ function useTimeTrackerHost(initial: HostInit = {}): TimeTrackerData {
110
110
  const [status, setStatus] = React.useState<TimeTrackerStatus>(initial.status ?? 'ready')
111
111
  const [runningSince, setRunningSince] = React.useState<number | null>(initial.runningSince ?? null)
112
112
  const [accumulatedMs, setAccumulatedMs] = React.useState(initial.accumulatedMs ?? 0)
113
- const [selectedTicketIds, setSelectedTicketIds] = React.useState<string[]>(initial.selectedTicketIds ?? [])
113
+ const [selectedTicketId, setSelectedTicketId] = React.useState<string | null>(initial.selectedTicketId ?? null)
114
114
  const [notes, setNotes] = React.useState(initial.notes ?? '')
115
115
  const [lastEntries, setLastEntries] = React.useState<TimeTrackerEntry[]>(initial.lastEntries ?? SEED_ENTRIES)
116
116
 
@@ -138,8 +138,8 @@ function useTimeTrackerHost(initial: HostInit = {}): TimeTrackerData {
138
138
  runningSince,
139
139
  accumulatedMs,
140
140
  ticketOptions,
141
- selectedTicketIds,
142
- onSelectedTicketsChange: setSelectedTicketIds,
141
+ selectedTicketId,
142
+ onSelectedTicketChange: setSelectedTicketId,
143
143
  onTicketSearch,
144
144
  ticketsLoading: initial.serverSearch ? ticketsLoading : undefined,
145
145
  notes,
@@ -163,12 +163,12 @@ function useTimeTrackerHost(initial: HostInit = {}): TimeTrackerData {
163
163
  setStatus('ready')
164
164
  setRunningSince(null)
165
165
  setAccumulatedMs(0)
166
- setSelectedTicketIds([])
166
+ setSelectedTicketId(null)
167
167
  setNotes('')
168
168
  },
169
169
  onSubmit: () => {
170
170
  const ms = currentElapsedMs()
171
- const ticketId = selectedTicketIds[0]
171
+ const ticketId = selectedTicketId
172
172
  const entry: TimeTrackerEntry = {
173
173
  id: `entry-${Date.now()}`,
174
174
  durationLabel: formatDuration(ms),
@@ -182,7 +182,7 @@ function useTimeTrackerHost(initial: HostInit = {}): TimeTrackerData {
182
182
  setStatus('ready')
183
183
  setRunningSince(null)
184
184
  setAccumulatedMs(0)
185
- setSelectedTicketIds([])
185
+ setSelectedTicketId(null)
186
186
  setNotes('')
187
187
  },
188
188
  onManualEntry: () => alert('Host: open the manual-entry form modal'),
@@ -224,7 +224,7 @@ export const PanelTracking: Story = {
224
224
  const host = useTimeTrackerHost({
225
225
  status: 'tracking',
226
226
  runningSince: Date.now() - 5_000,
227
- selectedTicketIds: ['TICK-102'],
227
+ selectedTicketId: 'TICK-102',
228
228
  })
229
229
  return (
230
230
  <div className="max-w-[460px]">
@@ -13,6 +13,7 @@ export const ToolTypeValues = {
13
13
  OPENFRAME: 'OPENFRAME',
14
14
  OPENFRAME_CHAT: 'OPENFRAME_CHAT',
15
15
  OPENFRAME_CLIENT: 'OPENFRAME_CLIENT',
16
+ OPENFRAME_RMM: 'OPENFRAME_RMM',
16
17
  OSQUERY: 'OSQUERY',
17
18
  SYSTEM: 'SYSTEM'
18
19
  } as const
@@ -30,6 +31,7 @@ export const toolLabels: Record<ToolType, string> = {
30
31
  OPENFRAME: 'OpenFrame',
31
32
  OPENFRAME_CHAT: 'OpenFrame Chat',
32
33
  OPENFRAME_CLIENT: 'OpenFrame Client',
34
+ OPENFRAME_RMM: 'OpenFrame RMM',
33
35
  OSQUERY: 'Osquery',
34
36
  SYSTEM: 'System'
35
37
  }
@@ -73,6 +73,17 @@ const toolAliasMap: Record<string, ToolType> = {
73
73
  'openframe-client': 'OPENFRAME_CLIENT',
74
74
  'openframeclient': 'OPENFRAME_CLIENT',
75
75
 
76
+ // OpenFrame RMM
77
+ 'RMM': 'OPENFRAME_RMM',
78
+ 'rmm': 'OPENFRAME_RMM',
79
+ 'OPENFRAME_RMM': 'OPENFRAME_RMM',
80
+ 'OPENFRAME-RMM': 'OPENFRAME_RMM',
81
+ 'OPENFRAMERMM': 'OPENFRAME_RMM',
82
+ 'openframe_rmm': 'OPENFRAME_RMM',
83
+ 'openframe-rmm': 'OPENFRAME_RMM',
84
+ 'openframermm': 'OPENFRAME_RMM',
85
+ 'openframe-rmm-agent': 'OPENFRAME_RMM',
86
+
76
87
  // OSQUERY
77
88
  'OSQUERY': 'OSQUERY',
78
89