@hed-hog/studio 0.0.285
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/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/studio.controller.d.ts +79 -0
- package/dist/studio.controller.d.ts.map +1 -0
- package/dist/studio.controller.js +186 -0
- package/dist/studio.controller.js.map +1 -0
- package/dist/studio.module.d.ts +3 -0
- package/dist/studio.module.d.ts.map +1 -0
- package/dist/studio.module.js +33 -0
- package/dist/studio.module.js.map +1 -0
- package/dist/studio.service.d.ts +76 -0
- package/dist/studio.service.d.ts.map +1 -0
- package/dist/studio.service.js +98 -0
- package/dist/studio.service.js.map +1 -0
- package/hedhog/data/menu.yaml +114 -0
- package/hedhog/data/role.yaml +7 -0
- package/hedhog/data/route.yaml +152 -0
- package/hedhog/data/setting_group.yaml +8 -0
- package/hedhog/frontend/app/_components/studio-status-badge.tsx.ejs +14 -0
- package/hedhog/frontend/app/_lib/mocks.ts.ejs +209 -0
- package/hedhog/frontend/app/_lib/status.ts.ejs +38 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +148 -0
- package/hedhog/frontend/app/assets/page.tsx.ejs +117 -0
- package/hedhog/frontend/app/editing/page.tsx.ejs +55 -0
- package/hedhog/frontend/app/incidents/page.tsx.ejs +59 -0
- package/hedhog/frontend/app/page.tsx.ejs +207 -0
- package/hedhog/frontend/app/projects/[id]/page.tsx.ejs +323 -0
- package/hedhog/frontend/app/projects/form/page.tsx.ejs +129 -0
- package/hedhog/frontend/app/projects/page.tsx.ejs +169 -0
- package/hedhog/frontend/app/publication/page.tsx.ejs +62 -0
- package/hedhog/frontend/app/scenes/form/page.tsx.ejs +110 -0
- package/hedhog/frontend/app/sessions/[id]/page.tsx.ejs +118 -0
- package/hedhog/frontend/app/sessions/form/page.tsx.ejs +103 -0
- package/hedhog/frontend/app/sessions/page.tsx.ejs +80 -0
- package/hedhog/frontend/app/storage-profiles/form/page.tsx.ejs +100 -0
- package/hedhog/frontend/app/storage-profiles/page.tsx.ejs +80 -0
- package/hedhog/frontend/app/takes/[id]/page.tsx.ejs +143 -0
- package/hedhog/frontend/app/takes/page.tsx.ejs +74 -0
- package/hedhog/table/capture_agent.yaml +48 -0
- package/hedhog/table/edit_composition.yaml +67 -0
- package/hedhog/table/edit_pipeline.yaml +46 -0
- package/hedhog/table/edit_stage_execution.yaml +46 -0
- package/hedhog/table/editor_delivery_package.yaml +63 -0
- package/hedhog/table/ingestion_job.yaml +74 -0
- package/hedhog/table/media_asset.yaml +130 -0
- package/hedhog/table/participant_command_ack.yaml +32 -0
- package/hedhog/table/participant_recording.yaml +67 -0
- package/hedhog/table/production_binding.yaml +34 -0
- package/hedhog/table/production_project.yaml +104 -0
- package/hedhog/table/publication_target.yaml +44 -0
- package/hedhog/table/recorded_file.yaml +74 -0
- package/hedhog/table/recording_command.yaml +72 -0
- package/hedhog/table/recording_incident.yaml +65 -0
- package/hedhog/table/recording_session.yaml +86 -0
- package/hedhog/table/scene.yaml +64 -0
- package/hedhog/table/scene_take.yaml +83 -0
- package/hedhog/table/session_participant.yaml +55 -0
- package/hedhog/table/storage_profile.yaml +75 -0
- package/hedhog/table/sync_marker.yaml +44 -0
- package/package.json +38 -0
- package/src/index.ts +4 -0
- package/src/language/en.json +8 -0
- package/src/language/pt.json +8 -0
- package/src/studio.controller.ts +94 -0
- package/src/studio.module.ts +20 -0
- package/src/studio.service.ts +102 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
- url: /studio/data
|
|
2
|
+
method: GET
|
|
3
|
+
relations:
|
|
4
|
+
role:
|
|
5
|
+
- where:
|
|
6
|
+
slug: admin
|
|
7
|
+
- where:
|
|
8
|
+
slug: admin-studio
|
|
9
|
+
|
|
10
|
+
- url: /studio/projects
|
|
11
|
+
method: GET
|
|
12
|
+
relations:
|
|
13
|
+
role:
|
|
14
|
+
- where:
|
|
15
|
+
slug: admin
|
|
16
|
+
- where:
|
|
17
|
+
slug: admin-studio
|
|
18
|
+
|
|
19
|
+
- url: /studio/projects/:id
|
|
20
|
+
method: GET
|
|
21
|
+
relations:
|
|
22
|
+
role:
|
|
23
|
+
- where:
|
|
24
|
+
slug: admin
|
|
25
|
+
- where:
|
|
26
|
+
slug: admin-studio
|
|
27
|
+
|
|
28
|
+
- url: /studio/projects/form
|
|
29
|
+
method: GET
|
|
30
|
+
relations:
|
|
31
|
+
role:
|
|
32
|
+
- where:
|
|
33
|
+
slug: admin
|
|
34
|
+
- where:
|
|
35
|
+
slug: admin-studio
|
|
36
|
+
|
|
37
|
+
- url: /studio/scenes
|
|
38
|
+
method: GET
|
|
39
|
+
relations:
|
|
40
|
+
role:
|
|
41
|
+
- where:
|
|
42
|
+
slug: admin
|
|
43
|
+
- where:
|
|
44
|
+
slug: admin-studio
|
|
45
|
+
|
|
46
|
+
- url: /studio/scenes/form
|
|
47
|
+
method: GET
|
|
48
|
+
relations:
|
|
49
|
+
role:
|
|
50
|
+
- where:
|
|
51
|
+
slug: admin
|
|
52
|
+
- where:
|
|
53
|
+
slug: admin-studio
|
|
54
|
+
|
|
55
|
+
- url: /studio/sessions
|
|
56
|
+
method: GET
|
|
57
|
+
relations:
|
|
58
|
+
role:
|
|
59
|
+
- where:
|
|
60
|
+
slug: admin
|
|
61
|
+
- where:
|
|
62
|
+
slug: admin-studio
|
|
63
|
+
|
|
64
|
+
- url: /studio/sessions/:id
|
|
65
|
+
method: GET
|
|
66
|
+
relations:
|
|
67
|
+
role:
|
|
68
|
+
- where:
|
|
69
|
+
slug: admin
|
|
70
|
+
- where:
|
|
71
|
+
slug: admin-studio
|
|
72
|
+
|
|
73
|
+
- url: /studio/sessions/form
|
|
74
|
+
method: GET
|
|
75
|
+
relations:
|
|
76
|
+
role:
|
|
77
|
+
- where:
|
|
78
|
+
slug: admin
|
|
79
|
+
- where:
|
|
80
|
+
slug: admin-studio
|
|
81
|
+
|
|
82
|
+
- url: /studio/takes
|
|
83
|
+
method: GET
|
|
84
|
+
relations:
|
|
85
|
+
role:
|
|
86
|
+
- where:
|
|
87
|
+
slug: admin
|
|
88
|
+
- where:
|
|
89
|
+
slug: admin-studio
|
|
90
|
+
|
|
91
|
+
- url: /studio/takes/:id
|
|
92
|
+
method: GET
|
|
93
|
+
relations:
|
|
94
|
+
role:
|
|
95
|
+
- where:
|
|
96
|
+
slug: admin
|
|
97
|
+
- where:
|
|
98
|
+
slug: admin-studio
|
|
99
|
+
|
|
100
|
+
- url: /studio/assets
|
|
101
|
+
method: GET
|
|
102
|
+
relations:
|
|
103
|
+
role:
|
|
104
|
+
- where:
|
|
105
|
+
slug: admin
|
|
106
|
+
- where:
|
|
107
|
+
slug: admin-studio
|
|
108
|
+
|
|
109
|
+
- url: /studio/storage-profiles
|
|
110
|
+
method: GET
|
|
111
|
+
relations:
|
|
112
|
+
role:
|
|
113
|
+
- where:
|
|
114
|
+
slug: admin
|
|
115
|
+
- where:
|
|
116
|
+
slug: admin-studio
|
|
117
|
+
|
|
118
|
+
- url: /studio/storage-profiles/form
|
|
119
|
+
method: GET
|
|
120
|
+
relations:
|
|
121
|
+
role:
|
|
122
|
+
- where:
|
|
123
|
+
slug: admin
|
|
124
|
+
- where:
|
|
125
|
+
slug: admin-studio
|
|
126
|
+
|
|
127
|
+
- url: /studio/incidents
|
|
128
|
+
method: GET
|
|
129
|
+
relations:
|
|
130
|
+
role:
|
|
131
|
+
- where:
|
|
132
|
+
slug: admin
|
|
133
|
+
- where:
|
|
134
|
+
slug: admin-studio
|
|
135
|
+
|
|
136
|
+
- url: /studio/editing
|
|
137
|
+
method: GET
|
|
138
|
+
relations:
|
|
139
|
+
role:
|
|
140
|
+
- where:
|
|
141
|
+
slug: admin
|
|
142
|
+
- where:
|
|
143
|
+
slug: admin-studio
|
|
144
|
+
|
|
145
|
+
- url: /studio/publication
|
|
146
|
+
method: GET
|
|
147
|
+
relations:
|
|
148
|
+
role:
|
|
149
|
+
- where:
|
|
150
|
+
slug: admin
|
|
151
|
+
- where:
|
|
152
|
+
slug: admin-studio
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Badge } from '@/components/ui/badge';
|
|
2
|
+
import { getStudioBadgeClass, toStudioLabel } from '../_lib/status';
|
|
3
|
+
|
|
4
|
+
type StudioStatusBadgeProps = {
|
|
5
|
+
value: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function StudioStatusBadge({ value }: StudioStatusBadgeProps) {
|
|
9
|
+
return (
|
|
10
|
+
<Badge variant="secondary" className={getStudioBadgeClass(value)}>
|
|
11
|
+
{toStudioLabel(value)}
|
|
12
|
+
</Badge>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PublicationTarget,
|
|
3
|
+
StorageProfile,
|
|
4
|
+
StudioAsset,
|
|
5
|
+
StudioIncident,
|
|
6
|
+
StudioProject,
|
|
7
|
+
StudioScene,
|
|
8
|
+
StudioSession,
|
|
9
|
+
StudioTake,
|
|
10
|
+
} from './types';
|
|
11
|
+
|
|
12
|
+
export const STUDIO_PROJECTS: StudioProject[] = [
|
|
13
|
+
{
|
|
14
|
+
id: 101,
|
|
15
|
+
title: 'LMS Aula 07 - API de Pagamentos',
|
|
16
|
+
projectType: 'course_lesson',
|
|
17
|
+
status: 'in_recording',
|
|
18
|
+
currentStage: 'recording',
|
|
19
|
+
binding: 'lms.lesson #4401',
|
|
20
|
+
owner: 'Ana Lima',
|
|
21
|
+
updatedAt: '2026-03-17T18:20:00Z',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 102,
|
|
25
|
+
title: 'Campanha Black Week - Teaser Vertical',
|
|
26
|
+
projectType: 'social_content',
|
|
27
|
+
status: 'in_editing',
|
|
28
|
+
currentStage: 'rough_cut',
|
|
29
|
+
binding: 'campaign #BW-2026',
|
|
30
|
+
owner: 'Bruno Costa',
|
|
31
|
+
updatedAt: '2026-03-17T17:03:00Z',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 103,
|
|
35
|
+
title: 'Video Institucional Produto Atlas',
|
|
36
|
+
projectType: 'standalone',
|
|
37
|
+
status: 'ready_to_publish',
|
|
38
|
+
currentStage: 'publication',
|
|
39
|
+
binding: 'external_reference ATLAS-VID',
|
|
40
|
+
owner: 'Camila Ramos',
|
|
41
|
+
updatedAt: '2026-03-16T14:31:00Z',
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export const STUDIO_SCENES: StudioScene[] = [
|
|
46
|
+
{
|
|
47
|
+
id: 1,
|
|
48
|
+
projectId: 101,
|
|
49
|
+
name: 'Intro do modulo',
|
|
50
|
+
status: 'recorded',
|
|
51
|
+
estimatedSeconds: 90,
|
|
52
|
+
takes: 3,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 2,
|
|
56
|
+
projectId: 101,
|
|
57
|
+
name: 'Demonstracao em tela',
|
|
58
|
+
status: 'ready_to_record',
|
|
59
|
+
estimatedSeconds: 420,
|
|
60
|
+
takes: 1,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 3,
|
|
64
|
+
projectId: 101,
|
|
65
|
+
name: 'Resumo final',
|
|
66
|
+
status: 'pending',
|
|
67
|
+
estimatedSeconds: 120,
|
|
68
|
+
takes: 0,
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
export const STUDIO_SESSIONS: StudioSession[] = [
|
|
73
|
+
{
|
|
74
|
+
id: 501,
|
|
75
|
+
projectId: 101,
|
|
76
|
+
title: 'Sessao principal - Aula 07',
|
|
77
|
+
status: 'recording',
|
|
78
|
+
sessionType: 'remote_collaborative',
|
|
79
|
+
host: 'Ana Lima',
|
|
80
|
+
participants: 4,
|
|
81
|
+
roomKey: 'studio-room-7a',
|
|
82
|
+
startedAt: '2026-03-17T18:00:00Z',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 502,
|
|
86
|
+
projectId: 102,
|
|
87
|
+
title: 'Sessao teaser vertical',
|
|
88
|
+
status: 'finished',
|
|
89
|
+
sessionType: 'hybrid',
|
|
90
|
+
host: 'Bruno Costa',
|
|
91
|
+
participants: 3,
|
|
92
|
+
roomKey: 'studio-room-bw',
|
|
93
|
+
startedAt: '2026-03-16T15:20:00Z',
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
export const STUDIO_TAKES: StudioTake[] = [
|
|
98
|
+
{
|
|
99
|
+
id: 9001,
|
|
100
|
+
projectId: 101,
|
|
101
|
+
sceneName: 'Intro do modulo',
|
|
102
|
+
sessionTitle: 'Sessao principal - Aula 07',
|
|
103
|
+
status: 'selected',
|
|
104
|
+
participants: 4,
|
|
105
|
+
expectedFiles: 12,
|
|
106
|
+
uploadedFiles: 12,
|
|
107
|
+
integrity: 'ok',
|
|
108
|
+
selected: true,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 9002,
|
|
112
|
+
projectId: 101,
|
|
113
|
+
sceneName: 'Demonstracao em tela',
|
|
114
|
+
sessionTitle: 'Sessao principal - Aula 07',
|
|
115
|
+
status: 'partial',
|
|
116
|
+
participants: 4,
|
|
117
|
+
expectedFiles: 12,
|
|
118
|
+
uploadedFiles: 9,
|
|
119
|
+
integrity: 'warning',
|
|
120
|
+
selected: false,
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
export const STUDIO_ASSETS: StudioAsset[] = [
|
|
125
|
+
{
|
|
126
|
+
id: 1,
|
|
127
|
+
participant: 'Ana Lima',
|
|
128
|
+
takeId: 9001,
|
|
129
|
+
sourceType: 'camera_video',
|
|
130
|
+
sizeMb: 650,
|
|
131
|
+
durationSec: 92,
|
|
132
|
+
storage: 'studio-main',
|
|
133
|
+
availability: 'available',
|
|
134
|
+
origin: 'uploaded_raw',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 2,
|
|
138
|
+
participant: 'Bruno Costa',
|
|
139
|
+
takeId: 9002,
|
|
140
|
+
sourceType: 'screen_capture',
|
|
141
|
+
sizeMb: 1200,
|
|
142
|
+
durationSec: 410,
|
|
143
|
+
storage: 'studio-main',
|
|
144
|
+
availability: 'pending',
|
|
145
|
+
origin: 'uploaded_raw',
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
export const STUDIO_STORAGE_PROFILES: StorageProfile[] = [
|
|
150
|
+
{
|
|
151
|
+
id: 1,
|
|
152
|
+
name: 'studio-main',
|
|
153
|
+
provider: 's3',
|
|
154
|
+
bucket: 'hedhog-studio-prod',
|
|
155
|
+
region: 'us-east-1',
|
|
156
|
+
basePath: 'studio/raw',
|
|
157
|
+
status: 'active',
|
|
158
|
+
testStatus: 'success',
|
|
159
|
+
lastTestedAt: '2026-03-17T12:20:00Z',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 2,
|
|
163
|
+
name: 'studio-proxy',
|
|
164
|
+
provider: 'r2',
|
|
165
|
+
bucket: 'hedhog-proxy',
|
|
166
|
+
region: 'auto',
|
|
167
|
+
basePath: 'studio/proxy',
|
|
168
|
+
status: 'active',
|
|
169
|
+
testStatus: 'unknown',
|
|
170
|
+
lastTestedAt: '2026-03-15T08:00:00Z',
|
|
171
|
+
},
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
export const STUDIO_INCIDENTS: StudioIncident[] = [
|
|
175
|
+
{
|
|
176
|
+
id: 1,
|
|
177
|
+
projectId: 101,
|
|
178
|
+
type: 'upload_failed',
|
|
179
|
+
severity: 'high',
|
|
180
|
+
target: 'take 9002 / participante Bruno',
|
|
181
|
+
status: 'open',
|
|
182
|
+
detectedAt: '2026-03-17T18:34:00Z',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 2,
|
|
186
|
+
projectId: 101,
|
|
187
|
+
type: 'delayed_start',
|
|
188
|
+
severity: 'medium',
|
|
189
|
+
target: 'sessao 501',
|
|
190
|
+
status: 'resolved',
|
|
191
|
+
detectedAt: '2026-03-17T18:02:00Z',
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
export const STUDIO_PUBLICATION_TARGETS: PublicationTarget[] = [
|
|
196
|
+
{
|
|
197
|
+
id: 1,
|
|
198
|
+
projectId: 103,
|
|
199
|
+
targetType: 'youtube',
|
|
200
|
+
status: 'scheduled',
|
|
201
|
+
scheduledAt: '2026-03-18T19:00:00Z',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 2,
|
|
205
|
+
projectId: 101,
|
|
206
|
+
targetType: 'lms',
|
|
207
|
+
status: 'pending',
|
|
208
|
+
},
|
|
209
|
+
];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const palette: Record<string, string> = {
|
|
2
|
+
draft: 'bg-slate-100 text-slate-700',
|
|
3
|
+
planned: 'bg-blue-100 text-blue-700',
|
|
4
|
+
in_recording: 'bg-orange-100 text-orange-700',
|
|
5
|
+
recorded: 'bg-emerald-100 text-emerald-700',
|
|
6
|
+
in_editing: 'bg-violet-100 text-violet-700',
|
|
7
|
+
in_finalization: 'bg-indigo-100 text-indigo-700',
|
|
8
|
+
ready_to_publish: 'bg-cyan-100 text-cyan-700',
|
|
9
|
+
published: 'bg-green-100 text-green-700',
|
|
10
|
+
archived: 'bg-gray-200 text-gray-700',
|
|
11
|
+
cancelled: 'bg-rose-100 text-rose-700',
|
|
12
|
+
pending: 'bg-amber-100 text-amber-700',
|
|
13
|
+
approved: 'bg-green-100 text-green-700',
|
|
14
|
+
selected: 'bg-lime-100 text-lime-700',
|
|
15
|
+
failed: 'bg-red-100 text-red-700',
|
|
16
|
+
recording: 'bg-orange-100 text-orange-700',
|
|
17
|
+
processing: 'bg-blue-100 text-blue-700',
|
|
18
|
+
ready: 'bg-teal-100 text-teal-700',
|
|
19
|
+
finished: 'bg-green-100 text-green-700',
|
|
20
|
+
idle: 'bg-zinc-100 text-zinc-700',
|
|
21
|
+
low: 'bg-sky-100 text-sky-700',
|
|
22
|
+
medium: 'bg-yellow-100 text-yellow-700',
|
|
23
|
+
high: 'bg-orange-100 text-orange-700',
|
|
24
|
+
critical: 'bg-red-100 text-red-700',
|
|
25
|
+
available: 'bg-green-100 text-green-700',
|
|
26
|
+
open: 'bg-red-100 text-red-700',
|
|
27
|
+
resolved: 'bg-green-100 text-green-700',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function getStudioBadgeClass(value: string) {
|
|
31
|
+
return palette[value] || 'bg-slate-100 text-slate-700';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function toStudioLabel(value: string) {
|
|
35
|
+
return value
|
|
36
|
+
.replace(/_/g, ' ')
|
|
37
|
+
.replace(/\b\w/g, (match) => match.toUpperCase());
|
|
38
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
export type StudioProjectType =
|
|
2
|
+
| 'course_lesson'
|
|
3
|
+
| 'standalone'
|
|
4
|
+
| 'social_content'
|
|
5
|
+
| 'campaign_asset'
|
|
6
|
+
| 'other';
|
|
7
|
+
|
|
8
|
+
export type StudioProjectStatus =
|
|
9
|
+
| 'draft'
|
|
10
|
+
| 'planned'
|
|
11
|
+
| 'in_recording'
|
|
12
|
+
| 'recorded'
|
|
13
|
+
| 'in_editing'
|
|
14
|
+
| 'in_finalization'
|
|
15
|
+
| 'ready_to_publish'
|
|
16
|
+
| 'published'
|
|
17
|
+
| 'archived'
|
|
18
|
+
| 'cancelled';
|
|
19
|
+
|
|
20
|
+
export type StudioStage =
|
|
21
|
+
| 'preparation'
|
|
22
|
+
| 'recording'
|
|
23
|
+
| 'rough_cut'
|
|
24
|
+
| 'cleanup'
|
|
25
|
+
| 'finalization'
|
|
26
|
+
| 'publication';
|
|
27
|
+
|
|
28
|
+
export type SceneStatus =
|
|
29
|
+
| 'pending'
|
|
30
|
+
| 'ready_to_record'
|
|
31
|
+
| 'recording'
|
|
32
|
+
| 'recorded'
|
|
33
|
+
| 'approved_for_edit'
|
|
34
|
+
| 'edited'
|
|
35
|
+
| 'archived';
|
|
36
|
+
|
|
37
|
+
export type SessionStatus =
|
|
38
|
+
| 'idle'
|
|
39
|
+
| 'arming'
|
|
40
|
+
| 'ready'
|
|
41
|
+
| 'start_requested'
|
|
42
|
+
| 'recording'
|
|
43
|
+
| 'stop_requested'
|
|
44
|
+
| 'processing'
|
|
45
|
+
| 'finished'
|
|
46
|
+
| 'cancelled';
|
|
47
|
+
|
|
48
|
+
export type TakeStatus =
|
|
49
|
+
| 'pending'
|
|
50
|
+
| 'armed'
|
|
51
|
+
| 'recording'
|
|
52
|
+
| 'stopped'
|
|
53
|
+
| 'uploaded'
|
|
54
|
+
| 'validated'
|
|
55
|
+
| 'partial'
|
|
56
|
+
| 'approved'
|
|
57
|
+
| 'discarded'
|
|
58
|
+
| 'selected';
|
|
59
|
+
|
|
60
|
+
export type Severity = 'low' | 'medium' | 'high' | 'critical';
|
|
61
|
+
|
|
62
|
+
export interface StudioProject {
|
|
63
|
+
id: number;
|
|
64
|
+
title: string;
|
|
65
|
+
projectType: StudioProjectType;
|
|
66
|
+
status: StudioProjectStatus;
|
|
67
|
+
currentStage: StudioStage;
|
|
68
|
+
binding: string;
|
|
69
|
+
owner: string;
|
|
70
|
+
updatedAt: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface StudioScene {
|
|
74
|
+
id: number;
|
|
75
|
+
projectId: number;
|
|
76
|
+
name: string;
|
|
77
|
+
status: SceneStatus;
|
|
78
|
+
estimatedSeconds: number;
|
|
79
|
+
takes: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface StudioSession {
|
|
83
|
+
id: number;
|
|
84
|
+
projectId: number;
|
|
85
|
+
title: string;
|
|
86
|
+
status: SessionStatus;
|
|
87
|
+
sessionType: 'local' | 'remote_collaborative' | 'hybrid';
|
|
88
|
+
host: string;
|
|
89
|
+
participants: number;
|
|
90
|
+
roomKey: string;
|
|
91
|
+
startedAt: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface StudioTake {
|
|
95
|
+
id: number;
|
|
96
|
+
projectId: number;
|
|
97
|
+
sceneName: string;
|
|
98
|
+
sessionTitle: string;
|
|
99
|
+
status: TakeStatus;
|
|
100
|
+
participants: number;
|
|
101
|
+
expectedFiles: number;
|
|
102
|
+
uploadedFiles: number;
|
|
103
|
+
integrity: 'ok' | 'warning' | 'corrupted';
|
|
104
|
+
selected: boolean;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface StudioAsset {
|
|
108
|
+
id: number;
|
|
109
|
+
participant: string;
|
|
110
|
+
takeId: number;
|
|
111
|
+
sourceType: string;
|
|
112
|
+
sizeMb: number;
|
|
113
|
+
durationSec: number;
|
|
114
|
+
storage: string;
|
|
115
|
+
availability: 'pending' | 'available' | 'archived' | 'failed';
|
|
116
|
+
origin: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface StorageProfile {
|
|
120
|
+
id: number;
|
|
121
|
+
name: string;
|
|
122
|
+
provider: 's3' | 'minio' | 'r2' | 'compatible_s3';
|
|
123
|
+
bucket: string;
|
|
124
|
+
region: string;
|
|
125
|
+
basePath: string;
|
|
126
|
+
status: 'active' | 'inactive';
|
|
127
|
+
testStatus: 'unknown' | 'success' | 'failed';
|
|
128
|
+
lastTestedAt: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface StudioIncident {
|
|
132
|
+
id: number;
|
|
133
|
+
projectId: number;
|
|
134
|
+
type: string;
|
|
135
|
+
severity: Severity;
|
|
136
|
+
target: string;
|
|
137
|
+
status: 'open' | 'resolved';
|
|
138
|
+
detectedAt: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface PublicationTarget {
|
|
142
|
+
id: number;
|
|
143
|
+
projectId: number;
|
|
144
|
+
targetType: string;
|
|
145
|
+
status: 'pending' | 'scheduled' | 'processing' | 'published' | 'failed';
|
|
146
|
+
scheduledAt?: string;
|
|
147
|
+
publishedUrl?: string;
|
|
148
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Page, PageHeader } from '@/components/entity-list';
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
5
|
+
import {
|
|
6
|
+
Table,
|
|
7
|
+
TableBody,
|
|
8
|
+
TableCell,
|
|
9
|
+
TableHead,
|
|
10
|
+
TableHeader,
|
|
11
|
+
TableRow,
|
|
12
|
+
} from '@/components/ui/table';
|
|
13
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
14
|
+
import { STUDIO_ASSETS } from '../_lib/mocks';
|
|
15
|
+
import { StudioStatusBadge } from '../_components/studio-status-badge';
|
|
16
|
+
|
|
17
|
+
export default function StudioAssetsPage() {
|
|
18
|
+
return (
|
|
19
|
+
<Page>
|
|
20
|
+
<PageHeader
|
|
21
|
+
title="Arquivos e Assets"
|
|
22
|
+
description="Catalogo tecnico com filtros de visualizacao"
|
|
23
|
+
breadcrumbs={[
|
|
24
|
+
{ label: 'Home', href: '/' },
|
|
25
|
+
{ label: 'Studio', href: '/studio' },
|
|
26
|
+
{ label: 'Assets' },
|
|
27
|
+
]}
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<Tabs defaultValue="table" className="space-y-4">
|
|
31
|
+
<TabsList>
|
|
32
|
+
<TabsTrigger value="table">Tabela</TabsTrigger>
|
|
33
|
+
<TabsTrigger value="participant">Por participante</TabsTrigger>
|
|
34
|
+
<TabsTrigger value="take">Por take</TabsTrigger>
|
|
35
|
+
</TabsList>
|
|
36
|
+
|
|
37
|
+
<TabsContent value="table">
|
|
38
|
+
<div className="rounded-md border">
|
|
39
|
+
<Table>
|
|
40
|
+
<TableHeader>
|
|
41
|
+
<TableRow>
|
|
42
|
+
<TableHead>Participante</TableHead>
|
|
43
|
+
<TableHead>Take</TableHead>
|
|
44
|
+
<TableHead>Tipo</TableHead>
|
|
45
|
+
<TableHead>Tamanho (MB)</TableHead>
|
|
46
|
+
<TableHead>Duracao (s)</TableHead>
|
|
47
|
+
<TableHead>Storage</TableHead>
|
|
48
|
+
<TableHead>Disponibilidade</TableHead>
|
|
49
|
+
<TableHead>Origem</TableHead>
|
|
50
|
+
</TableRow>
|
|
51
|
+
</TableHeader>
|
|
52
|
+
<TableBody>
|
|
53
|
+
{STUDIO_ASSETS.map((asset) => (
|
|
54
|
+
<TableRow key={asset.id}>
|
|
55
|
+
<TableCell>{asset.participant}</TableCell>
|
|
56
|
+
<TableCell>#{asset.takeId}</TableCell>
|
|
57
|
+
<TableCell>{asset.sourceType}</TableCell>
|
|
58
|
+
<TableCell>{asset.sizeMb}</TableCell>
|
|
59
|
+
<TableCell>{asset.durationSec}</TableCell>
|
|
60
|
+
<TableCell>{asset.storage}</TableCell>
|
|
61
|
+
<TableCell>
|
|
62
|
+
<StudioStatusBadge value={asset.availability} />
|
|
63
|
+
</TableCell>
|
|
64
|
+
<TableCell>{asset.origin}</TableCell>
|
|
65
|
+
</TableRow>
|
|
66
|
+
))}
|
|
67
|
+
</TableBody>
|
|
68
|
+
</Table>
|
|
69
|
+
</div>
|
|
70
|
+
</TabsContent>
|
|
71
|
+
|
|
72
|
+
<TabsContent value="participant" className="grid gap-4 md:grid-cols-2">
|
|
73
|
+
{[...new Set(STUDIO_ASSETS.map((item) => item.participant))].map(
|
|
74
|
+
(name) => (
|
|
75
|
+
<Card key={name}>
|
|
76
|
+
<CardHeader>
|
|
77
|
+
<CardTitle className="text-base">{name}</CardTitle>
|
|
78
|
+
</CardHeader>
|
|
79
|
+
<CardContent className="space-y-2 text-sm">
|
|
80
|
+
{STUDIO_ASSETS.filter(
|
|
81
|
+
(item) => item.participant === name
|
|
82
|
+
).map((item) => (
|
|
83
|
+
<div key={item.id} className="rounded-md border p-2">
|
|
84
|
+
#{item.takeId} • {item.sourceType} • {item.sizeMb}MB
|
|
85
|
+
</div>
|
|
86
|
+
))}
|
|
87
|
+
</CardContent>
|
|
88
|
+
</Card>
|
|
89
|
+
)
|
|
90
|
+
)}
|
|
91
|
+
</TabsContent>
|
|
92
|
+
|
|
93
|
+
<TabsContent value="take" className="grid gap-4 md:grid-cols-2">
|
|
94
|
+
{[...new Set(STUDIO_ASSETS.map((item) => item.takeId))].map(
|
|
95
|
+
(takeId) => (
|
|
96
|
+
<Card key={takeId}>
|
|
97
|
+
<CardHeader>
|
|
98
|
+
<CardTitle className="text-base">Take #{takeId}</CardTitle>
|
|
99
|
+
</CardHeader>
|
|
100
|
+
<CardContent className="space-y-2 text-sm">
|
|
101
|
+
{STUDIO_ASSETS.filter((item) => item.takeId === takeId).map(
|
|
102
|
+
(item) => (
|
|
103
|
+
<div key={item.id} className="rounded-md border p-2">
|
|
104
|
+
{item.participant} • {item.sourceType} •{' '}
|
|
105
|
+
{item.durationSec}s
|
|
106
|
+
</div>
|
|
107
|
+
)
|
|
108
|
+
)}
|
|
109
|
+
</CardContent>
|
|
110
|
+
</Card>
|
|
111
|
+
)
|
|
112
|
+
)}
|
|
113
|
+
</TabsContent>
|
|
114
|
+
</Tabs>
|
|
115
|
+
</Page>
|
|
116
|
+
);
|
|
117
|
+
}
|