@semiont/react-ui 0.5.26 → 0.5.28
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/README.md +28 -4
- package/dist/{PdfAnnotationCanvas.client-6ZSF6ZTJ.js → PdfAnnotationCanvas.client-C2IGG4SW.js} +33 -6
- package/dist/{PdfAnnotationCanvas.client-JCJMXWWJ.css → PdfAnnotationCanvas.client-TGDPPGXJ.css} +6 -1
- package/dist/{ar-YTUUGK2O.js → ar-FABPTJVB.js} +88 -26
- package/dist/{bn-ASGNGPMD.js → bn-LKP6BDMH.js} +88 -26
- package/dist/{chunk-L3WKRWP3.js → chunk-2GOHTTHW.js} +88 -26
- package/dist/{chunk-OBQOZCJE.js → chunk-2YHEE63S.js} +31 -31
- package/dist/{cs-WMYVAOZY.js → cs-YQYNWHRG.js} +88 -26
- package/dist/{da-FSHHN4D6.js → da-QHZOYKRY.js} +88 -26
- package/dist/{de-FJFO3TPT.js → de-GKA7RD7J.js} +88 -26
- package/dist/{el-XOH4QIAG.js → el-45T257AL.js} +88 -26
- package/dist/{en-3FCBW3YD.js → en-RVW5EQ66.js} +4 -2
- package/dist/{es-HDX4QI7E.js → es-AVER7RU4.js} +88 -26
- package/dist/{fa-DJ6WTFTJ.js → fa-K3VPK3O2.js} +88 -26
- package/dist/{fi-4S7H7W7U.js → fi-5NEKF7EB.js} +88 -26
- package/dist/{fr-6UJSYHXC.js → fr-FUMNDLBZ.js} +88 -26
- package/dist/{he-ZZJOHJX2.js → he-3JGNA3PR.js} +88 -26
- package/dist/{hi-HZJTAW7U.js → hi-IJY375DF.js} +88 -26
- package/dist/{id-E3I6ILEM.js → id-LWHKJ7ZD.js} +88 -26
- package/dist/index.css +380 -524
- package/dist/index.d.ts +318 -192
- package/dist/index.js +2960 -2421
- package/dist/integrations/css-modules-helper.js +1 -3
- package/dist/{it-ULAPAD7U.js → it-EBVOV4RW.js} +88 -26
- package/dist/{ja-SAHZQ4CZ.js → ja-KWRIX2NF.js} +88 -26
- package/dist/{ko-DFU2ADQ4.js → ko-L5CJMFDS.js} +88 -26
- package/dist/{ms-NWL76XNT.js → ms-LSNMJDR2.js} +88 -26
- package/dist/{nl-ATCM76WN.js → nl-ZB32MB7U.js} +88 -26
- package/dist/{no-UIAQ5RJF.js → no-4GTNY7M5.js} +88 -26
- package/dist/{pl-NOECQDXD.js → pl-LUHBLTHB.js} +88 -26
- package/dist/{pt-SVWIIUPC.js → pt-C4H3UNQ6.js} +88 -26
- package/dist/{ro-NR2DRTZG.js → ro-GGITS5V4.js} +88 -26
- package/dist/{sv-STVJ37JP.js → sv-T56RTLBP.js} +88 -26
- package/dist/test-utils.css +1 -1
- package/dist/test-utils.d.ts +1 -1
- package/dist/test-utils.js +2 -2
- package/dist/{th-UWQR4K54.js → th-22X2IWCB.js} +88 -26
- package/dist/{tr-WNXZSD27.js → tr-77TFG62H.js} +88 -26
- package/dist/{uk-SJRMB47Y.js → uk-MIIL6NXT.js} +88 -26
- package/dist/{vi-TMRQFES2.js → vi-7JYOIGNV.js} +88 -26
- package/dist/{zh-QOL3LYEM.js → zh-ID6DRYU4.js} +88 -26
- package/package.json +11 -10
- package/src/components/AssistProgress.tsx +178 -134
- package/src/components/CodeMirrorRenderer.tsx +8 -8
- package/src/components/{EntityFoundLog.tsx → ItemFoundLog.tsx} +12 -7
- package/src/components/ProtectedErrorBoundary.css +3 -1
- package/src/components/StatusDisplay.css +1 -1
- package/src/components/Toast.css +3 -1
- package/src/components/__tests__/AssistProgress.test.tsx +268 -141
- package/src/components/annotation/annotation-entries.css +0 -4
- package/src/components/annotation/references.css +0 -4
- package/src/components/image-annotation/AnnotationOverlay.tsx +6 -6
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +1 -1
- package/src/components/image-annotation/__tests__/AnnotationOverlay.click.test.tsx +7 -9
- package/src/components/image-annotation/__tests__/SvgDrawingCanvas.click.test.tsx +1 -2
- package/src/components/layout/Header.css +0 -4
- package/src/components/layout/LeftSidebar.css +0 -4
- package/src/components/modals/ComposeStep.tsx +218 -0
- package/src/components/modals/ConfigureGatherStep.tsx +10 -18
- package/src/components/modals/ConfigureGenerationStep.tsx +131 -54
- package/src/components/modals/ConfigureSearchStep.tsx +42 -40
- package/src/components/modals/ContextSummary.tsx +185 -72
- package/src/components/modals/CorpusPane.tsx +75 -0
- package/src/components/modals/DiscardPrompt.tsx +38 -0
- package/src/components/modals/GatherContextStep.tsx +237 -107
- package/src/components/modals/ReferenceWizardModal.tsx +287 -60
- package/src/components/modals/ResourceGenerateModal.tsx +233 -109
- package/src/components/modals/SearchModal.css +335 -111
- package/src/components/modals/SearchModal.tsx +1 -1
- package/src/components/modals/SearchResultsStep.tsx +63 -88
- package/src/components/modals/WizardFooter.tsx +69 -0
- package/src/components/modals/__tests__/ComposeStep.test.tsx +152 -0
- package/src/components/modals/__tests__/ConfigureGatherStep.test.tsx +14 -26
- package/src/components/modals/__tests__/ConfigureGenerationStep.test.tsx +290 -0
- package/src/components/modals/__tests__/ConfigureSearchStep.test.tsx +95 -0
- package/src/components/modals/__tests__/GatherContextStep.resource.test.tsx +463 -25
- package/src/components/modals/__tests__/ReferenceWizardModal.test.tsx +635 -0
- package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +277 -85
- package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchResultsStep.test.tsx +61 -0
- package/src/components/modals/__tests__/WizardFooter.test.tsx +344 -0
- package/src/components/modals/modals.css +16 -42
- package/src/components/navigation/NavigationTabs.css +0 -20
- package/src/components/pdf-annotation/PdfAnnotationCanvas.css +21 -2
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +36 -3
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +41 -6
- package/src/components/resource/AnnotateView.tsx +19 -8
- package/src/components/resource/AnnotationHistory.tsx +2 -0
- package/src/components/resource/BrowseView.tsx +20 -9
- package/src/components/resource/ResourceViewer.tsx +27 -28
- package/src/components/resource/__tests__/AnnotateView.embeddable.test.tsx +1 -1
- package/src/components/resource/__tests__/AnnotateView.focus.test.tsx +50 -0
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +2 -0
- package/src/components/resource/__tests__/BrowseView.embeddable.test.tsx +1 -1
- package/src/components/resource/__tests__/BrowseView.test.tsx +38 -12
- package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +47 -3
- package/src/components/resource/annotate-renderers.tsx +3 -3
- package/src/components/resource/event-formatting.ts +0 -3
- package/src/components/resource/panels/AssessmentEntry.tsx +1 -1
- package/src/components/resource/panels/AssessmentPanel.css +5 -6
- package/src/components/resource/panels/AssistSection.css +95 -263
- package/src/components/resource/panels/AssistSection.tsx +4 -4
- package/src/components/resource/panels/AssistShell.tsx +12 -4
- package/src/components/resource/panels/CollaborationPanel.css +47 -22
- package/src/components/resource/panels/CollaborationPanel.tsx +93 -2
- package/src/components/resource/panels/CommentEntry.tsx +1 -1
- package/src/components/resource/panels/CommentsPanel.css +0 -16
- package/src/components/resource/panels/HighlightEntry.tsx +1 -1
- package/src/components/resource/panels/HighlightPanel.css +0 -7
- package/src/components/resource/panels/JsonLdPanel.css +0 -4
- package/src/components/resource/panels/ReferenceEntry.tsx +10 -3
- package/src/components/resource/panels/ReferencesPanel.css +0 -12
- package/src/components/resource/panels/ReferencesPanel.tsx +16 -20
- package/src/components/resource/panels/ResourceInfoPanel.css +0 -32
- package/src/components/resource/panels/ResourceInfoPanel.tsx +89 -20
- package/src/components/resource/panels/StatisticsPanel.css +0 -20
- package/src/components/resource/panels/TagEntry.tsx +1 -1
- package/src/components/resource/panels/TaggingPanel.css +0 -4
- package/src/components/resource/panels/TaggingPanel.tsx +2 -10
- package/src/components/resource/panels/UnifiedAnnotationsPanel.css +0 -4
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +7 -2
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +48 -50
- package/src/components/resource/panels/__tests__/AssistShell.test.tsx +11 -6
- package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +89 -0
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +44 -36
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +41 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.headless.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +67 -54
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +185 -7
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +0 -1
- package/src/components/settings/SettingsPanel.css +0 -4
- package/src/features/auth/auth.css +2 -26
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +0 -65
- package/src/features/resource-compose/components/ResourceComposePage.tsx +17 -130
- package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +1 -76
- package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -48
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +55 -0
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +29 -0
- package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +53 -3
- package/src/features/resource-discovery/state/discover-state-unit.ts +29 -8
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +71 -15
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +166 -71
- package/src/features/resource-viewer/hooks/__tests__/useResourceViewedReport.test.tsx +63 -0
- package/src/features/resource-viewer/hooks/useResourceViewedReport.ts +33 -0
- package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +2 -2
- package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +1 -1
- package/src/styles/core/buttons.css +3 -1
- package/src/styles/core/forms.css +35 -29
- package/src/styles/core/indicators.css +0 -4
- package/src/styles/core/inputs.css +0 -4
- package/src/styles/core/progress.css +2 -34
- package/src/styles/core/sliders.css +0 -4
- package/src/styles/core/toggles.css +0 -4
- package/src/styles/features/resource-discovery.css +13 -0
- package/src/styles/features/resource-viewer.css +0 -42
- package/src/styles/features/resource.css +0 -4
- package/src/styles/motivations/motivation-assessment.css +2 -2
- package/src/styles/panels/history-panel.css +0 -40
- package/src/styles/panels/user-panel.css +0 -3
- package/src/styles/patterns/panel-helpers.css +0 -27
- package/src/styles/patterns/panel-sections.css +0 -59
- package/src/styles/patterns/panels-base.css +0 -32
- package/translations/ar.json +84 -24
- package/translations/bn.json +84 -24
- package/translations/cs.json +84 -24
- package/translations/da.json +84 -24
- package/translations/de.json +84 -24
- package/translations/el.json +84 -24
- package/translations/en.json +84 -24
- package/translations/es.json +84 -24
- package/translations/fa.json +84 -24
- package/translations/fi.json +84 -24
- package/translations/fr.json +84 -24
- package/translations/he.json +84 -24
- package/translations/hi.json +84 -24
- package/translations/id.json +84 -24
- package/translations/it.json +84 -24
- package/translations/ja.json +84 -24
- package/translations/ko.json +84 -24
- package/translations/ms.json +84 -24
- package/translations/nl.json +84 -24
- package/translations/no.json +84 -24
- package/translations/pl.json +84 -24
- package/translations/pt.json +84 -24
- package/translations/ro.json +84 -24
- package/translations/sv.json +84 -24
- package/translations/th.json +84 -24
- package/translations/tr.json +84 -24
- package/translations/uk.json +84 -24
- package/translations/vi.json +84 -24
- package/translations/zh.json +84 -24
- package/dist/PdfAnnotationCanvas.client-6ZSF6ZTJ.js.map +0 -1
- package/dist/PdfAnnotationCanvas.client-JCJMXWWJ.css.map +0 -1
- package/dist/ar-YTUUGK2O.js.map +0 -1
- package/dist/bn-ASGNGPMD.js.map +0 -1
- package/dist/chunk-BTUG3VJJ.js.map +0 -1
- package/dist/chunk-L3WKRWP3.js.map +0 -1
- package/dist/chunk-O23TLLXW.js.map +0 -1
- package/dist/chunk-OBQOZCJE.js.map +0 -1
- package/dist/chunk-QT7LYM72.js.map +0 -1
- package/dist/chunk-VXASXU4K.js.map +0 -1
- package/dist/chunk-XUDKYAVC.js +0 -21
- package/dist/chunk-XUDKYAVC.js.map +0 -1
- package/dist/cs-WMYVAOZY.js.map +0 -1
- package/dist/da-FSHHN4D6.js.map +0 -1
- package/dist/de-FJFO3TPT.js.map +0 -1
- package/dist/el-XOH4QIAG.js.map +0 -1
- package/dist/en-3FCBW3YD.js.map +0 -1
- package/dist/es-HDX4QI7E.js.map +0 -1
- package/dist/fa-DJ6WTFTJ.js.map +0 -1
- package/dist/fi-4S7H7W7U.js.map +0 -1
- package/dist/fr-6UJSYHXC.js.map +0 -1
- package/dist/he-ZZJOHJX2.js.map +0 -1
- package/dist/hi-HZJTAW7U.js.map +0 -1
- package/dist/id-E3I6ILEM.js.map +0 -1
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/css-modules-helper.js.map +0 -1
- package/dist/integrations/styled-components-theme.js.map +0 -1
- package/dist/it-ULAPAD7U.js.map +0 -1
- package/dist/ja-SAHZQ4CZ.js.map +0 -1
- package/dist/ko-DFU2ADQ4.js.map +0 -1
- package/dist/ms-NWL76XNT.js.map +0 -1
- package/dist/nl-ATCM76WN.js.map +0 -1
- package/dist/no-UIAQ5RJF.js.map +0 -1
- package/dist/pl-NOECQDXD.js.map +0 -1
- package/dist/pt-SVWIIUPC.js.map +0 -1
- package/dist/ro-NR2DRTZG.js.map +0 -1
- package/dist/sv-STVJ37JP.js.map +0 -1
- package/dist/test-utils.css.map +0 -1
- package/dist/test-utils.js.map +0 -1
- package/dist/th-UWQR4K54.js.map +0 -1
- package/dist/tr-WNXZSD27.js.map +0 -1
- package/dist/uk-SJRMB47Y.js.map +0 -1
- package/dist/vi-TMRQFES2.js.map +0 -1
- package/dist/zh-QOL3LYEM.js.map +0 -1
- package/src/components/modals/ResourceSearchModal.tsx +0 -224
- package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +0 -159
- package/src/integrations/tailwind-plugin.cjs +0 -224
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import type { ConnectionState } from '@semiont/core';
|
|
3
|
+
import type { CollaboratorEntry, ConnectionState } from '@semiont/core';
|
|
4
4
|
import { useTranslations } from '../../../contexts/TranslationContext';
|
|
5
5
|
import './CollaborationPanel.css';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Token counts read as ceilings, not quantities — "200K" carries the meaning a
|
|
9
|
+
* bare 200000 makes the reader compute. Kept lossless above the K/M break so a
|
|
10
|
+
* 128000 window never displays as a rounded-away 130K.
|
|
11
|
+
*/
|
|
12
|
+
function formatTokens(n: number): string {
|
|
13
|
+
if (n >= 1_000_000) {
|
|
14
|
+
const m = n / 1_000_000;
|
|
15
|
+
return `${Number.isInteger(m) ? m : m.toFixed(1)}M`;
|
|
16
|
+
}
|
|
17
|
+
if (n >= 1_000) {
|
|
18
|
+
const k = n / 1_000;
|
|
19
|
+
return `${Number.isInteger(k) ? k : k.toFixed(1)}K`;
|
|
20
|
+
}
|
|
21
|
+
return String(n);
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
interface Props {
|
|
8
25
|
/**
|
|
9
26
|
* Connection state from `client.actor.state$`. See
|
|
@@ -26,16 +43,34 @@ interface Props {
|
|
|
26
43
|
eventCount: number;
|
|
27
44
|
lastEventTimestamp?: string;
|
|
28
45
|
knowledgeBaseName?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The KB's collaborator roster (`client.browse.agents()`, typically via
|
|
48
|
+
* `useCollaborators`). Optional so hosts that never wire it — including
|
|
49
|
+
* external consumers of this package — render exactly as before.
|
|
50
|
+
*
|
|
51
|
+
* Each entry's `limits` is absent whenever discovery could not answer *right
|
|
52
|
+
* now* (INFERENCE-LIMITS-EXPOSURE D3), so a missing ceiling is normal and
|
|
53
|
+
* shows as no ceiling rather than as an error.
|
|
54
|
+
*/
|
|
55
|
+
collaborators?: CollaboratorEntry[];
|
|
29
56
|
}
|
|
30
57
|
|
|
31
58
|
export function CollaborationPanel({
|
|
32
59
|
state,
|
|
33
60
|
eventCount,
|
|
34
61
|
lastEventTimestamp,
|
|
35
|
-
knowledgeBaseName
|
|
62
|
+
knowledgeBaseName,
|
|
63
|
+
collaborators
|
|
36
64
|
}: Props) {
|
|
37
65
|
const t = useTranslations('CollaborationPanel');
|
|
38
66
|
|
|
67
|
+
// Only Software agents have a provider/model and can carry inference
|
|
68
|
+
// ceilings; Persons and Organizations are collaborators in a different
|
|
69
|
+
// sense and have nothing to show in this section.
|
|
70
|
+
const softwareAgents = (collaborators ?? []).filter(
|
|
71
|
+
(entry) => entry.agent['@type'] === 'Software',
|
|
72
|
+
);
|
|
73
|
+
|
|
39
74
|
// Healthy = live, or briefly flapping. Only genuinely sustained
|
|
40
75
|
// disconnects surface as "Disconnected" in the UI.
|
|
41
76
|
const isHealthy = state === 'open' || state === 'reconnecting' || state === 'initial' || state === 'connecting';
|
|
@@ -122,6 +157,62 @@ export function CollaborationPanel({
|
|
|
122
157
|
</div>
|
|
123
158
|
</div>
|
|
124
159
|
|
|
160
|
+
{/* Collaborators roster — software agents and their discovered ceilings */}
|
|
161
|
+
{softwareAgents.length > 0 && (
|
|
162
|
+
<div className="semiont-collaboration-panel__section semiont-collaboration-panel__section--bordered">
|
|
163
|
+
<h3 className="semiont-collaboration-panel__heading">
|
|
164
|
+
{t('collaborators')}
|
|
165
|
+
</h3>
|
|
166
|
+
{softwareAgents.map((entry, i) => {
|
|
167
|
+
// `agent` is narrowed to the Software member by the filter above,
|
|
168
|
+
// but the generated union is structural, so read through a local.
|
|
169
|
+
const agent = entry.agent as Extract<CollaboratorEntry['agent'], { '@type': 'Software' }>;
|
|
170
|
+
const limits = entry.limits;
|
|
171
|
+
// `maxOutputTokens === contextTokens` is the schema's documented
|
|
172
|
+
// sentinel for a provider with ONE shared window (Ollama). Showing
|
|
173
|
+
// "128K in / 128K out" there would invent a distinction the
|
|
174
|
+
// provider does not make.
|
|
175
|
+
const ceiling = !limits
|
|
176
|
+
? null
|
|
177
|
+
: limits.maxOutputTokens === limits.contextTokens
|
|
178
|
+
? t('sharedWindow', { contextTokens: formatTokens(limits.contextTokens) })
|
|
179
|
+
: t('ceilings', {
|
|
180
|
+
contextTokens: formatTokens(limits.contextTokens),
|
|
181
|
+
maxOutputTokens: formatTokens(limits.maxOutputTokens),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div
|
|
186
|
+
key={agent['@id'] ?? `${agent.provider}:${agent.model}:${i}`}
|
|
187
|
+
className="semiont-collaboration-panel__collaborator"
|
|
188
|
+
data-testid="semiont-collaborator-row"
|
|
189
|
+
>
|
|
190
|
+
<div className="semiont-collaboration-panel__collaborator-id">
|
|
191
|
+
{agent.provider && (
|
|
192
|
+
<span className="semiont-collaboration-panel__collaborator-provider">
|
|
193
|
+
{agent.provider}
|
|
194
|
+
</span>
|
|
195
|
+
)}
|
|
196
|
+
<span className="semiont-collaboration-panel__collaborator-model">
|
|
197
|
+
{agent.model ?? agent.name}
|
|
198
|
+
</span>
|
|
199
|
+
</div>
|
|
200
|
+
{entry.servesJobTypes && entry.servesJobTypes.length > 0 && (
|
|
201
|
+
<div className="semiont-collaboration-panel__collaborator-jobs">
|
|
202
|
+
{entry.servesJobTypes.join(', ')}
|
|
203
|
+
</div>
|
|
204
|
+
)}
|
|
205
|
+
{ceiling && (
|
|
206
|
+
<div className="semiont-collaboration-panel__collaborator-limits">
|
|
207
|
+
{ceiling}
|
|
208
|
+
</div>
|
|
209
|
+
)}
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
})}
|
|
213
|
+
</div>
|
|
214
|
+
)}
|
|
215
|
+
|
|
125
216
|
{/* Sharing Section - Placeholder for future */}
|
|
126
217
|
<div className="semiont-collaboration-panel__section semiont-collaboration-panel__section--bordered">
|
|
127
218
|
<h3 className="semiont-collaboration-panel__heading">
|
|
@@ -87,7 +87,7 @@ export function CommentEntry({
|
|
|
87
87
|
data-type="comment"
|
|
88
88
|
data-focused={isFocused ? 'true' : 'false'}
|
|
89
89
|
onClick={() => {
|
|
90
|
-
session?.client.browse.click(comment.id
|
|
90
|
+
session?.client.browse.click(comment.id);
|
|
91
91
|
}}
|
|
92
92
|
{...hoverProps}
|
|
93
93
|
>
|
|
@@ -31,10 +31,6 @@
|
|
|
31
31
|
margin-bottom: var(--semiont-panel-header-margin-bottom);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
[data-theme="dark"] .semiont-comments-panel__title {
|
|
35
|
-
color: var(--semiont-text-primary);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
34
|
.semiont-comments-panel__list {
|
|
39
35
|
flex: 1;
|
|
40
36
|
overflow-y: auto;
|
|
@@ -68,29 +64,17 @@
|
|
|
68
64
|
color: var(--semiont-text-primary);
|
|
69
65
|
}
|
|
70
66
|
|
|
71
|
-
[data-theme="dark"] .semiont-comments-panel__comment-author {
|
|
72
|
-
color: var(--semiont-text-primary);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
67
|
.semiont-comments-panel__comment-time {
|
|
76
68
|
font-size: var(--semiont-text-xs);
|
|
77
69
|
color: var(--semiont-text-tertiary);
|
|
78
70
|
}
|
|
79
71
|
|
|
80
|
-
[data-theme="dark"] .semiont-comments-panel__comment-time {
|
|
81
|
-
color: var(--semiont-text-tertiary);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
72
|
.semiont-comments-panel__comment-text {
|
|
85
73
|
font-size: var(--semiont-text-sm);
|
|
86
74
|
color: var(--semiont-text-primary);
|
|
87
75
|
line-height: 1.5;
|
|
88
76
|
}
|
|
89
77
|
|
|
90
|
-
[data-theme="dark"] .semiont-comments-panel__comment-text {
|
|
91
|
-
color: var(--semiont-text-primary);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
78
|
.semiont-comments-panel__input-area {
|
|
95
79
|
padding: var(--semiont-panel-padding);
|
|
96
80
|
border-top: 1px solid var(--semiont-color-gray-200);
|
|
@@ -51,7 +51,7 @@ export function HighlightEntry({
|
|
|
51
51
|
data-type="highlight"
|
|
52
52
|
data-focused={isFocused ? 'true' : 'false'}
|
|
53
53
|
onClick={() => {
|
|
54
|
-
session?.client.browse.click(highlight.id
|
|
54
|
+
session?.client.browse.click(highlight.id);
|
|
55
55
|
}}
|
|
56
56
|
{...hoverProps}
|
|
57
57
|
>
|
|
@@ -30,10 +30,6 @@
|
|
|
30
30
|
letter-spacing: 0.05em;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
[data-theme="dark"] .semiont-highlight-panel__label {
|
|
34
|
-
color: var(--semiont-text-secondary);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
33
|
.semiont-highlight-panel__colors {
|
|
38
34
|
display: grid;
|
|
39
35
|
grid-template-columns: repeat(5, 1fr);
|
|
@@ -58,6 +54,3 @@
|
|
|
58
54
|
transform: scale(1.1);
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
[data-theme="dark"] .semiont-highlight-panel__color--selected {
|
|
62
|
-
border-color: var(--semiont-text-primary);
|
|
63
|
-
}
|
|
@@ -27,6 +27,8 @@ interface ReferenceEntryProps {
|
|
|
27
27
|
onOpenResource?: (resourceId: string) => void;
|
|
28
28
|
annotateMode?: boolean;
|
|
29
29
|
isGenerating?: boolean;
|
|
30
|
+
/** The reference just got attention-worthy (created or resolved) — glow the icon (RESOLUTION-SPARKLE D6). */
|
|
31
|
+
sparkle?: boolean;
|
|
30
32
|
ref?: Ref<HTMLDivElement>;
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -38,6 +40,7 @@ export function ReferenceEntry({
|
|
|
38
40
|
onOpenResource,
|
|
39
41
|
annotateMode = true,
|
|
40
42
|
isGenerating = false,
|
|
43
|
+
sparkle = false,
|
|
41
44
|
ref,
|
|
42
45
|
}: ReferenceEntryProps) {
|
|
43
46
|
const t = useTranslations('ReferencesPanel');
|
|
@@ -117,7 +120,7 @@ export function ReferenceEntry({
|
|
|
117
120
|
data-type="reference"
|
|
118
121
|
data-focused={isFocused ? 'true' : 'false'}
|
|
119
122
|
onClick={() => {
|
|
120
|
-
session?.client.browse.click(reference.id
|
|
123
|
+
session?.client.browse.click(reference.id);
|
|
121
124
|
}}
|
|
122
125
|
{...hoverProps}
|
|
123
126
|
>
|
|
@@ -125,7 +128,7 @@ export function ReferenceEntry({
|
|
|
125
128
|
<div className="semiont-annotation-entry__header">
|
|
126
129
|
<div className="semiont-reference-icon-group">
|
|
127
130
|
<button
|
|
128
|
-
className={`semiont-reference-icon${iconIsClickable ? ' semiont-reference-icon--clickable' : ''}`}
|
|
131
|
+
className={`semiont-reference-icon${iconIsClickable ? ' semiont-reference-icon--clickable' : ''}${sparkle ? ' annotation-sparkle' : ''}`}
|
|
129
132
|
title={isResolved ? t('open') : annotateMode ? t('resolve') : t('stub')}
|
|
130
133
|
onClick={iconIsClickable ? handleIconClick : undefined}
|
|
131
134
|
data-generating={!isResolved && isGenerating ? 'true' : 'false'}
|
|
@@ -151,7 +154,11 @@ export function ReferenceEntry({
|
|
|
151
154
|
)}
|
|
152
155
|
{!selectedText && (
|
|
153
156
|
<div className="semiont-annotation-entry__meta">
|
|
154
|
-
{
|
|
157
|
+
{/* A resource-level annotation with a resolved, named target is
|
|
158
|
+
a derivation (the shape generation mints — the vocabulary
|
|
159
|
+
deliberately has no 'deriving' purpose): qualify the link
|
|
160
|
+
line below instead of showing the generic type label. */}
|
|
161
|
+
{!selector && resolvedDocumentName ? t('derived') : annotationType}
|
|
155
162
|
</div>
|
|
156
163
|
)}
|
|
157
164
|
{resolvedDocumentName && (
|
|
@@ -37,30 +37,18 @@
|
|
|
37
37
|
margin-bottom: var(--semiont-panel-header-margin-bottom);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
[data-theme="dark"] .semiont-references-panel__title {
|
|
41
|
-
color: var(--semiont-text-primary);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
40
|
.semiont-references-panel__path {
|
|
45
41
|
font-size: var(--semiont-text-sm);
|
|
46
42
|
color: var(--semiont-text-tertiary);
|
|
47
43
|
margin-top: var(--semiont-panel-padding-xs);
|
|
48
44
|
}
|
|
49
45
|
|
|
50
|
-
[data-theme="dark"] .semiont-references-panel__path {
|
|
51
|
-
color: var(--semiont-text-tertiary);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
46
|
.semiont-references-panel__count {
|
|
55
47
|
font-size: var(--semiont-text-sm);
|
|
56
48
|
color: var(--semiont-text-tertiary);
|
|
57
49
|
margin-top: var(--semiont-panel-padding-xs);
|
|
58
50
|
}
|
|
59
51
|
|
|
60
|
-
[data-theme="dark"] .semiont-references-panel__count {
|
|
61
|
-
color: var(--semiont-text-tertiary);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
52
|
/* Reference Icon Group — status icon + hover-reveal unlink */
|
|
65
53
|
.semiont-reference-icon-group {
|
|
66
54
|
position: relative;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
4
|
+
import { assistProgressTranslations } from '../../../lib/assist-progress-copy';
|
|
4
5
|
import { useTranslations } from '../../../contexts/TranslationContext';
|
|
5
6
|
import type { SemiontSession } from '@semiont/sdk';
|
|
6
7
|
import { useSessionEventSubscriptions } from '../../../hooks/useSessionEventSubscriptions';
|
|
7
8
|
import type { RouteBuilder, LinkComponentProps } from '../../../contexts/RoutingContext';
|
|
8
9
|
import { AssistShell } from './AssistShell';
|
|
9
|
-
import {
|
|
10
|
+
import { ItemFoundLog } from '../../ItemFoundLog';
|
|
10
11
|
import { ReferenceEntry } from './ReferenceEntry';
|
|
11
12
|
import type { components, Selector } from '@semiont/core';
|
|
12
13
|
import { getTextPositionSelector, getTargetSelector } from '@semiont/core';
|
|
@@ -82,6 +83,8 @@ interface Props {
|
|
|
82
83
|
scrollToAnnotationId?: string | null;
|
|
83
84
|
onScrollCompleted?: () => void;
|
|
84
85
|
hoveredAnnotationId?: string | null;
|
|
86
|
+
/** Annotations currently sparkling (recently created or resolved) — entries in the set glow their icon (RESOLUTION-SPARKLE D6). */
|
|
87
|
+
sparkleAnnotationIds?: Set<string>;
|
|
85
88
|
|
|
86
89
|
/** User UI locale — stamped on the unresolved-reference body's `language` field. */
|
|
87
90
|
locale?: string;
|
|
@@ -118,6 +121,7 @@ export function ReferencesPanel({
|
|
|
118
121
|
scrollToAnnotationId,
|
|
119
122
|
onScrollCompleted,
|
|
120
123
|
hoveredAnnotationId,
|
|
124
|
+
sparkleAnnotationIds,
|
|
121
125
|
locale,
|
|
122
126
|
sourceLanguage,
|
|
123
127
|
}: Props) {
|
|
@@ -126,7 +130,7 @@ export function ReferencesPanel({
|
|
|
126
130
|
// lives in one namespace so the same words aren't re-translated per panel.
|
|
127
131
|
const ta = useTranslations('AssistProgress');
|
|
128
132
|
const [selectedEntityTypes, setSelectedEntityTypes] = useState<string[]>([]);
|
|
129
|
-
const [lastAnnotationLog, setLastDetectionLog] = useState<Array<{
|
|
133
|
+
const [lastAnnotationLog, setLastDetectionLog] = useState<Array<{ value: string; foundCount: number }> | null>(null);
|
|
130
134
|
const [pendingEntityTypes, setPendingEntityTypes] = useState<string[]>([]);
|
|
131
135
|
const [includeDescriptiveReferences, setIncludeDescriptiveReferences] = useState(false);
|
|
132
136
|
const [focusedAnnotationId, setFocusedAnnotationId] = useState<string | null>(null);
|
|
@@ -243,8 +247,8 @@ export function ReferencesPanel({
|
|
|
243
247
|
|
|
244
248
|
// Save detection log when detection completes
|
|
245
249
|
// Only depends on isAssisting boolean to avoid infinite loops from array reference changes
|
|
246
|
-
// Trade-off: If
|
|
247
|
-
// This is acceptable because in practice,
|
|
250
|
+
// Trade-off: If completedItems changes while isAssisting stays false, we won't update
|
|
251
|
+
// This is acceptable because in practice, completedItems only changes when annotation finishes
|
|
248
252
|
useEffect(() => {
|
|
249
253
|
// When annotation starts, reset the flag
|
|
250
254
|
if (isAssisting) {
|
|
@@ -253,12 +257,12 @@ export function ReferencesPanel({
|
|
|
253
257
|
}
|
|
254
258
|
|
|
255
259
|
// When annotation is complete and we haven't saved yet, save the log
|
|
256
|
-
if (!hasSavedLogRef.current && progress?.
|
|
260
|
+
if (!hasSavedLogRef.current && progress?.completedItems) {
|
|
257
261
|
hasSavedLogRef.current = true;
|
|
258
|
-
setLastDetectionLog(progress.
|
|
262
|
+
setLastDetectionLog(progress.completedItems);
|
|
259
263
|
setSelectedEntityTypes([]);
|
|
260
264
|
}
|
|
261
|
-
}, [isAssisting, progress?.
|
|
265
|
+
}, [isAssisting, progress?.completedItems]); // Both dependencies needed to annotation completion
|
|
262
266
|
|
|
263
267
|
const togglePendingEntityType = (type: string) => {
|
|
264
268
|
setPendingEntityTypes(prev =>
|
|
@@ -371,24 +375,15 @@ export function ReferencesPanel({
|
|
|
371
375
|
progressProps={{
|
|
372
376
|
onCancel: () => session?.client.job.cancelRequest('annotation'),
|
|
373
377
|
onDismiss: () => session?.client.mark.dismissProgress(),
|
|
374
|
-
translations: {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
inProgress: t('annotating'),
|
|
378
|
-
complete: t('complete'),
|
|
379
|
-
failed: t('failed'),
|
|
380
|
-
found: (count) => t('found', { count }),
|
|
381
|
-
current: (entityType) => t('current', { entityType }),
|
|
382
|
-
paramsTitle: ta('paramsTitle'),
|
|
383
|
-
processing: (label) => ta('processing', { label }),
|
|
384
|
-
close: ta('close'),
|
|
385
|
-
},
|
|
378
|
+
translations: assistProgressTranslations(ta, {
|
|
379
|
+
found: (count: number) => t('found', { count }),
|
|
380
|
+
}),
|
|
386
381
|
}}
|
|
387
382
|
form={
|
|
388
383
|
<>
|
|
389
384
|
{/* Completed annotation log - shown after completion */}
|
|
390
385
|
{lastAnnotationLog && (
|
|
391
|
-
<
|
|
386
|
+
<ItemFoundLog
|
|
392
387
|
entries={lastAnnotationLog}
|
|
393
388
|
formatFound={(count) => t('found', { count })}
|
|
394
389
|
/>
|
|
@@ -491,6 +486,7 @@ export function ReferencesPanel({
|
|
|
491
486
|
onOpenResource={onOpenResource}
|
|
492
487
|
annotateMode={annotateMode}
|
|
493
488
|
isGenerating={reference.id === generatingReferenceId}
|
|
489
|
+
sparkle={sparkleAnnotationIds?.has(reference.id) ?? false}
|
|
494
490
|
ref={(el) => setEntryRef(reference.id, el)}
|
|
495
491
|
/>
|
|
496
492
|
))
|
|
@@ -21,10 +21,6 @@
|
|
|
21
21
|
color: var(--semiont-text-primary);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
[data-theme="dark"] .semiont-resource-info-panel__title {
|
|
25
|
-
color: var(--semiont-text-primary);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
.semiont-resource-info-panel__section {
|
|
29
25
|
margin-bottom: var(--semiont-panel-gap);
|
|
30
26
|
}
|
|
@@ -40,28 +36,16 @@
|
|
|
40
36
|
margin-bottom: var(--semiont-panel-gap-sm);
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
[data-theme="dark"] .semiont-resource-info-panel__heading {
|
|
44
|
-
color: var(--semiont-text-primary);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
39
|
.semiont-resource-info-panel__value {
|
|
48
40
|
font-size: var(--semiont-text-sm);
|
|
49
41
|
color: var(--semiont-text-primary);
|
|
50
42
|
}
|
|
51
43
|
|
|
52
|
-
[data-theme="dark"] .semiont-resource-info-panel__value {
|
|
53
|
-
color: var(--semiont-text-primary);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
44
|
.semiont-resource-info-panel__value--empty {
|
|
57
45
|
color: var(--semiont-text-tertiary);
|
|
58
46
|
font-style: italic;
|
|
59
47
|
}
|
|
60
48
|
|
|
61
|
-
[data-theme="dark"] .semiont-resource-info-panel__value--empty {
|
|
62
|
-
color: var(--semiont-text-tertiary);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
49
|
.semiont-resource-info-panel__metric {
|
|
66
50
|
display: flex;
|
|
67
51
|
align-items: center;
|
|
@@ -78,20 +62,12 @@
|
|
|
78
62
|
font-size: var(--semiont-text-sm);
|
|
79
63
|
}
|
|
80
64
|
|
|
81
|
-
[data-theme="dark"] .semiont-resource-info-panel__metric-label {
|
|
82
|
-
color: var(--semiont-text-tertiary);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
65
|
.semiont-resource-info-panel__metric-value {
|
|
86
66
|
color: var(--semiont-text-primary);
|
|
87
67
|
font-size: var(--semiont-text-sm);
|
|
88
68
|
font-weight: var(--semiont-font-medium);
|
|
89
69
|
}
|
|
90
70
|
|
|
91
|
-
[data-theme="dark"] .semiont-resource-info-panel__metric-value {
|
|
92
|
-
color: var(--semiont-text-primary);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
71
|
.semiont-resource-info-panel__tags {
|
|
96
72
|
display: flex;
|
|
97
73
|
flex-wrap: wrap;
|
|
@@ -142,10 +118,6 @@
|
|
|
142
118
|
margin-right: var(--semiont-panel-gap-sm);
|
|
143
119
|
}
|
|
144
120
|
|
|
145
|
-
[data-theme="dark"] .semiont-resource-info-panel__label {
|
|
146
|
-
color: var(--semiont-text-tertiary);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
121
|
.semiont-resource-info-panel__tag-list {
|
|
150
122
|
display: flex;
|
|
151
123
|
flex-wrap: wrap;
|
|
@@ -169,10 +141,6 @@
|
|
|
169
141
|
line-height: 1.5;
|
|
170
142
|
}
|
|
171
143
|
|
|
172
|
-
[data-theme="dark"] .semiont-resource-info-panel__description {
|
|
173
|
-
color: var(--semiont-text-tertiary);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
144
|
/* Resource Info Panel Buttons */
|
|
177
145
|
.semiont-resource-button {
|
|
178
146
|
width: 100%;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useTranslations } from '../../../contexts/TranslationContext';
|
|
4
|
-
import type
|
|
4
|
+
import { readyValue, type SemiontSession, type YieldOutcome } from '@semiont/sdk';
|
|
5
5
|
import { formatLocaleDisplay } from '@semiont/core';
|
|
6
6
|
import { resourceId as makeResourceId, type components } from '@semiont/core';
|
|
7
|
+
import { useObservable } from '../../../hooks/useObservable';
|
|
7
8
|
import { renderAgentLabel } from './agent-label';
|
|
9
|
+
import { AssistShell } from './AssistShell';
|
|
10
|
+
import { assistProgressTranslations } from '../../../lib/assist-progress-copy';
|
|
8
11
|
import './ResourceInfoPanel.css';
|
|
9
12
|
|
|
10
13
|
type Agent = components['schemas']['Agent'];
|
|
14
|
+
type JobProgress = components['schemas']['JobProgress'];
|
|
11
15
|
|
|
12
16
|
interface Props {
|
|
13
17
|
/** Session carrying the client and event bus; null renders inert. */
|
|
@@ -30,6 +34,17 @@ interface Props {
|
|
|
30
34
|
* to a verb). Omit to hide the Generate action.
|
|
31
35
|
*/
|
|
32
36
|
onGenerate?: () => void;
|
|
37
|
+
/**
|
|
38
|
+
* Generation lifecycle, page-held (`yield.isGenerating$` / `yield.progress$`
|
|
39
|
+
* / `yield.outcome$`): this panel is generation's progress surface
|
|
40
|
+
* (GENERATE-FROM-RESOURCE D7) — the run reports where it was started.
|
|
41
|
+
*/
|
|
42
|
+
isGenerating?: boolean;
|
|
43
|
+
generationProgress?: JobProgress | null;
|
|
44
|
+
/** The finished run's result; the ended frame links it by name (D8). */
|
|
45
|
+
generationOutcome?: YieldOutcome | null;
|
|
46
|
+
/** Clear the finished display — wires `yield.dismissProgress()`. */
|
|
47
|
+
onDismissProgress?: () => void;
|
|
33
48
|
}
|
|
34
49
|
|
|
35
50
|
/**
|
|
@@ -54,8 +69,13 @@ export function ResourceInfoPanel({
|
|
|
54
69
|
wasDerivedFrom,
|
|
55
70
|
generator,
|
|
56
71
|
onGenerate,
|
|
72
|
+
isGenerating = false,
|
|
73
|
+
generationProgress = null,
|
|
74
|
+
generationOutcome = null,
|
|
75
|
+
onDismissProgress,
|
|
57
76
|
}: Props) {
|
|
58
77
|
const t = useTranslations('ResourceInfoPanel');
|
|
78
|
+
const ta = useTranslations('AssistProgress');
|
|
59
79
|
|
|
60
80
|
// Single attribution surface. `wasAttributedTo` is the canonical list
|
|
61
81
|
// of responsible parties; if a producer set only `generator` we
|
|
@@ -152,13 +172,7 @@ export function ResourceInfoPanel({
|
|
|
152
172
|
<span className="semiont-resource-info-panel__label">{t('derivedFrom')}</span>
|
|
153
173
|
<span className="semiont-resource-info-panel__value">
|
|
154
174
|
{(Array.isArray(wasDerivedFrom) ? wasDerivedFrom : [wasDerivedFrom]).map((id, i) => (
|
|
155
|
-
<
|
|
156
|
-
key={id}
|
|
157
|
-
className="semiont-resource-info-panel__link"
|
|
158
|
-
onClick={() => session?.client.browse.navigateReference(makeResourceId(id))}
|
|
159
|
-
>
|
|
160
|
-
{i > 0 && ', '}{id}
|
|
161
|
-
</button>
|
|
175
|
+
<DerivedFromLink key={id} session={session} id={id} first={i === 0} />
|
|
162
176
|
))}
|
|
163
177
|
</span>
|
|
164
178
|
</div>
|
|
@@ -185,19 +199,47 @@ export function ResourceInfoPanel({
|
|
|
185
199
|
</div>
|
|
186
200
|
)}
|
|
187
201
|
|
|
188
|
-
{/* Generate
|
|
202
|
+
{/* Generate — the run reports where it was started (GENERATE-FROM-RESOURCE
|
|
203
|
+
D7): the same AssistShell every assist uses, its form the Generate
|
|
204
|
+
control, the progress frame in its place while a generation runs. */}
|
|
189
205
|
{onGenerate && (
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
{
|
|
199
|
-
|
|
200
|
-
|
|
206
|
+
<AssistShell
|
|
207
|
+
assistType="generation"
|
|
208
|
+
title={t('generate')}
|
|
209
|
+
isAssisting={isGenerating}
|
|
210
|
+
progress={generationProgress}
|
|
211
|
+
progressProps={{
|
|
212
|
+
onCancel: () => session?.client.job.cancelRequest('generation'),
|
|
213
|
+
...(onDismissProgress ? { onDismiss: onDismissProgress } : {}),
|
|
214
|
+
...(generationOutcome ? {
|
|
215
|
+
outcome: {
|
|
216
|
+
label: generationOutcome.resourceName,
|
|
217
|
+
onOpen: () => session?.client.browse.openResource(generationOutcome.resourceId),
|
|
218
|
+
},
|
|
219
|
+
// The terminal sentence derives from the OUTCOME, not the final
|
|
220
|
+
// progress frame — whose fire-and-forget emit can lose the race
|
|
221
|
+
// with job:complete and leave "creating…" beside a ✅
|
|
222
|
+
// (GENERATION-ARRIVAL D4/D5).
|
|
223
|
+
endedMessage: generationOutcome.truncated
|
|
224
|
+
? ta('codeCompleteGeneratedTruncated')
|
|
225
|
+
: ta('codeCompleteGenerated'),
|
|
226
|
+
} : {}),
|
|
227
|
+
translations: assistProgressTranslations(ta),
|
|
228
|
+
}}
|
|
229
|
+
form={
|
|
230
|
+
<>
|
|
231
|
+
<button
|
|
232
|
+
onClick={onGenerate}
|
|
233
|
+
className="semiont-resource-button semiont-resource-button--secondary"
|
|
234
|
+
>
|
|
235
|
+
✨ {t('generate')}
|
|
236
|
+
</button>
|
|
237
|
+
<p className="semiont-resource-info-panel__description">
|
|
238
|
+
{t('generateDescription')}
|
|
239
|
+
</p>
|
|
240
|
+
</>
|
|
241
|
+
}
|
|
242
|
+
/>
|
|
201
243
|
)}
|
|
202
244
|
|
|
203
245
|
{/* Clone Action */}
|
|
@@ -244,3 +286,30 @@ export function ResourceInfoPanel({
|
|
|
244
286
|
</div>
|
|
245
287
|
);
|
|
246
288
|
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* One derived-from entry: linked by id (wire identity), labeled by the source
|
|
292
|
+
* resource's NAME once `browse.resource` serves its descriptor. The raw id is
|
|
293
|
+
* the honest label until then — and stays if the descriptor never resolves
|
|
294
|
+
* (deleted source, no session). Own component because the id list maps in a
|
|
295
|
+
* loop and the subscription is a hook.
|
|
296
|
+
*/
|
|
297
|
+
function DerivedFromLink({ session, id, first }: {
|
|
298
|
+
session: SemiontSession | null;
|
|
299
|
+
id: string;
|
|
300
|
+
first: boolean;
|
|
301
|
+
}) {
|
|
302
|
+
// `browse.resource` is stable per id (cache + scope wrappers memoize), so
|
|
303
|
+
// subscribing straight off the render read is safe; `failed` is an emission,
|
|
304
|
+
// never a stream error, so `readyValue` covers every unresolved state.
|
|
305
|
+
const descriptor = useObservable(session ? session.client.browse.resource(makeResourceId(id)) : null);
|
|
306
|
+
const name = descriptor ? readyValue(descriptor)?.name : undefined;
|
|
307
|
+
return (
|
|
308
|
+
<button
|
|
309
|
+
className="semiont-resource-info-panel__link"
|
|
310
|
+
onClick={() => session?.client.browse.openResource(makeResourceId(id))}
|
|
311
|
+
>
|
|
312
|
+
{!first && ', '}{name ?? id}
|
|
313
|
+
</button>
|
|
314
|
+
);
|
|
315
|
+
}
|