mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
feat(analytics): add project_id + project_kind to studio/artifact events (#1509)
Product tracking doc 260513 added project_id + project_kind to studio_view (artifact), studio_click (share_option), and artifact_export_result. The Studio funnel can now group by project type without joining run_created on the back end. - contracts: 3 props gain required project_id + project_kind - ProjectView → FileWorkspace → FileViewer: thread projectKind down, converting metadata.kind via projectKindToTracking once at the top - FileViewer + HtmlViewer: populate the three call sites
This commit is contained in:
parent
c16297f10c
commit
dc7791ef9d
8 changed files with 65 additions and 14 deletions
|
|
@ -4,6 +4,7 @@ import { APP_CHROME_FILE_ACTIONS_ID } from './AppChromeHeader';
|
|||
import {
|
||||
anonymizeArtifactId,
|
||||
artifactKindToTracking,
|
||||
type TrackingProjectKind,
|
||||
} from '@open-design/contracts/analytics';
|
||||
import { useAnalytics } from '../analytics/provider';
|
||||
import {
|
||||
|
|
@ -486,6 +487,7 @@ function setSlideStateCached(key: string, state: SlideState) {
|
|||
|
||||
interface Props {
|
||||
projectId: string;
|
||||
projectKind: TrackingProjectKind;
|
||||
file: ProjectFile;
|
||||
liveHtml?: string;
|
||||
isDeck?: boolean;
|
||||
|
|
@ -500,6 +502,7 @@ interface Props {
|
|||
|
||||
export function FileViewer({
|
||||
projectId,
|
||||
projectKind,
|
||||
file,
|
||||
liveHtml,
|
||||
isDeck,
|
||||
|
|
@ -536,13 +539,16 @@ export function FileViewer({
|
|||
rendererId: rendererMatch?.renderer.id ?? null,
|
||||
fileKind: file.kind ?? null,
|
||||
}),
|
||||
project_id: projectId,
|
||||
project_kind: projectKind,
|
||||
});
|
||||
}, [projectId, file.name, file.kind, rendererMatch?.renderer.id, analytics.track]);
|
||||
}, [projectId, projectKind, file.name, file.kind, rendererMatch?.renderer.id, analytics.track]);
|
||||
|
||||
if (rendererMatch?.renderer.id === 'html' || rendererMatch?.renderer.id === 'deck-html') {
|
||||
return (
|
||||
<HtmlViewer
|
||||
projectId={projectId}
|
||||
projectKind={projectKind}
|
||||
file={file}
|
||||
liveHtml={liveHtml}
|
||||
isDeck={rendererMatch.renderer.id === 'deck-html'}
|
||||
|
|
@ -3366,6 +3372,7 @@ function DocumentPreviewViewer({
|
|||
|
||||
function HtmlViewer({
|
||||
projectId,
|
||||
projectKind,
|
||||
file,
|
||||
liveHtml,
|
||||
isDeck,
|
||||
|
|
@ -3378,6 +3385,7 @@ function HtmlViewer({
|
|||
onFileSaved,
|
||||
}: {
|
||||
projectId: string;
|
||||
projectKind: TrackingProjectKind;
|
||||
file: ProjectFile;
|
||||
liveHtml?: string;
|
||||
isDeck: boolean;
|
||||
|
|
@ -3420,6 +3428,8 @@ function HtmlViewer({
|
|||
action: 'select_share_option',
|
||||
share_context: 'artifact',
|
||||
export_format: format,
|
||||
project_id: projectId,
|
||||
project_kind: projectKind,
|
||||
},
|
||||
{ requestId },
|
||||
);
|
||||
|
|
@ -3432,6 +3442,7 @@ function HtmlViewer({
|
|||
area: 'app_header',
|
||||
artifact_id: artifactId,
|
||||
project_id: projectId,
|
||||
project_kind: projectKind,
|
||||
export_format: format,
|
||||
result,
|
||||
...(errorCode ? { error_code: errorCode } : {}),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
useState,
|
||||
type DragEvent as ReactDragEvent,
|
||||
} from 'react';
|
||||
import type { TrackingProjectKind } from '@open-design/contracts/analytics';
|
||||
import { useT } from '../i18n';
|
||||
import { isMacPlatform } from '../utils/platform';
|
||||
import {
|
||||
|
|
@ -42,6 +43,7 @@ import {
|
|||
|
||||
interface Props {
|
||||
projectId: string;
|
||||
projectKind: TrackingProjectKind;
|
||||
files: ProjectFile[];
|
||||
liveArtifacts: LiveArtifactSummary[];
|
||||
onRefreshFiles: () => Promise<void> | void;
|
||||
|
|
@ -78,6 +80,7 @@ type TabDropEdge = 'before' | 'after';
|
|||
|
||||
export function FileWorkspace({
|
||||
projectId,
|
||||
projectKind,
|
||||
files,
|
||||
liveArtifacts,
|
||||
onRefreshFiles,
|
||||
|
|
@ -784,6 +787,7 @@ export function FileWorkspace({
|
|||
) : activeFile ? (
|
||||
<FileViewer
|
||||
projectId={projectId}
|
||||
projectKind={projectKind}
|
||||
file={activeFile}
|
||||
isDeck={isDeck}
|
||||
onExportAsPptx={onExportAsPptx}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import {
|
|||
type MemorySystemPromptResponse,
|
||||
type ResearchOptions,
|
||||
} from '@open-design/contracts';
|
||||
import { projectKindToTracking } from '@open-design/contracts/analytics';
|
||||
import { navigate } from '../router';
|
||||
import { agentDisplayName, agentModelDisplayName } from '../utils/agentLabels';
|
||||
import { isMacPlatform } from '../utils/platform';
|
||||
|
|
@ -2467,6 +2468,7 @@ export function ProjectView({
|
|||
) : null}
|
||||
<FileWorkspace
|
||||
projectId={project.id}
|
||||
projectKind={projectKindToTracking(project.metadata?.kind) ?? 'prototype'}
|
||||
files={projectFiles}
|
||||
liveArtifacts={liveArtifacts}
|
||||
onRefreshFiles={() => {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ describe('FileViewer Inspect/Picker empty-annotation hint (#890)', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={htmlFile()}
|
||||
liveHtml="<html><body><h1>Plain PRD with no data-od-id</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -107,6 +108,7 @@ describe('FileViewer Inspect/Picker empty-annotation hint (#890)', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={htmlFile()}
|
||||
liveHtml="<html><body><main data-od-id='hero'>Hero</main></body></html>"
|
||||
/>,
|
||||
|
|
@ -132,6 +134,7 @@ describe('FileViewer Inspect/Picker empty-annotation hint (#890)', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={htmlFile()}
|
||||
liveHtml="<html><body><h1>No annotations</h1></body></html>"
|
||||
/>,
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ describe('FileViewer JSON artifacts', () => {
|
|||
return new Response('', { status: 404 });
|
||||
}));
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('.lines')?.textContent).toBe(
|
||||
|
|
@ -113,7 +113,7 @@ describe('FileViewer JSON artifacts', () => {
|
|||
return new Response('', { status: 404 });
|
||||
}));
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const displayedText = container.querySelector('.lines')?.textContent ?? '';
|
||||
|
|
@ -139,7 +139,7 @@ describe('FileViewer JSON artifacts', () => {
|
|||
return new Response('', { status: 404 });
|
||||
}));
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const displayedText = container.querySelector('.lines')?.textContent ?? '';
|
||||
|
|
@ -165,7 +165,7 @@ describe('FileViewer JSON artifacts', () => {
|
|||
return new Response('', { status: 404 });
|
||||
}));
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const displayedText = container.querySelector('.lines')?.textContent ?? '';
|
||||
|
|
@ -191,7 +191,7 @@ describe('FileViewer JSON artifacts', () => {
|
|||
return new Response('', { status: 404 });
|
||||
}));
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const displayedText = container.querySelector('.lines')?.textContent ?? '';
|
||||
|
|
@ -218,7 +218,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const markup = renderToStaticMarkup(<FileViewer projectId="project-1" file={file} />);
|
||||
const markup = renderToStaticMarkup(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
expect(markup).toContain('class="viewer svg-viewer"');
|
||||
expect(markup).not.toContain('class="viewer image-viewer"');
|
||||
|
|
@ -230,7 +230,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
it('keeps normal image artifacts on the existing image viewer path', () => {
|
||||
const file = baseFile({ name: 'photo.png', path: 'photo.png' });
|
||||
|
||||
const markup = renderToStaticMarkup(<FileViewer projectId="project-1" file={file} />);
|
||||
const markup = renderToStaticMarkup(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
expect(markup).toContain('class="viewer image-viewer"');
|
||||
expect(markup).not.toContain('class="viewer svg-viewer"');
|
||||
|
|
@ -263,7 +263,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
}));
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('[data-testid="sketch-preview-svg"]')).toBeTruthy();
|
||||
|
|
@ -298,7 +298,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
}));
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const { container } = render(<FileViewer projectId="project-1" file={file} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={file} />);
|
||||
|
||||
await waitFor(() => {
|
||||
const svg = container.querySelector<SVGSVGElement>('[data-testid="sketch-preview-svg"] svg');
|
||||
|
|
@ -349,7 +349,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
});
|
||||
|
||||
const markup = renderToStaticMarkup(
|
||||
<FileViewer projectId="project-1" file={file} liveHtml="<html><body>hi</body></html>" />,
|
||||
<FileViewer projectId="project-1" projectKind="prototype" file={file} liveHtml="<html><body>hi</body></html>" />,
|
||||
);
|
||||
|
||||
expect(markup).toContain('data-testid="artifact-preview-frame"');
|
||||
|
|
@ -377,6 +377,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
const markup = renderToStaticMarkup(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
isDeck
|
||||
liveHtml={'<html><body><section class="slide">one</section></body></html>'}
|
||||
|
|
@ -407,6 +408,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
const markup = renderToStaticMarkup(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml={'<html><body><section class="slide">one</section><section class="slide">two</section></body></html>'}
|
||||
/>,
|
||||
|
|
@ -435,6 +437,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -517,6 +520,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -581,6 +585,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -709,6 +714,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -802,6 +808,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -851,6 +858,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -915,6 +923,7 @@ describe('FileViewer SVG artifacts', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={file}
|
||||
liveHtml="<html><body><h1>Hello</h1></body></html>"
|
||||
/>,
|
||||
|
|
@ -963,6 +972,7 @@ describe('FileViewer comment picker and tweaks mode', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={htmlPreviewFile()}
|
||||
liveHtml='<html><body><main data-od-id="hero">Hero</main></body></html>'
|
||||
/>,
|
||||
|
|
@ -988,6 +998,7 @@ describe('FileViewer comment picker and tweaks mode', () => {
|
|||
render(
|
||||
<FileViewer
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
file={htmlPreviewFile()}
|
||||
liveHtml='<html><body><main data-od-id="hero">Hero</main></body></html>'
|
||||
/>,
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ describe('FileWorkspace upload input', () => {
|
|||
const markup = renderToStaticMarkup(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -157,6 +158,7 @@ describe('FileWorkspace upload input', () => {
|
|||
render(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[baseFile()]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -214,6 +216,7 @@ describe('FileWorkspace upload input', () => {
|
|||
render(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[baseFile({ name: 'uploaded.png', path: 'uploaded.png' })]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -243,6 +246,7 @@ describe('FileWorkspace upload input', () => {
|
|||
const markup = renderToStaticMarkup(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -263,6 +267,7 @@ describe('FileWorkspace upload input', () => {
|
|||
const markup = renderToStaticMarkup(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -287,6 +292,7 @@ describe('FileWorkspace upload input', () => {
|
|||
const markup = renderToStaticMarkup(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -325,6 +331,7 @@ describe('FileWorkspace design file rename', () => {
|
|||
const container = renderWorkspace(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[workspaceFile('paste-1.txt'), workspaceFile('index.html')]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={onRefreshFiles}
|
||||
|
|
@ -387,6 +394,7 @@ describe('FileWorkspace design file rename', () => {
|
|||
const container = renderWorkspace(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[workspaceFile('paste-1.txt')]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -484,6 +492,7 @@ describe('FileWorkspace sketch round-trip', () => {
|
|||
render(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[
|
||||
baseFile({
|
||||
name: 'diagram.sketch.json',
|
||||
|
|
@ -577,6 +586,7 @@ describe('FileWorkspace sketch round-trip', () => {
|
|||
render(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[
|
||||
baseFile({
|
||||
name: 'diagram.sketch.json',
|
||||
|
|
@ -681,6 +691,7 @@ describe('FileWorkspace sketch round-trip', () => {
|
|||
render(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[
|
||||
baseFile({
|
||||
name: 'diagram.sketch.json',
|
||||
|
|
@ -749,6 +760,7 @@ describe('FileWorkspace tab reordering', () => {
|
|||
const container = renderWorkspace(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[
|
||||
workspaceFile('analysis.html'),
|
||||
workspaceFile('notes.md'),
|
||||
|
|
@ -788,6 +800,7 @@ describe('FileWorkspace tab reordering', () => {
|
|||
const container = renderWorkspace(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[
|
||||
workspaceFile('analysis.html'),
|
||||
workspaceFile('notes.md'),
|
||||
|
|
@ -826,6 +839,7 @@ describe('FileWorkspace tab reordering', () => {
|
|||
const container = renderWorkspace(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[workspaceFile('analysis.html'), workspaceFile('notes.md')]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
@ -854,6 +868,7 @@ describe('FileWorkspace tab reordering', () => {
|
|||
const container = renderWorkspace(
|
||||
<FileWorkspace
|
||||
projectId="project-1"
|
||||
projectKind="prototype"
|
||||
files={[workspaceFile('analysis.html'), workspaceFile('notes.md')]}
|
||||
liveArtifacts={[]}
|
||||
onRefreshFiles={vi.fn()}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ describe('FileViewer markdown code block copy', () => {
|
|||
});
|
||||
|
||||
it('copies fenced code blocks from the markdown preview', async () => {
|
||||
const { container } = render(<FileViewer projectId="project-1" file={baseFile()} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={baseFile()} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('.markdown-code-copy')).toBeTruthy();
|
||||
|
|
@ -97,7 +97,7 @@ describe('FileViewer markdown code block copy', () => {
|
|||
|
||||
it('copies empty fenced code blocks instead of treating the button as broken', async () => {
|
||||
mockedFetchProjectFileText.mockResolvedValue('```ts\n```');
|
||||
const { container } = render(<FileViewer projectId="project-1" file={baseFile()} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={baseFile()} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('.markdown-code-copy')).toBeTruthy();
|
||||
|
|
@ -117,7 +117,7 @@ describe('FileViewer markdown code block copy', () => {
|
|||
value: vi.fn().mockReturnValue(true),
|
||||
});
|
||||
const execCommandSpy = vi.mocked(document.execCommand);
|
||||
const { container } = render(<FileViewer projectId="project-1" file={baseFile()} />);
|
||||
const { container } = render(<FileViewer projectId="project-1" projectKind="prototype" file={baseFile()} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('.markdown-code-copy')).toBeTruthy();
|
||||
|
|
|
|||
|
|
@ -340,6 +340,8 @@ export interface StudioViewArtifactProps {
|
|||
// never the raw filename.
|
||||
artifact_id: string;
|
||||
artifact_kind: TrackingArtifactKind;
|
||||
project_id: string;
|
||||
project_kind: TrackingProjectKind;
|
||||
}
|
||||
|
||||
export interface StudioClickShareOptionProps {
|
||||
|
|
@ -350,6 +352,8 @@ export interface StudioClickShareOptionProps {
|
|||
action: 'select_share_option';
|
||||
share_context: 'artifact';
|
||||
export_format: TrackingExportFormat;
|
||||
project_id: string;
|
||||
project_kind: TrackingProjectKind;
|
||||
}
|
||||
|
||||
export interface ArtifactExportResultProps {
|
||||
|
|
@ -357,6 +361,7 @@ export interface ArtifactExportResultProps {
|
|||
area: 'app_header';
|
||||
artifact_id: string;
|
||||
project_id: string;
|
||||
project_kind: TrackingProjectKind;
|
||||
export_format: TrackingExportFormat;
|
||||
result: TrackingExportResult;
|
||||
error_code?: string;
|
||||
|
|
|
|||
Loading…
Reference in a new issue