@flamingo-stack/openframe-frontend-core 0.0.207 → 0.0.208
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/{chunk-Z3GQGR5E.js → chunk-2HMZSCJY.js} +3158 -2074
- package/dist/chunk-2HMZSCJY.js.map +1 -0
- package/dist/chunk-4XLJWX2N.js +12 -0
- package/dist/chunk-4XLJWX2N.js.map +1 -0
- package/dist/{chunk-APM6KBPU.cjs → chunk-C5EC5AZM.cjs} +1644 -560
- package/dist/chunk-C5EC5AZM.cjs.map +1 -0
- package/dist/chunk-VFKQMAUF.cjs +12 -0
- package/dist/chunk-VFKQMAUF.cjs.map +1 -0
- package/dist/components/chat/embeddable-chat.d.ts +35 -2
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/index.d.ts +3 -0
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-embedded-chat.d.ts +10 -169
- package/dist/components/chat/hooks/use-embedded-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +85 -0
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +124 -0
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -0
- package/dist/components/chat/hooks/use-unified-chat.d.ts +33 -0
- package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -0
- package/dist/components/chat/index.cjs +8 -2
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +11 -5
- package/dist/components/chat/types/index.d.ts +1 -0
- package/dist/components/chat/types/index.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +185 -0
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -0
- package/dist/components/features/index.cjs +3 -2
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.js +2 -1
- package/dist/components/index.cjs +26 -2
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +27 -3
- package/dist/components/navigation/index.cjs +3 -2
- package/dist/components/navigation/index.cjs.map +1 -1
- package/dist/components/navigation/index.js +2 -1
- package/dist/components/shared/delivery/delivery-lists.d.ts +16 -0
- package/dist/components/shared/delivery/delivery-lists.d.ts.map +1 -0
- package/dist/components/shared/delivery/delivery-table.d.ts +12 -0
- package/dist/components/shared/delivery/delivery-table.d.ts.map +1 -0
- package/dist/components/shared/delivery/index.d.ts +3 -0
- package/dist/components/shared/delivery/index.d.ts.map +1 -0
- package/dist/components/shared/dev-section/dev-section-page.d.ts +31 -0
- package/dist/components/shared/dev-section/dev-section-page.d.ts.map +1 -0
- package/dist/components/shared/dev-section/dev-section-view.d.ts +34 -0
- package/dist/components/shared/dev-section/dev-section-view.d.ts.map +1 -0
- package/dist/components/shared/dev-section/index.d.ts +3 -0
- package/dist/components/shared/dev-section/index.d.ts.map +1 -0
- package/dist/components/shared/legal-document/index.d.ts +10 -0
- package/dist/components/shared/legal-document/index.d.ts.map +1 -0
- package/dist/components/shared/legal-document/legal-document-page.d.ts +66 -0
- package/dist/components/shared/legal-document/legal-document-page.d.ts.map +1 -0
- package/dist/components/shared/legal-document/use-legal-docs.d.ts +40 -0
- package/dist/components/shared/legal-document/use-legal-docs.d.ts.map +1 -0
- package/dist/components/shared/product-release/index.d.ts +2 -1
- package/dist/components/shared/product-release/index.d.ts.map +1 -1
- package/dist/components/shared/product-release/release-detail-page.d.ts +11 -7
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/shared/roadmap/index.d.ts +18 -0
- package/dist/components/shared/roadmap/index.d.ts.map +1 -0
- package/dist/components/shared/roadmap/roadmap-grid-skeleton.d.ts +24 -0
- package/dist/components/shared/roadmap/roadmap-grid-skeleton.d.ts.map +1 -0
- package/dist/components/shared/roadmap/roadmap-grid.d.ts +18 -0
- package/dist/components/shared/roadmap/roadmap-grid.d.ts.map +1 -0
- package/dist/components/shared/roadmap/use-roadmap-voting.d.ts +25 -0
- package/dist/components/shared/roadmap/use-roadmap-voting.d.ts.map +1 -0
- package/dist/components/ui/index.cjs +8 -2
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +11 -5
- package/dist/components/ui/release-changelog-section.d.ts +13 -2
- package/dist/components/ui/release-changelog-section.d.ts.map +1 -1
- package/dist/embed-shims/index.cjs +1 -6
- package/dist/embed-shims/index.cjs.map +1 -1
- package/dist/embed-shims/index.js +1 -6
- package/dist/embed-shims/index.js.map +1 -1
- package/dist/index.cjs +18 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +19 -3
- package/dist/types/delivery.d.ts +49 -0
- package/dist/types/delivery.d.ts.map +1 -0
- package/dist/types/index.cjs +13 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +12 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/dev-sections/index.d.ts +11 -0
- package/dist/utils/dev-sections/index.d.ts.map +1 -0
- package/dist/utils/dev-sections/openframe-dev-sections.d.ts +209 -0
- package/dist/utils/dev-sections/openframe-dev-sections.d.ts.map +1 -0
- package/dist/utils/index.cjs +82 -0
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +81 -2
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/embeddable-chat.tsx +123 -8
- package/src/components/chat/hooks/index.ts +9 -2
- package/src/components/chat/hooks/use-embedded-chat.ts +18 -1016
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +372 -0
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +1058 -0
- package/src/components/chat/hooks/use-unified-chat.ts +171 -0
- package/src/components/chat/types/index.ts +1 -0
- package/src/components/chat/types/unified-chat-state.types.ts +215 -0
- package/src/components/index.ts +8 -0
- package/src/components/shared/delivery/delivery-lists.tsx +199 -0
- package/src/components/shared/delivery/delivery-table.tsx +174 -0
- package/src/components/shared/delivery/index.ts +9 -0
- package/src/components/shared/dev-section/dev-section-page.tsx +72 -0
- package/src/components/shared/dev-section/dev-section-view.tsx +129 -0
- package/src/components/shared/dev-section/index.ts +2 -0
- package/src/components/shared/legal-document/index.ts +19 -0
- package/src/components/shared/legal-document/legal-document-page.tsx +178 -0
- package/src/components/shared/legal-document/use-legal-docs.ts +123 -0
- package/src/components/shared/product-release/index.ts +14 -3
- package/src/components/shared/product-release/release-detail-page.tsx +45 -7
- package/src/components/shared/roadmap/index.ts +23 -0
- package/src/components/shared/roadmap/roadmap-grid-skeleton.tsx +74 -0
- package/src/components/shared/roadmap/roadmap-grid.tsx +106 -0
- package/src/components/shared/roadmap/use-roadmap-voting.ts +163 -0
- package/src/components/ui/release-changelog-section.tsx +113 -32
- package/src/stories/EmbeddableChat.stories.tsx +186 -0
- package/src/types/delivery.ts +54 -0
- package/src/types/index.ts +1 -0
- package/src/utils/dev-sections/index.ts +17 -0
- package/src/utils/dev-sections/openframe-dev-sections.ts +148 -0
- package/src/utils/index.ts +6 -1
- package/dist/chunk-APM6KBPU.cjs.map +0 -1
- package/dist/chunk-Z3GQGR5E.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import React, { useState } from 'react';
|
|
3
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { Badge } from './badge';
|
|
5
5
|
import { ChevronDown } from 'lucide-react';
|
|
6
6
|
import type { ChangelogEntry } from '../../types/product-release';
|
|
@@ -10,10 +10,21 @@ interface ReleaseChangelogSectionProps {
|
|
|
10
10
|
entries: ChangelogEntry[];
|
|
11
11
|
isBreaking?: boolean;
|
|
12
12
|
hideTitle?: boolean;
|
|
13
|
-
/** When true, section starts collapsed and can be toggled open/closed
|
|
13
|
+
/** When true, section starts collapsed and can be toggled open/closed
|
|
14
|
+
* via a button on the title row. Mutually exclusive with `previewFirst`. */
|
|
14
15
|
collapsible?: boolean;
|
|
15
16
|
/** Initial collapsed state (only used when collapsible=true). Defaults to true (collapsed). */
|
|
16
17
|
defaultCollapsed?: boolean;
|
|
18
|
+
/** When true, render the first entry in full and fade-mask the rest
|
|
19
|
+
* with a "Show N more / Show less" toggle below the list. Hides the
|
|
20
|
+
* fade + toggle when there's only one entry. Mutually exclusive with
|
|
21
|
+
* `collapsible` — when both are passed, `collapsible` wins.
|
|
22
|
+
*
|
|
23
|
+
* This is the same progressive-disclosure pattern used on the
|
|
24
|
+
* investor-update detail page's Key Highlights / Financial Notes
|
|
25
|
+
* sections (formerly a duplicated `FadedHighlightSection` component
|
|
26
|
+
* in the hub — unified here). */
|
|
27
|
+
previewFirst?: boolean;
|
|
17
28
|
/** Optional lucide icon rendered inline before the title text. Matches the
|
|
18
29
|
* catalog card's changelog-strip icons (Sparkles for Features, Wrench for
|
|
19
30
|
* Fixes, TrendingUp for Improvements, AlertTriangle for Breaking) — same
|
|
@@ -23,6 +34,10 @@ interface ReleaseChangelogSectionProps {
|
|
|
23
34
|
SimpleMarkdownRenderer: React.ComponentType<{ content: string }>;
|
|
24
35
|
}
|
|
25
36
|
|
|
37
|
+
// Collapsed height for the preview-first mode. ~120px shows the first
|
|
38
|
+
// entry's title + the start of its description before the mask kicks in.
|
|
39
|
+
const PREVIEW_COLLAPSED_HEIGHT = 120;
|
|
40
|
+
|
|
26
41
|
export function ReleaseChangelogSection({
|
|
27
42
|
title,
|
|
28
43
|
entries,
|
|
@@ -30,13 +45,29 @@ export function ReleaseChangelogSection({
|
|
|
30
45
|
hideTitle = false,
|
|
31
46
|
collapsible = false,
|
|
32
47
|
defaultCollapsed = true,
|
|
48
|
+
previewFirst = false,
|
|
33
49
|
icon,
|
|
34
50
|
SimpleMarkdownRenderer
|
|
35
51
|
}: ReleaseChangelogSectionProps) {
|
|
36
52
|
const [collapsed, setCollapsed] = useState(collapsible ? defaultCollapsed : false);
|
|
53
|
+
const [previewExpanded, setPreviewExpanded] = useState(false);
|
|
54
|
+
const previewContentRef = useRef<HTMLDivElement>(null);
|
|
55
|
+
|
|
56
|
+
// Reset preview-expanded state when the entries set changes — otherwise
|
|
57
|
+
// a parent that refetches and shrinks entries from N → 1 would leave
|
|
58
|
+
// the user with a stale "expanded" state and a momentarily-wrong
|
|
59
|
+
// "Show 0 more" button before the `previewNeedsFade` gate hides it.
|
|
60
|
+
// Keyed on `entries.length` (not identity) so re-renders with the same
|
|
61
|
+
// length don't churn state unnecessarily.
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
setPreviewExpanded(false);
|
|
64
|
+
}, [entries.length]);
|
|
37
65
|
|
|
38
66
|
if (!entries || entries.length === 0) return null;
|
|
39
67
|
|
|
68
|
+
// collapsible wins when both flags are passed (documented in JSDoc).
|
|
69
|
+
const inPreviewMode = previewFirst && !collapsible;
|
|
70
|
+
const previewNeedsFade = inPreviewMode && entries.length > 1;
|
|
40
71
|
const showEntries = !collapsible || !collapsed;
|
|
41
72
|
|
|
42
73
|
return (
|
|
@@ -68,37 +99,87 @@ export function ReleaseChangelogSection({
|
|
|
68
99
|
)
|
|
69
100
|
)}
|
|
70
101
|
{showEntries && (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
inPreviewMode ? (
|
|
103
|
+
/* Preview-first mode: render the list in a height-clamped +
|
|
104
|
+
mask-faded wrapper. The CSS mask creates the soft fade-out
|
|
105
|
+
at the bottom of the collapsed region; the inline maxHeight
|
|
106
|
+
+ transition animate the open/close. When `previewExpanded`
|
|
107
|
+
flips, the wrapper falls back to its natural scrollHeight
|
|
108
|
+
(or 2000px on first render before the ref measures). */
|
|
109
|
+
<div className="relative">
|
|
110
|
+
<div
|
|
111
|
+
ref={previewContentRef}
|
|
112
|
+
className="overflow-hidden transition-[max-height] duration-500"
|
|
113
|
+
style={{
|
|
114
|
+
transitionTimingFunction: 'cubic-bezier(0.33, 1, 0.68, 1)',
|
|
115
|
+
maxHeight: previewExpanded || !previewNeedsFade
|
|
116
|
+
? previewContentRef.current?.scrollHeight ?? 2000
|
|
117
|
+
: PREVIEW_COLLAPSED_HEIGHT,
|
|
118
|
+
...(previewNeedsFade && !previewExpanded ? {
|
|
119
|
+
maskImage: 'linear-gradient(to bottom, black 30%, transparent 100%)',
|
|
120
|
+
WebkitMaskImage: 'linear-gradient(to bottom, black 30%, transparent 100%)',
|
|
121
|
+
} : {}),
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
<ChangelogEntryList entries={entries} SimpleMarkdownRenderer={SimpleMarkdownRenderer} />
|
|
125
|
+
</div>
|
|
126
|
+
{previewNeedsFade && (
|
|
127
|
+
<button
|
|
128
|
+
type="button"
|
|
129
|
+
onClick={() => setPreviewExpanded(!previewExpanded)}
|
|
130
|
+
className="mt-4 flex items-center gap-1.5 text-sm text-ods-text-secondary hover:text-ods-accent transition-colors duration-200"
|
|
131
|
+
>
|
|
132
|
+
<span>{previewExpanded ? 'Show less' : `Show ${entries.length - 1} more`}</span>
|
|
133
|
+
<ChevronDown
|
|
134
|
+
className={`w-3.5 h-3.5 transition-transform duration-300 ${previewExpanded ? 'rotate-180' : ''}`}
|
|
135
|
+
/>
|
|
136
|
+
</button>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
) : (
|
|
140
|
+
<ChangelogEntryList entries={entries} SimpleMarkdownRenderer={SimpleMarkdownRenderer} />
|
|
141
|
+
)
|
|
101
142
|
)}
|
|
102
143
|
</div>
|
|
103
144
|
);
|
|
104
145
|
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Internal list renderer — shared by the default and preview-first
|
|
149
|
+
* branches. Each entry is a bordered-left list item with bold title
|
|
150
|
+
* + markdown-rendered description body.
|
|
151
|
+
*/
|
|
152
|
+
function ChangelogEntryList({
|
|
153
|
+
entries,
|
|
154
|
+
SimpleMarkdownRenderer,
|
|
155
|
+
}: {
|
|
156
|
+
entries: ChangelogEntry[];
|
|
157
|
+
SimpleMarkdownRenderer: React.ComponentType<{ content: string }>;
|
|
158
|
+
}) {
|
|
159
|
+
return (
|
|
160
|
+
<ul className="space-y-6">
|
|
161
|
+
{entries.map((entry, index) => (
|
|
162
|
+
<li key={index} className="border-l-2 border-ods-border pl-4 ml-0">
|
|
163
|
+
{/* Entry title — `text-h3` is body family + BOLD weight (per
|
|
164
|
+
ODS tokens: `--font-h3-weight: var(--font-weight-bold)`)
|
|
165
|
+
at 14/18px responsive. Same body size as the description
|
|
166
|
+
below, distinguished by weight — clean visual hierarchy
|
|
167
|
+
without inflating the body scale. */}
|
|
168
|
+
<p className="text-h3 text-ods-text-primary mb-2">{entry.title}</p>
|
|
169
|
+
{entry.description && (
|
|
170
|
+
/* Entry description — body text matches the main release
|
|
171
|
+
summary at the SAME 14/18px responsive `text-h4` scale.
|
|
172
|
+
The `SimpleMarkdownRenderer` forces its own `<p>` typography
|
|
173
|
+
which would override `text-h4` on `lg+` viewports and
|
|
174
|
+
inflate the changelog body to 20px. The `[&_p]:!` overrides
|
|
175
|
+
pin every descendant `<p>` back to the h4 responsive tokens
|
|
176
|
+
so the breakpoints stay aligned with the rest of the page. */
|
|
177
|
+
<div className="text-h4 text-ods-text-primary [&_p]:!text-[length:var(--font-size-h4-body)] [&_p]:!leading-[var(--font-line-space-h4-body)] [&_p]:!font-medium">
|
|
178
|
+
<SimpleMarkdownRenderer content={entry.description} />
|
|
179
|
+
</div>
|
|
180
|
+
)}
|
|
181
|
+
</li>
|
|
182
|
+
))}
|
|
183
|
+
</ul>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
|
2
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
3
|
+
import React, { useMemo } from 'react'
|
|
4
|
+
import {
|
|
5
|
+
ChatRuntimeContext,
|
|
6
|
+
type ChatRuntime,
|
|
7
|
+
} from '../contexts/chat-runtime-context'
|
|
8
|
+
import { EmbeddableChat } from '../components/chat/embeddable-chat'
|
|
9
|
+
import type { UseNatsChatAdapterConfig } from '../components/chat/hooks/use-nats-chat-adapter'
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Shared mocks
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal mock runtime — endpoints point at non-existent paths so that
|
|
17
|
+
* an accidental fetch in the active mode resolves to a 404 rather than
|
|
18
|
+
* hitting a real server. Inactive-mode hooks never call out. Memoised
|
|
19
|
+
* with `useMemo` per the runtime's embedder contract.
|
|
20
|
+
*/
|
|
21
|
+
function createMockRuntime(): ChatRuntime {
|
|
22
|
+
return {
|
|
23
|
+
endpoints: {
|
|
24
|
+
chatStreamUrl: '/__story__/chat',
|
|
25
|
+
approvalToolUrl: '/__story__/confirm-tool',
|
|
26
|
+
commandsUrl: '/__story__/commands',
|
|
27
|
+
buildListUrl: () => null,
|
|
28
|
+
attachmentUploadUrl: '/__story__/upload',
|
|
29
|
+
attachmentViewUrlPrefix: '/__story__/view/',
|
|
30
|
+
chatIdentityUrl: '/__story__/identity',
|
|
31
|
+
},
|
|
32
|
+
navigation: {
|
|
33
|
+
mode: 'embed',
|
|
34
|
+
defaultContentOrigin: 'https://example.com',
|
|
35
|
+
},
|
|
36
|
+
source: 'storybook',
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Stub Mingo config — `getNatsWsUrl` returns null so the NATS dialog
|
|
42
|
+
* subscription stays idle (no WS handshake attempted). `publishUserMessage`
|
|
43
|
+
* just logs; the story exists to demonstrate UI layout, not transport
|
|
44
|
+
* behaviour.
|
|
45
|
+
*/
|
|
46
|
+
function createMockMingoConfig(): UseNatsChatAdapterConfig {
|
|
47
|
+
return {
|
|
48
|
+
dialogId: 'story-dialog-id',
|
|
49
|
+
getNatsWsUrl: () => null,
|
|
50
|
+
publishUserMessage: (text, options) => {
|
|
51
|
+
// eslint-disable-next-line no-console
|
|
52
|
+
console.log('[story] mingo publish', { text, options })
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// =============================================================================
|
|
58
|
+
// Decorator — runtime + react-query + isolated drawer slot
|
|
59
|
+
// =============================================================================
|
|
60
|
+
|
|
61
|
+
function StoryShell({ children }: { children: React.ReactNode }) {
|
|
62
|
+
const runtime = useMemo(() => createMockRuntime(), [])
|
|
63
|
+
const queryClient = useMemo(() => new QueryClient(), [])
|
|
64
|
+
return (
|
|
65
|
+
<QueryClientProvider client={queryClient}>
|
|
66
|
+
<ChatRuntimeContext.Provider value={runtime}>
|
|
67
|
+
{/* Filler content under the drawer so the floating overlay
|
|
68
|
+
has visual context to slide over. */}
|
|
69
|
+
<div className="min-h-[100dvh] bg-ods-bg p-8">
|
|
70
|
+
<div className="text-ods-text-secondary text-sm">
|
|
71
|
+
Storybook canvas — drawer opens on the right →
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
{children}
|
|
75
|
+
</ChatRuntimeContext.Provider>
|
|
76
|
+
</QueryClientProvider>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// =============================================================================
|
|
81
|
+
// Meta
|
|
82
|
+
// =============================================================================
|
|
83
|
+
|
|
84
|
+
const meta = {
|
|
85
|
+
title: 'Chat/EmbeddableChat',
|
|
86
|
+
component: EmbeddableChat,
|
|
87
|
+
parameters: {
|
|
88
|
+
layout: 'fullscreen',
|
|
89
|
+
},
|
|
90
|
+
decorators: [
|
|
91
|
+
(Story) => (
|
|
92
|
+
<StoryShell>
|
|
93
|
+
<Story />
|
|
94
|
+
</StoryShell>
|
|
95
|
+
),
|
|
96
|
+
],
|
|
97
|
+
} satisfies Meta<typeof EmbeddableChat>
|
|
98
|
+
|
|
99
|
+
export default meta
|
|
100
|
+
type Story = StoryObj<typeof meta>
|
|
101
|
+
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// 1. Guide-only (legacy / multi-platform-hub)
|
|
104
|
+
// =============================================================================
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Legacy / single-mode Guide consumer. No `modes` prop — the lib
|
|
108
|
+
* synthesises `modes.guide` from the top-level legacy props. The
|
|
109
|
+
* header has NO mode toggle since only one transport is configured.
|
|
110
|
+
*
|
|
111
|
+
* This is exactly how `multi-platform-hub` mounts the chat today.
|
|
112
|
+
*/
|
|
113
|
+
export const GuideOnly: Story = {
|
|
114
|
+
args: {
|
|
115
|
+
defaultOpen: true,
|
|
116
|
+
showInternalTrigger: false,
|
|
117
|
+
emptyStateGreeting: 'Ask me anything about the OpenFrame docs.',
|
|
118
|
+
suggestedQueries: [
|
|
119
|
+
'How do I install the agent?',
|
|
120
|
+
'What integrations are supported?',
|
|
121
|
+
'Where do I configure SSO?',
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// =============================================================================
|
|
127
|
+
// 2. Mingo-only (NATS agent surface)
|
|
128
|
+
// =============================================================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Mingo-only consumer — the unified chat surface running just the NATS
|
|
132
|
+
* agent transport. Header has NO toggle (only one mode configured).
|
|
133
|
+
* No floating "Ask AI" trigger; the drawer opens uncontrolled.
|
|
134
|
+
*
|
|
135
|
+
* `getNatsWsUrl` returns null in the mock config so no real NATS
|
|
136
|
+
* handshake is attempted — the story renders the empty Mingo panel.
|
|
137
|
+
*/
|
|
138
|
+
export const MingoOnly: Story = {
|
|
139
|
+
render: (args) => (
|
|
140
|
+
<EmbeddableChat
|
|
141
|
+
{...args}
|
|
142
|
+
modes={{
|
|
143
|
+
mingo: createMockMingoConfig(),
|
|
144
|
+
}}
|
|
145
|
+
defaultActiveMode="mingo"
|
|
146
|
+
defaultOpen
|
|
147
|
+
showInternalTrigger={false}
|
|
148
|
+
emptyStateGreeting="Hi — I'm the Mingo agent. What would you like me to help with?"
|
|
149
|
+
/>
|
|
150
|
+
),
|
|
151
|
+
args: {},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// =============================================================================
|
|
155
|
+
// 3. Both modes (toggle visible — openframe-frontend target)
|
|
156
|
+
// =============================================================================
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Dual-mode consumer — Guide + Mingo configured side-by-side. The header
|
|
160
|
+
* shows the segmented toggle `Mingo | Guide`. Clicking the toggle flips
|
|
161
|
+
* the active adapter; each side keeps its own history so the user picks
|
|
162
|
+
* up where they left off.
|
|
163
|
+
*
|
|
164
|
+
* This is the target shape for `openframe-frontend`. Both mocks are
|
|
165
|
+
* idle (no real backend) — toggle and layout are the visible deliverable.
|
|
166
|
+
*/
|
|
167
|
+
export const BothModes: Story = {
|
|
168
|
+
render: (args) => (
|
|
169
|
+
<EmbeddableChat
|
|
170
|
+
{...args}
|
|
171
|
+
modes={{
|
|
172
|
+
guide: {},
|
|
173
|
+
mingo: createMockMingoConfig(),
|
|
174
|
+
}}
|
|
175
|
+
defaultActiveMode="mingo"
|
|
176
|
+
defaultOpen
|
|
177
|
+
showInternalTrigger={false}
|
|
178
|
+
emptyStateGreeting="Switch between Mingo (agent) and Guide (docs) via the header toggle."
|
|
179
|
+
suggestedQueries={[
|
|
180
|
+
'How do I onboard a new device?',
|
|
181
|
+
'Show me the audit log',
|
|
182
|
+
]}
|
|
183
|
+
/>
|
|
184
|
+
),
|
|
185
|
+
args: {},
|
|
186
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivery (ClickUp Bug-fixes & Enhancements) wire types — shared between the
|
|
3
|
+
* hub's `/api/delivery*` route shapes and the lib's `DeliveryTable`/`DeliveryLists`/
|
|
4
|
+
* `DeliverySection` components.
|
|
5
|
+
*
|
|
6
|
+
* Lifted from hub `types/delivery.ts` so embedders consuming the lib's
|
|
7
|
+
* delivery surfaces and the lib's own `ReleaseDetailPage` (which renders
|
|
8
|
+
* related delivery items) share one canonical shape.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export interface DeliveryItem {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
status: string;
|
|
16
|
+
statusColor: string; // ClickUp status color
|
|
17
|
+
taskType: 'Request' | 'Bug' | string; // ClickUp task type
|
|
18
|
+
/**
|
|
19
|
+
* Canonical ClickUp custom_item_id (1008 = Bug, 1009 = Request, …).
|
|
20
|
+
* Surfaced here so the chat's compact card can render a type-specific
|
|
21
|
+
* lucide icon via `TaskTypeIcon` instead of the two-letter initials
|
|
22
|
+
* fallback. Single source of truth lives in
|
|
23
|
+
* `lib/utils/clickup-task-type-utils.ts` (hub-side).
|
|
24
|
+
*/
|
|
25
|
+
customItemId: number | null;
|
|
26
|
+
/**
|
|
27
|
+
* Every ClickUp list the task is associated with (home list + ClickUp's
|
|
28
|
+
* "Tasks in Multiple Lists" locations). UI joins these for display.
|
|
29
|
+
* Falls back to a single-element array containing the home list when
|
|
30
|
+
* there are no additional locations.
|
|
31
|
+
*/
|
|
32
|
+
listNames: string[];
|
|
33
|
+
dateOpened: number; // Unix timestamp
|
|
34
|
+
dateUpdated: number; // Unix timestamp
|
|
35
|
+
dateClosed: number | null; // Unix timestamp or null if not closed
|
|
36
|
+
clickupUrl: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DeliveryResponse {
|
|
40
|
+
completed: DeliveryItem[];
|
|
41
|
+
inProgress: DeliveryItem[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Task type to badge label mapping
|
|
45
|
+
export const TASK_TYPE_LABELS = {
|
|
46
|
+
Request: 'ENHANCEMENT',
|
|
47
|
+
Bug: 'BUG-FIX',
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
// Task type to badge text-color mapping (ODS attention-red for Bug; default for others)
|
|
51
|
+
export const TASK_TYPE_TEXT_COLORS = {
|
|
52
|
+
Request: '', // Default white/grey
|
|
53
|
+
Bug: 'text-[var(--ods-attention-red-error)]',
|
|
54
|
+
} as const;
|
package/src/types/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from './customer-interview'
|
|
|
21
21
|
export * from './customer-interview-ai.types'
|
|
22
22
|
export * from './luma'
|
|
23
23
|
export * from './product-release'
|
|
24
|
+
export * from './delivery'
|
|
24
25
|
export * from './vendor'
|
|
25
26
|
export * from './vendor-links'
|
|
26
27
|
export * from './video-processing'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-sections registry barrel.
|
|
3
|
+
*
|
|
4
|
+
* `RELEASE_STATUS_OPTIONS` (the hub's old alias) is deliberately NOT
|
|
5
|
+
* re-exported — embedders that need the release-status options should
|
|
6
|
+
* import `releaseStatusOptions` from `@flamingo-stack/openframe-frontend-core/types`
|
|
7
|
+
* directly. That matches lib's existing canonical export name and
|
|
8
|
+
* avoids one-way alias drift.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
OPENFRAME_DEV_SECTIONS,
|
|
13
|
+
ROADMAP_STATUS_OPTIONS,
|
|
14
|
+
DELIVERY_TASK_TYPE_OPTIONS,
|
|
15
|
+
type OpenframeDevSection,
|
|
16
|
+
type OpenframeDevSectionKey,
|
|
17
|
+
} from './openframe-dev-sections'
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical per-section metadata for the OpenFrame dev-center surfaces
|
|
3
|
+
* (Roadmap / Bug-fixes & Enhancements / Releases / Onboarding Guides).
|
|
4
|
+
*
|
|
5
|
+
* One file co-locates every per-section value the openframe homepage
|
|
6
|
+
* navigator card AND the destination full-page hero both consume —
|
|
7
|
+
* icon, brief navigator description, longer hero paragraph, search
|
|
8
|
+
* config (placeholder + paramKey), filter config (paramKey + options).
|
|
9
|
+
*
|
|
10
|
+
* Adding a 5th section is one edit here and zero edits across the
|
|
11
|
+
* page files / navigator grid.
|
|
12
|
+
*
|
|
13
|
+
* EMBEDDER NOTE — `onboarding`:
|
|
14
|
+
* The `onboarding` entry is INERT on `hero`/`search`/`filter` because
|
|
15
|
+
* `/onboarding-guides` is owned by `OnboardingGuidesCatalogView` (a
|
|
16
|
+
* hub-side full-page view), not the shared `DevSectionView` chrome.
|
|
17
|
+
* This entry exists ONLY to drive the homepage navigator card. Any
|
|
18
|
+
* embedder iterating the registry must SKIP `onboarding` if they
|
|
19
|
+
* don't host the `/onboarding-guides` route — e.g.
|
|
20
|
+
* `Object.values(OPENFRAME_DEV_SECTIONS).filter(s => s.href !== '/onboarding-guides')`.
|
|
21
|
+
*
|
|
22
|
+
* SERVER-BUNDLE SAFETY:
|
|
23
|
+
* This module imports lucide-react icon components as JSX values but
|
|
24
|
+
* never RENDERS them at module load. Lib's tsup config places `utils/`
|
|
25
|
+
* in the server bundle (no `"use client"` banner), which is safe
|
|
26
|
+
* because component-function references don't execute on import.
|
|
27
|
+
* Precedent: `src/utils/platform-config.tsx` (also lucide imports,
|
|
28
|
+
* also server-bundle, also imported by route-page `metadata` exports).
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { Map as MapIcon, Wrench, Rocket, GraduationCap, type LucideIcon } from 'lucide-react'
|
|
32
|
+
import { releaseStatusOptions } from '../../types'
|
|
33
|
+
|
|
34
|
+
// Roadmap status options — `as const` preserves readonly tuple typing
|
|
35
|
+
// across the registry boundary.
|
|
36
|
+
export const ROADMAP_STATUS_OPTIONS = [
|
|
37
|
+
{ value: 'all', label: 'All' },
|
|
38
|
+
{ value: 'completed', label: 'Completed' },
|
|
39
|
+
{ value: 'in_progress', label: 'In Progress' },
|
|
40
|
+
] as const
|
|
41
|
+
|
|
42
|
+
// Delivery (ClickUp custom item type) filter options. `Bug` and `Request`
|
|
43
|
+
// are the ClickUp `custom_item_id` labels — 1008 / 1009.
|
|
44
|
+
export const DELIVERY_TASK_TYPE_OPTIONS = [
|
|
45
|
+
{ value: 'all', label: 'All' },
|
|
46
|
+
{ value: 'Bug', label: 'Bug-fix' },
|
|
47
|
+
{ value: 'Request', label: 'Enhancement' },
|
|
48
|
+
] as const
|
|
49
|
+
|
|
50
|
+
export interface OpenframeDevSection {
|
|
51
|
+
/** Route href the navigator card and any internal cross-link composes. */
|
|
52
|
+
href: string
|
|
53
|
+
icon: LucideIcon
|
|
54
|
+
/** Brief copy for the homepage navigator card (≈50 char teaser). */
|
|
55
|
+
navigator: {
|
|
56
|
+
title: string
|
|
57
|
+
description: string
|
|
58
|
+
}
|
|
59
|
+
/** Longer copy for the destination page hero (≈120-150 char marketing paragraph). */
|
|
60
|
+
hero: {
|
|
61
|
+
title: string
|
|
62
|
+
description: string
|
|
63
|
+
}
|
|
64
|
+
/** Inline search bar configuration. */
|
|
65
|
+
search: {
|
|
66
|
+
/** Placeholder text shown in the search input. */
|
|
67
|
+
placeholder: string
|
|
68
|
+
/** URL search param the input writes on submit and the list reads on fetch. */
|
|
69
|
+
paramKey: string
|
|
70
|
+
} | null
|
|
71
|
+
/** Filter pill row configuration. `null` when the section has no filter (e.g. onboarding-guides). */
|
|
72
|
+
filter: {
|
|
73
|
+
label: string
|
|
74
|
+
/** URL search param the pills write and the list reads. */
|
|
75
|
+
paramKey: string
|
|
76
|
+
/** The option value that maps to "no filter applied". When selected,
|
|
77
|
+
* the URL param is removed instead of being set. Defaults to the
|
|
78
|
+
* first option's value if omitted — explicit field guards against
|
|
79
|
+
* brittleness if `options` is later reordered. */
|
|
80
|
+
defaultValue: string
|
|
81
|
+
options: readonly { value: string; label: string }[]
|
|
82
|
+
} | null
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const OPENFRAME_DEV_SECTIONS = {
|
|
86
|
+
roadmap: {
|
|
87
|
+
href: '/roadmap',
|
|
88
|
+
icon: MapIcon,
|
|
89
|
+
navigator: {
|
|
90
|
+
title: 'Development Roadmap',
|
|
91
|
+
description: "What we're building next — vote on upcoming features.",
|
|
92
|
+
},
|
|
93
|
+
hero: {
|
|
94
|
+
title: 'Development Roadmap',
|
|
95
|
+
description:
|
|
96
|
+
"See what's in flight, what's planned, and what's up for community vote. The entire OpenFrame roadmap is public.",
|
|
97
|
+
},
|
|
98
|
+
search: { placeholder: 'Search roadmap items...', paramKey: 'search' },
|
|
99
|
+
filter: { label: 'Status', paramKey: 'status', defaultValue: 'all', options: ROADMAP_STATUS_OPTIONS },
|
|
100
|
+
},
|
|
101
|
+
delivery: {
|
|
102
|
+
href: '/bug-fixes-and-enhancements',
|
|
103
|
+
icon: Wrench,
|
|
104
|
+
navigator: {
|
|
105
|
+
title: 'Bug-fixes & Enhancements',
|
|
106
|
+
description: 'Recently shipped fixes and improvements.',
|
|
107
|
+
},
|
|
108
|
+
hero: {
|
|
109
|
+
title: 'Bug-fixes & Enhancements',
|
|
110
|
+
description:
|
|
111
|
+
'A running log of fixes and improvements shipping into OpenFrame — recently completed and actively in progress.',
|
|
112
|
+
},
|
|
113
|
+
search: { placeholder: 'Search tasks...', paramKey: 'search' },
|
|
114
|
+
filter: { label: 'Type', paramKey: 'task_type', defaultValue: 'all', options: DELIVERY_TASK_TYPE_OPTIONS },
|
|
115
|
+
},
|
|
116
|
+
releases: {
|
|
117
|
+
href: '/releases',
|
|
118
|
+
icon: Rocket,
|
|
119
|
+
navigator: {
|
|
120
|
+
title: 'Product Releases',
|
|
121
|
+
description: 'Version history and release notes.',
|
|
122
|
+
},
|
|
123
|
+
hero: {
|
|
124
|
+
title: 'Product Releases',
|
|
125
|
+
description:
|
|
126
|
+
'Version notes, change summaries, and stability tier (alpha / beta / stable) for every OpenFrame release.',
|
|
127
|
+
},
|
|
128
|
+
search: { placeholder: 'Search releases...', paramKey: 'search' },
|
|
129
|
+
filter: { label: 'Status', paramKey: 'release_status', defaultValue: 'all', options: releaseStatusOptions },
|
|
130
|
+
},
|
|
131
|
+
onboarding: {
|
|
132
|
+
href: '/onboarding-guides',
|
|
133
|
+
icon: GraduationCap,
|
|
134
|
+
navigator: {
|
|
135
|
+
title: 'Onboarding Guides',
|
|
136
|
+
description: 'Step-by-step product walkthroughs.',
|
|
137
|
+
},
|
|
138
|
+
// `hero` / `search` / `filter` are intentionally inert here —
|
|
139
|
+
// /onboarding-guides is owned by OnboardingGuidesCatalogView, not
|
|
140
|
+
// DevSectionView. This entry exists ONLY to drive the homepage
|
|
141
|
+
// navigator card so all 4 cards stay in one registry.
|
|
142
|
+
hero: { title: '', description: '' },
|
|
143
|
+
search: null,
|
|
144
|
+
filter: null,
|
|
145
|
+
},
|
|
146
|
+
} as const satisfies Record<string, OpenframeDevSection>
|
|
147
|
+
|
|
148
|
+
export type OpenframeDevSectionKey = keyof typeof OPENFRAME_DEV_SECTIONS
|
package/src/utils/index.ts
CHANGED
|
@@ -168,4 +168,9 @@ export { isCrossOriginUrl } from '../components/chat/utils/is-cross-origin-url'
|
|
|
168
168
|
// React-version-aware `fetchpriority` prop builder — spread into `<img>`
|
|
169
169
|
// / `<iframe>` so the rendered DOM attribute is correct under React 18
|
|
170
170
|
// (lowercase) AND React 19 (camelCase) without console warnings.
|
|
171
|
-
export { fetchPriorityProp, type FetchPriorityValue } from './fetch-priority'
|
|
171
|
+
export { fetchPriorityProp, type FetchPriorityValue } from './fetch-priority'
|
|
172
|
+
|
|
173
|
+
// Dev-center section registry (Roadmap / Delivery / Releases / Onboarding) —
|
|
174
|
+
// server-safe (no JSX, no contexts/* imports); imported by route-page
|
|
175
|
+
// `metadata` exports + the shared `<DevSectionView>` chrome.
|
|
176
|
+
export * from './dev-sections'
|