@things-factory/integration-label-studio 9.1.19
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/CHANGELOG.md +85 -0
- package/EXTERNAL_DATA_SOURCING.md +484 -0
- package/IMPLEMENTATION_GUIDE.md +469 -0
- package/INTEGRATION.md +279 -0
- package/README.md +1014 -0
- package/SETUP_GUIDE.md +577 -0
- package/TEST_GUIDE.md +387 -0
- package/UI_CUSTOMIZATION.md +395 -0
- package/USER_SYNC_GUIDE.md +514 -0
- package/client/bootstrap.ts +1 -0
- package/client/index.ts +1 -0
- package/client/label-studio-label-page.ts +52 -0
- package/client/label-studio-project-create.ts +216 -0
- package/client/label-studio-project-list.ts +214 -0
- package/client/label-studio-wrapper.ts +294 -0
- package/client/route.ts +15 -0
- package/client/tsconfig.json +13 -0
- package/config/config.development.js +124 -0
- package/config/config.production.js +182 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/label-studio-label-page.d.ts +8 -0
- package/dist-client/label-studio-label-page.js +54 -0
- package/dist-client/label-studio-label-page.js.map +1 -0
- package/dist-client/label-studio-project-create.d.ts +16 -0
- package/dist-client/label-studio-project-create.js +235 -0
- package/dist-client/label-studio-project-create.js.map +1 -0
- package/dist-client/label-studio-project-list.d.ts +16 -0
- package/dist-client/label-studio-project-list.js +222 -0
- package/dist-client/label-studio-project-list.js.map +1 -0
- package/dist-client/label-studio-wrapper.d.ts +57 -0
- package/dist-client/label-studio-wrapper.js +304 -0
- package/dist-client/label-studio-wrapper.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +14 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/controller/label-studio-role-mapper.d.ts +35 -0
- package/dist-server/controller/label-studio-role-mapper.js +65 -0
- package/dist-server/controller/label-studio-role-mapper.js.map +1 -0
- package/dist-server/controller/user-provisioning-service.d.ts +66 -0
- package/dist-server/controller/user-provisioning-service.js +264 -0
- package/dist-server/controller/user-provisioning-service.js.map +1 -0
- package/dist-server/index.d.ts +7 -0
- package/dist-server/index.js +19 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/route/label-studio-sso.d.ts +2 -0
- package/dist-server/route/label-studio-sso.js +156 -0
- package/dist-server/route/label-studio-sso.js.map +1 -0
- package/dist-server/route/webhook.d.ts +65 -0
- package/dist-server/route/webhook.js +248 -0
- package/dist-server/route/webhook.js.map +1 -0
- package/dist-server/route.d.ts +1 -0
- package/dist-server/route.js +21 -0
- package/dist-server/route.js.map +1 -0
- package/dist-server/service/ai-prediction-service.d.ts +27 -0
- package/dist-server/service/ai-prediction-service.js +222 -0
- package/dist-server/service/ai-prediction-service.js.map +1 -0
- package/dist-server/service/dataset-labeling-integration.d.ts +44 -0
- package/dist-server/service/dataset-labeling-integration.js +512 -0
- package/dist-server/service/dataset-labeling-integration.js.map +1 -0
- package/dist-server/service/external-data-source-service.d.ts +78 -0
- package/dist-server/service/external-data-source-service.js +415 -0
- package/dist-server/service/external-data-source-service.js.map +1 -0
- package/dist-server/service/index.d.ts +12 -0
- package/dist-server/service/index.js +27 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/label-studio-sso-service.d.ts +38 -0
- package/dist-server/service/label-studio-sso-service.js +98 -0
- package/dist-server/service/label-studio-sso-service.js.map +1 -0
- package/dist-server/service/ml/ml-backend-service.d.ts +23 -0
- package/dist-server/service/ml/ml-backend-service.js +153 -0
- package/dist-server/service/ml/ml-backend-service.js.map +1 -0
- package/dist-server/service/prediction/prediction-management.d.ts +32 -0
- package/dist-server/service/prediction/prediction-management.js +299 -0
- package/dist-server/service/prediction/prediction-management.js.map +1 -0
- package/dist-server/service/project/project-management.d.ts +36 -0
- package/dist-server/service/project/project-management.js +309 -0
- package/dist-server/service/project/project-management.js.map +1 -0
- package/dist-server/service/task/task-management.d.ts +42 -0
- package/dist-server/service/task/task-management.js +372 -0
- package/dist-server/service/task/task-management.js.map +1 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.d.ts +28 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.js +111 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.js.map +1 -0
- package/dist-server/service/webhook/webhook-management.d.ts +21 -0
- package/dist-server/service/webhook/webhook-management.js +134 -0
- package/dist-server/service/webhook/webhook-management.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/dist-server/types/dataset-labeling-types.d.ts +71 -0
- package/dist-server/types/dataset-labeling-types.js +259 -0
- package/dist-server/types/dataset-labeling-types.js.map +1 -0
- package/dist-server/types/label-studio-types.d.ts +128 -0
- package/dist-server/types/label-studio-types.js +494 -0
- package/dist-server/types/label-studio-types.js.map +1 -0
- package/dist-server/types/prediction-types.d.ts +39 -0
- package/dist-server/types/prediction-types.js +121 -0
- package/dist-server/types/prediction-types.js.map +1 -0
- package/dist-server/utils/annotation-exporter.d.ts +104 -0
- package/dist-server/utils/annotation-exporter.js +261 -0
- package/dist-server/utils/annotation-exporter.js.map +1 -0
- package/dist-server/utils/label-config-builder.d.ts +117 -0
- package/dist-server/utils/label-config-builder.js +286 -0
- package/dist-server/utils/label-config-builder.js.map +1 -0
- package/dist-server/utils/label-studio-api-client.d.ts +180 -0
- package/dist-server/utils/label-studio-api-client.js +401 -0
- package/dist-server/utils/label-studio-api-client.js.map +1 -0
- package/dist-server/utils/media-url-extractor.d.ts +45 -0
- package/dist-server/utils/media-url-extractor.js +152 -0
- package/dist-server/utils/media-url-extractor.js.map +1 -0
- package/dist-server/utils/task-transformer.d.ts +108 -0
- package/dist-server/utils/task-transformer.js +260 -0
- package/dist-server/utils/task-transformer.js.map +1 -0
- package/package.json +47 -0
- package/server/SERVER_STRUCTURE.md +351 -0
- package/server/controller/label-studio-role-mapper.ts +76 -0
- package/server/controller/user-provisioning-service.ts +340 -0
- package/server/index.ts +19 -0
- package/server/route/label-studio-sso.ts +194 -0
- package/server/route/webhook.ts +304 -0
- package/server/route.ts +35 -0
- package/server/service/ai-prediction-service.ts +239 -0
- package/server/service/dataset-labeling-integration.ts +590 -0
- package/server/service/external-data-source-service.ts +438 -0
- package/server/service/index.ts +24 -0
- package/server/service/label-studio-sso-service.ts +108 -0
- package/server/service/labeling-scenario-service.ts.deprecated +566 -0
- package/server/service/ml/ml-backend-service.ts +127 -0
- package/server/service/prediction/prediction-management.ts +281 -0
- package/server/service/project/project-management.ts +284 -0
- package/server/service/task/task-management.ts +363 -0
- package/server/service/user-provisioning/user-sync-mutation.ts +80 -0
- package/server/service/webhook/webhook-management.ts +109 -0
- package/server/tsconfig.json +11 -0
- package/server/types/dataset-labeling-types.ts +181 -0
- package/server/types/global.d.ts +23 -0
- package/server/types/label-studio-types.ts +346 -0
- package/server/types/prediction-types.ts +86 -0
- package/server/types/scenario-types.ts.deprecated +362 -0
- package/server/utils/annotation-exporter.ts +340 -0
- package/server/utils/label-config-builder.ts +340 -0
- package/server/utils/label-studio-api-client.ts +487 -0
- package/server/utils/media-url-extractor.ts +193 -0
- package/server/utils/task-transformer.ts +342 -0
- package/test-ai-prediction.js +268 -0
- package/test-dataset-integration.js +449 -0
- package/test-simple.js +89 -0
- package/things-factory.config.js +12 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label Studio Wrapper Component for Things Factory
|
|
3
|
+
*
|
|
4
|
+
* This component embeds Label Studio within Things Factory using an iframe.
|
|
5
|
+
* It uses subdomain-based cookie sharing for SSO authentication, eliminating
|
|
6
|
+
* the need for proxying.
|
|
7
|
+
*
|
|
8
|
+
* ## Key Features:
|
|
9
|
+
* - Direct Label Studio access (no proxy needed)
|
|
10
|
+
* - Automatic SSO cookie setup via shared domain
|
|
11
|
+
* - Hidden header for seamless integration
|
|
12
|
+
* - Floating Action Buttons (FAB) for Reload and Fullscreen
|
|
13
|
+
*
|
|
14
|
+
* ## Architecture:
|
|
15
|
+
* 1. Client calls /label-studio/sso/setup
|
|
16
|
+
* 2. Backend sets cookie with shared domain (e.g., .nubison.localhost)
|
|
17
|
+
* 3. Browser → Label Studio (direct, with cookie)
|
|
18
|
+
*
|
|
19
|
+
* ## Configuration Requirements:
|
|
20
|
+
* - Label Studio and Things Factory must use subdomain pattern (e.g., label.example.com, app.example.com)
|
|
21
|
+
* - Label Studio .env must include:
|
|
22
|
+
* - CSRF_TRUSTED_ORIGINS: Include Things Factory frontend domain
|
|
23
|
+
* - ALLOWED_HOSTS: Include subdomain patterns
|
|
24
|
+
* - JWT_SSO_* settings for SSO authentication
|
|
25
|
+
* - Things Factory config must include:
|
|
26
|
+
* - labelStudio.serverUrl: Label Studio URL
|
|
27
|
+
* - labelStudio.cookieDomain: Shared cookie domain (e.g., .example.com)
|
|
28
|
+
*
|
|
29
|
+
* ## Usage:
|
|
30
|
+
* ```html
|
|
31
|
+
* <label-studio-wrapper></label-studio-wrapper>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* The component automatically:
|
|
35
|
+
* 1. Calls SSO setup endpoint to establish authentication
|
|
36
|
+
* 2. Builds iframe URL pointing directly to Label Studio
|
|
37
|
+
* 3. Adds ?hideHeader=true to hide Label Studio's header
|
|
38
|
+
* 4. Provides FAB buttons for reload and fullscreen
|
|
39
|
+
*/
|
|
40
|
+
import { css, html, LitElement } from 'lit'
|
|
41
|
+
import { customElement, state, query } from 'lit/decorators.js'
|
|
42
|
+
|
|
43
|
+
@customElement('label-studio-wrapper')
|
|
44
|
+
export class LabelStudioWrapper extends LitElement {
|
|
45
|
+
static styles = css`
|
|
46
|
+
:host {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
height: 100%;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.container {
|
|
54
|
+
flex: 1;
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
position: relative;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.iframe-container {
|
|
62
|
+
flex: 1;
|
|
63
|
+
position: relative;
|
|
64
|
+
overflow: hidden;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
iframe {
|
|
68
|
+
width: 100%;
|
|
69
|
+
height: 100%;
|
|
70
|
+
border: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.fab-container {
|
|
74
|
+
position: absolute;
|
|
75
|
+
bottom: 24px;
|
|
76
|
+
left: 24px;
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
gap: 12px;
|
|
80
|
+
z-index: 1000;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.fab-button {
|
|
84
|
+
width: 56px;
|
|
85
|
+
height: 56px;
|
|
86
|
+
border-radius: 16px;
|
|
87
|
+
background-color: var(--md-sys-color-primary-container);
|
|
88
|
+
color: var(--md-sys-color-on-primary-container);
|
|
89
|
+
border: none;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
95
|
+
transition: all 0.2s ease;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.fab-button:hover {
|
|
99
|
+
background-color: var(--md-sys-color-primary);
|
|
100
|
+
color: var(--md-sys-color-on-primary);
|
|
101
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
102
|
+
transform: translateY(-2px);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.fab-button md-icon {
|
|
106
|
+
font-size: 24px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.loading {
|
|
110
|
+
display: flex;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
align-items: center;
|
|
113
|
+
height: 100%;
|
|
114
|
+
font-size: 18px;
|
|
115
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.error {
|
|
119
|
+
display: flex;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
align-items: center;
|
|
122
|
+
height: 100%;
|
|
123
|
+
color: var(--md-sys-color-error);
|
|
124
|
+
flex-direction: column;
|
|
125
|
+
gap: 10px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
md-filled-button {
|
|
129
|
+
--md-filled-button-container-color: var(--md-sys-color-primary);
|
|
130
|
+
}
|
|
131
|
+
`
|
|
132
|
+
|
|
133
|
+
@state() private loading: boolean = true
|
|
134
|
+
@state() private error: string | null = null
|
|
135
|
+
@state() private iframeUrl: string = ''
|
|
136
|
+
@state() private path: string = ''
|
|
137
|
+
@state() private iframeLoaded: boolean = false
|
|
138
|
+
@state() private labelStudioUrl: string = ''
|
|
139
|
+
@query('iframe') private iframe!: HTMLIFrameElement
|
|
140
|
+
|
|
141
|
+
async updated(changes: any) {
|
|
142
|
+
if (changes.has('path') && this.path) {
|
|
143
|
+
await this.buildIframeUrl()
|
|
144
|
+
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
if (!this.iframeLoaded && !this.error && !this.loading) {
|
|
147
|
+
this.error = 'Failed to load Label Studio. The server may be unavailable.'
|
|
148
|
+
}
|
|
149
|
+
}, 15000)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async buildIframeUrl() {
|
|
154
|
+
try {
|
|
155
|
+
this.loading = true
|
|
156
|
+
this.error = null
|
|
157
|
+
|
|
158
|
+
// Step 1: Get Label Studio configuration
|
|
159
|
+
console.log('[Label Studio Wrapper] Fetching Label Studio configuration...')
|
|
160
|
+
|
|
161
|
+
const configResponse = await fetch('/label-studio/sso/config', {
|
|
162
|
+
method: 'GET',
|
|
163
|
+
credentials: 'include'
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
if (!configResponse.ok) {
|
|
167
|
+
throw new Error(`Failed to fetch Label Studio config: ${configResponse.status}`)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const configData = await configResponse.json()
|
|
171
|
+
this.labelStudioUrl = configData.labelStudioUrl
|
|
172
|
+
|
|
173
|
+
if (!this.labelStudioUrl || this.labelStudioUrl === 'not configured') {
|
|
174
|
+
throw new Error('Label Studio URL is not configured. Please check your settings.')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
console.log('[Label Studio Wrapper] Label Studio URL:', this.labelStudioUrl)
|
|
178
|
+
console.log('[Label Studio Wrapper] Cookie domain:', configData.cookieDomain)
|
|
179
|
+
|
|
180
|
+
// Step 2: Setup SSO token before loading iframe
|
|
181
|
+
console.log('[Label Studio Wrapper] Setting up SSO token...')
|
|
182
|
+
|
|
183
|
+
const ssoResponse = await fetch('/label-studio/sso/setup', {
|
|
184
|
+
method: 'GET',
|
|
185
|
+
credentials: 'include' // Include cookies in request
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
if (!ssoResponse.ok) {
|
|
189
|
+
const errorData = await ssoResponse.json().catch(() => ({}))
|
|
190
|
+
throw new Error(errorData.message || `SSO setup failed: ${ssoResponse.status}`)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const ssoData = await ssoResponse.json()
|
|
194
|
+
console.log('[Label Studio Wrapper] SSO setup complete:', ssoData.message)
|
|
195
|
+
|
|
196
|
+
// Step 3: Build iframe URL pointing directly to Label Studio
|
|
197
|
+
// No proxy needed - cookie is shared via domain
|
|
198
|
+
let url = this.labelStudioUrl + this.path
|
|
199
|
+
|
|
200
|
+
// Build query parameters
|
|
201
|
+
const params = new URLSearchParams()
|
|
202
|
+
|
|
203
|
+
// Hide header for seamless iframe embedding
|
|
204
|
+
params.set('hideHeader', 'true')
|
|
205
|
+
|
|
206
|
+
// Combine URL with parameters
|
|
207
|
+
const queryString = params.toString()
|
|
208
|
+
this.iframeUrl = queryString ? `${url}?${queryString}` : url
|
|
209
|
+
|
|
210
|
+
console.log('[Label Studio Wrapper] iframe URL:', this.iframeUrl)
|
|
211
|
+
} catch (err: any) {
|
|
212
|
+
console.error('[Label Studio Wrapper] Failed to build iframe URL:', err)
|
|
213
|
+
this.error = `Failed to initialize: ${err.message}`
|
|
214
|
+
} finally {
|
|
215
|
+
this.loading = false
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
handleIframeLoad() {
|
|
220
|
+
console.log('Label Studio iframe loaded successfully')
|
|
221
|
+
this.iframeLoaded = true
|
|
222
|
+
this.loading = false
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
handleIframeError() {
|
|
226
|
+
console.error('Label Studio iframe failed to load')
|
|
227
|
+
this.error = 'Failed to load Label Studio iframe. Please check the server connection.'
|
|
228
|
+
this.loading = false
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
handleReload() {
|
|
232
|
+
if (this.iframe) {
|
|
233
|
+
this.iframe.src = this.iframeUrl
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
handleFullscreen() {
|
|
238
|
+
if (this.iframe) {
|
|
239
|
+
if (this.iframe.requestFullscreen) {
|
|
240
|
+
this.iframe.requestFullscreen()
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
render() {
|
|
246
|
+
if (this.loading) {
|
|
247
|
+
return html`
|
|
248
|
+
<div class="loading">
|
|
249
|
+
<md-circular-progress indeterminate></md-circular-progress>
|
|
250
|
+
<span>Loading Label Studio...</span>
|
|
251
|
+
</div>
|
|
252
|
+
`
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (this.error) {
|
|
256
|
+
return html`
|
|
257
|
+
<div class="error">
|
|
258
|
+
<md-icon>error</md-icon>
|
|
259
|
+
<div>${this.error}</div>
|
|
260
|
+
<md-filled-button @click=${this.buildIframeUrl}>
|
|
261
|
+
<md-icon slot="icon">refresh</md-icon>
|
|
262
|
+
Retry
|
|
263
|
+
</md-filled-button>
|
|
264
|
+
</div>
|
|
265
|
+
`
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return html`
|
|
269
|
+
<div class="container">
|
|
270
|
+
<div class="iframe-container">
|
|
271
|
+
<iframe
|
|
272
|
+
src=${this.iframeUrl}
|
|
273
|
+
@load=${this.handleIframeLoad}
|
|
274
|
+
@error=${this.handleIframeError}
|
|
275
|
+
allow="fullscreen"
|
|
276
|
+
allow-same-origin
|
|
277
|
+
allow-scripts
|
|
278
|
+
allow-forms
|
|
279
|
+
allow-popups
|
|
280
|
+
allow-top-navigation
|
|
281
|
+
></iframe>
|
|
282
|
+
</div>
|
|
283
|
+
<div class="fab-container">
|
|
284
|
+
<button class="fab-button" @click=${this.handleReload} title="Reload">
|
|
285
|
+
<md-icon>refresh</md-icon>
|
|
286
|
+
</button>
|
|
287
|
+
<button class="fab-button" @click=${this.handleFullscreen} title="Fullscreen">
|
|
288
|
+
<md-icon>fullscreen</md-icon>
|
|
289
|
+
</button>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
`
|
|
293
|
+
}
|
|
294
|
+
}
|
package/client/route.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default function route(page: string) {
|
|
2
|
+
switch (page) {
|
|
3
|
+
case 'label-studio-project-list':
|
|
4
|
+
import('./label-studio-project-list.js')
|
|
5
|
+
return page
|
|
6
|
+
|
|
7
|
+
case 'label-studio-project-create':
|
|
8
|
+
import('./label-studio-project-create.js')
|
|
9
|
+
return page
|
|
10
|
+
|
|
11
|
+
case 'label-studio-label':
|
|
12
|
+
import('./label-studio-label-page.js')
|
|
13
|
+
return page
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig-base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"experimentalDecorators": true,
|
|
5
|
+
"skipLibCheck": true,
|
|
6
|
+
"strict": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"module": "esnext",
|
|
9
|
+
"outDir": "../dist-client",
|
|
10
|
+
"baseUrl": "./"
|
|
11
|
+
},
|
|
12
|
+
"include": ["./**/*"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// Label Studio Custom integration configuration for DEVELOPMENT
|
|
3
|
+
labelStudio: {
|
|
4
|
+
// Label Studio Custom server URL (subdomain approach recommended)
|
|
5
|
+
// Development: http://label.hatiolab.localhost:8080
|
|
6
|
+
// Production: https://label.example.com
|
|
7
|
+
serverUrl: process.env.LABEL_STUDIO_URL || 'http://label.hatiolab.localhost:8080',
|
|
8
|
+
|
|
9
|
+
// API Token for Label Studio (REQUIRED for user synchronization and API access)
|
|
10
|
+
// How to get:
|
|
11
|
+
// 1. Login to Label Studio with admin account
|
|
12
|
+
// 2. Go to Account Settings → Access Token
|
|
13
|
+
// 3. Click "Create new token"
|
|
14
|
+
// 4. Copy the generated token
|
|
15
|
+
apiToken: process.env.LABEL_STUDIO_API_TOKEN || '',
|
|
16
|
+
|
|
17
|
+
// Cookie domain for subdomain sharing (SSO)
|
|
18
|
+
// Development: .hatiolab.localhost
|
|
19
|
+
// Production: .example.com
|
|
20
|
+
// IMPORTANT: Must start with a dot (.) for subdomain sharing
|
|
21
|
+
cookieDomain: process.env.LABEL_STUDIO_COOKIE_DOMAIN || '.hatiolab.localhost',
|
|
22
|
+
|
|
23
|
+
// Label Studio UI interface elements to display
|
|
24
|
+
// Options: panel, controls, annotations:menu, side-column, predictions:menu
|
|
25
|
+
interfaces: 'panel,controls,annotations:menu'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Label Studio Custom (SSO Edition) - v1.20.0-sso.38
|
|
31
|
+
// ============================================================================
|
|
32
|
+
//
|
|
33
|
+
// This configuration is for Label Studio Custom Docker image with built-in SSO:
|
|
34
|
+
// ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38
|
|
35
|
+
//
|
|
36
|
+
// Features:
|
|
37
|
+
// - Native JWT SSO authentication (label-studio-sso v6.0.8 integrated)
|
|
38
|
+
// - JWT → Django Session conversion for performance
|
|
39
|
+
// - Automatic Organization assignment
|
|
40
|
+
// - Custom SSO Token API
|
|
41
|
+
// - iframe-friendly configuration
|
|
42
|
+
//
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Required Environment Variables
|
|
45
|
+
// ============================================================================
|
|
46
|
+
//
|
|
47
|
+
// Things-Factory (.env):
|
|
48
|
+
// LABEL_STUDIO_URL=http://label.hatiolab.localhost:8080
|
|
49
|
+
// LABEL_STUDIO_API_TOKEN=your-api-token-here
|
|
50
|
+
// LABEL_STUDIO_COOKIE_DOMAIN=.hatiolab.localhost
|
|
51
|
+
//
|
|
52
|
+
// Label Studio Custom (.env):
|
|
53
|
+
// # Database
|
|
54
|
+
// POSTGRES_HOST=postgres
|
|
55
|
+
// POSTGRES_DB=labelstudio
|
|
56
|
+
// POSTGRES_USER=postgres
|
|
57
|
+
// POSTGRES_PASSWORD=your-password
|
|
58
|
+
//
|
|
59
|
+
// # SSO Configuration
|
|
60
|
+
// JWT_SSO_NATIVE_USER_ID_CLAIM=user_id
|
|
61
|
+
// JWT_SSO_COOKIE_NAME=ls_auth_token
|
|
62
|
+
// JWT_SSO_TOKEN_PARAM=token
|
|
63
|
+
// SSO_TOKEN_EXPIRY=600
|
|
64
|
+
//
|
|
65
|
+
// # Cookie Domain (must match Things-Factory)
|
|
66
|
+
// SESSION_COOKIE_DOMAIN=.hatiolab.localhost
|
|
67
|
+
// CSRF_COOKIE_DOMAIN=.hatiolab.localhost
|
|
68
|
+
//
|
|
69
|
+
// # iframe Security Headers
|
|
70
|
+
// CSP_FRAME_ANCESTORS='self' http://localhost:3000 http://hatiolab.localhost:3000
|
|
71
|
+
//
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Docker Deployment
|
|
74
|
+
// ============================================================================
|
|
75
|
+
//
|
|
76
|
+
// docker-compose.yml:
|
|
77
|
+
//
|
|
78
|
+
// services:
|
|
79
|
+
// labelstudio:
|
|
80
|
+
// image: ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38
|
|
81
|
+
// environment:
|
|
82
|
+
// POSTGRES_HOST: postgres
|
|
83
|
+
// POSTGRES_DB: labelstudio
|
|
84
|
+
// SESSION_COOKIE_DOMAIN: .hatiolab.localhost
|
|
85
|
+
// CSRF_COOKIE_DOMAIN: .hatiolab.localhost
|
|
86
|
+
// CSP_FRAME_ANCESTORS: "'self' http://hatiolab.localhost:3000"
|
|
87
|
+
// ports:
|
|
88
|
+
// - "8080:8080"
|
|
89
|
+
//
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// User Synchronization
|
|
92
|
+
// ============================================================================
|
|
93
|
+
//
|
|
94
|
+
// Things-Factory users with 'label-studio' privileges will be synced to Label Studio:
|
|
95
|
+
//
|
|
96
|
+
// Privilege mapping:
|
|
97
|
+
// - user.owner === true + label-studio privilege → Admin (is_superuser=true)
|
|
98
|
+
// - label-studio privilege only → Staff (is_superuser=false)
|
|
99
|
+
// - No label-studio privilege → Inactive (is_active=false)
|
|
100
|
+
//
|
|
101
|
+
// GraphQL API:
|
|
102
|
+
// mutation { syncMyUserToLabelStudio { success email action } }
|
|
103
|
+
// mutation { syncAllUsersToLabelStudio { total created updated } }
|
|
104
|
+
//
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Security Checklist
|
|
107
|
+
// ============================================================================
|
|
108
|
+
//
|
|
109
|
+
// Development (HTTP):
|
|
110
|
+
// □ Label Studio Custom image v1.20.0-sso.32 running
|
|
111
|
+
// □ Cookie domain matches (.hatiolab.localhost)
|
|
112
|
+
// □ API token generated and configured
|
|
113
|
+
// □ CSP frame-ancestors includes Things-Factory URL
|
|
114
|
+
// □ Users synced with correct privileges
|
|
115
|
+
//
|
|
116
|
+
// Production (HTTPS):
|
|
117
|
+
// □ SESSION_COOKIE_SECURE=true (Label Studio)
|
|
118
|
+
// □ CSRF_COOKIE_SECURE=true (Label Studio)
|
|
119
|
+
// □ HTTPS URLs for both systems
|
|
120
|
+
// □ Cookie domain matches production domain (.example.com)
|
|
121
|
+
// □ JWT secret is strong (32+ characters)
|
|
122
|
+
// □ API token is kept secret
|
|
123
|
+
//
|
|
124
|
+
// ============================================================================
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// Label Studio Custom integration configuration for PRODUCTION
|
|
3
|
+
labelStudio: {
|
|
4
|
+
// Label Studio Custom server URL (HTTPS required for production)
|
|
5
|
+
// Production: https://label.example.com
|
|
6
|
+
serverUrl: process.env.LABEL_STUDIO_URL || '',
|
|
7
|
+
|
|
8
|
+
// API Token for Label Studio (REQUIRED for user synchronization and API access)
|
|
9
|
+
// How to get:
|
|
10
|
+
// 1. Login to Label Studio with admin account
|
|
11
|
+
// 2. Go to Account Settings → Access Token
|
|
12
|
+
// 3. Click "Create new token"
|
|
13
|
+
// 4. Copy the generated token
|
|
14
|
+
// IMPORTANT: Use environment variable in production
|
|
15
|
+
apiToken: process.env.LABEL_STUDIO_API_TOKEN || '',
|
|
16
|
+
|
|
17
|
+
// Cookie domain for subdomain sharing (SSO)
|
|
18
|
+
// Production: .example.com
|
|
19
|
+
// IMPORTANT: Must start with a dot (.) for subdomain sharing
|
|
20
|
+
cookieDomain: process.env.LABEL_STUDIO_COOKIE_DOMAIN || '',
|
|
21
|
+
|
|
22
|
+
// Label Studio UI interface elements to display
|
|
23
|
+
// Options: panel, controls, annotations:menu, side-column, predictions:menu
|
|
24
|
+
interfaces: 'panel,controls,annotations:menu'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Label Studio Custom (SSO Edition) - v1.20.0-sso.32 PRODUCTION
|
|
30
|
+
// ============================================================================
|
|
31
|
+
//
|
|
32
|
+
// This configuration is for Label Studio Custom Docker image with built-in SSO:
|
|
33
|
+
// ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38
|
|
34
|
+
//
|
|
35
|
+
// Features:
|
|
36
|
+
// - Native JWT SSO authentication (label-studio-sso v6.0.8 integrated)
|
|
37
|
+
// - JWT → Django Session conversion for performance
|
|
38
|
+
// - Automatic Organization assignment
|
|
39
|
+
// - Custom SSO Token API
|
|
40
|
+
// - iframe-friendly configuration
|
|
41
|
+
// - HTTPS production-ready deployment
|
|
42
|
+
//
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Required Environment Variables (PRODUCTION)
|
|
45
|
+
// ============================================================================
|
|
46
|
+
//
|
|
47
|
+
// Things-Factory (.env.production):
|
|
48
|
+
// LABEL_STUDIO_URL=https://label.example.com
|
|
49
|
+
// LABEL_STUDIO_API_TOKEN=your-api-token-here
|
|
50
|
+
// LABEL_STUDIO_COOKIE_DOMAIN=.example.com
|
|
51
|
+
//
|
|
52
|
+
// Label Studio Custom (.env):
|
|
53
|
+
// # Database (RDS/Aurora recommended)
|
|
54
|
+
// POSTGRES_HOST=your-db-endpoint.rds.amazonaws.com
|
|
55
|
+
// POSTGRES_DB=labelstudio
|
|
56
|
+
// POSTGRES_USER=postgres
|
|
57
|
+
// POSTGRES_PASSWORD=your-secure-password
|
|
58
|
+
//
|
|
59
|
+
// # SSO Configuration
|
|
60
|
+
// JWT_SSO_NATIVE_USER_ID_CLAIM=user_id
|
|
61
|
+
// JWT_SSO_COOKIE_NAME=ls_auth_token
|
|
62
|
+
// JWT_SSO_TOKEN_PARAM=token
|
|
63
|
+
// SSO_TOKEN_EXPIRY=600
|
|
64
|
+
//
|
|
65
|
+
// # Cookie Domain (must match Things-Factory)
|
|
66
|
+
// SESSION_COOKIE_DOMAIN=.example.com
|
|
67
|
+
// CSRF_COOKIE_DOMAIN=.example.com
|
|
68
|
+
//
|
|
69
|
+
// # ⚠️ HTTPS Cookie Security (REQUIRED for production)
|
|
70
|
+
// SESSION_COOKIE_SECURE=true
|
|
71
|
+
// CSRF_COOKIE_SECURE=true
|
|
72
|
+
//
|
|
73
|
+
// # iframe Security Headers
|
|
74
|
+
// CSP_FRAME_ANCESTORS='self' https://app.example.com https://console.example.com
|
|
75
|
+
//
|
|
76
|
+
// # Label Studio URL
|
|
77
|
+
// LABEL_STUDIO_HOST=https://label.example.com
|
|
78
|
+
//
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Docker Deployment (Production)
|
|
81
|
+
// ============================================================================
|
|
82
|
+
//
|
|
83
|
+
// docker-compose.production.yml:
|
|
84
|
+
//
|
|
85
|
+
// services:
|
|
86
|
+
// labelstudio:
|
|
87
|
+
// image: ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38
|
|
88
|
+
//
|
|
89
|
+
// environment:
|
|
90
|
+
// # Database
|
|
91
|
+
// POSTGRES_HOST: your-db-endpoint.rds.amazonaws.com
|
|
92
|
+
// POSTGRES_DB: labelstudio
|
|
93
|
+
// POSTGRES_USER: ${POSTGRES_USER}
|
|
94
|
+
// POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
95
|
+
//
|
|
96
|
+
// # SSO
|
|
97
|
+
// JWT_SSO_NATIVE_USER_ID_CLAIM: user_id
|
|
98
|
+
// JWT_SSO_COOKIE_NAME: ls_auth_token
|
|
99
|
+
// SSO_TOKEN_EXPIRY: 600
|
|
100
|
+
//
|
|
101
|
+
// # Cookie Domain
|
|
102
|
+
// SESSION_COOKIE_DOMAIN: .example.com
|
|
103
|
+
// CSRF_COOKIE_DOMAIN: .example.com
|
|
104
|
+
//
|
|
105
|
+
// # ⚠️ HTTPS Security (REQUIRED)
|
|
106
|
+
// SESSION_COOKIE_SECURE: "true"
|
|
107
|
+
// CSRF_COOKIE_SECURE: "true"
|
|
108
|
+
// LABEL_STUDIO_HOST: https://label.example.com
|
|
109
|
+
//
|
|
110
|
+
// # iframe Security
|
|
111
|
+
// CSP_FRAME_ANCESTORS: "'self' https://app.example.com"
|
|
112
|
+
//
|
|
113
|
+
// ports:
|
|
114
|
+
// - "8080:8080"
|
|
115
|
+
//
|
|
116
|
+
// # Health check
|
|
117
|
+
// healthcheck:
|
|
118
|
+
// test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
119
|
+
// interval: 30s
|
|
120
|
+
// timeout: 10s
|
|
121
|
+
// retries: 3
|
|
122
|
+
//
|
|
123
|
+
// ============================================================================
|
|
124
|
+
// Kubernetes Deployment (Production)
|
|
125
|
+
// ============================================================================
|
|
126
|
+
//
|
|
127
|
+
// See: /Users/super/Documents/GitHub/label-studio-custom/k8s/04-deployment.yaml
|
|
128
|
+
//
|
|
129
|
+
// Key configuration:
|
|
130
|
+
// - Image: ghcr.io/aidoop/label-studio-custom:1.20.0-sso.38
|
|
131
|
+
// - Replicas: 2+ (for high availability)
|
|
132
|
+
// - Health checks: /health endpoint
|
|
133
|
+
// - Ingress: ALB with HTTPS
|
|
134
|
+
// - Database: RDS Aurora PostgreSQL
|
|
135
|
+
//
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// User Synchronization
|
|
138
|
+
// ============================================================================
|
|
139
|
+
//
|
|
140
|
+
// Things-Factory users with 'label-studio' privileges will be synced to Label Studio:
|
|
141
|
+
//
|
|
142
|
+
// Privilege mapping:
|
|
143
|
+
// - user.owner === true + label-studio privilege → Admin (is_superuser=true)
|
|
144
|
+
// - label-studio privilege only → Staff (is_superuser=false)
|
|
145
|
+
// - No label-studio privilege → Inactive (is_active=false)
|
|
146
|
+
//
|
|
147
|
+
// GraphQL API:
|
|
148
|
+
// mutation { syncMyUserToLabelStudio { success email action } }
|
|
149
|
+
// mutation { syncAllUsersToLabelStudio { total created updated } }
|
|
150
|
+
//
|
|
151
|
+
// ============================================================================
|
|
152
|
+
// PRODUCTION Security Checklist
|
|
153
|
+
// ============================================================================
|
|
154
|
+
//
|
|
155
|
+
// Infrastructure:
|
|
156
|
+
// □ HTTPS enabled for both Things-Factory and Label Studio
|
|
157
|
+
// □ SSL certificates valid and auto-renewed
|
|
158
|
+
// □ Database (RDS) with encrypted storage
|
|
159
|
+
// □ VPC with private subnets for database
|
|
160
|
+
// □ Security groups restrict database access
|
|
161
|
+
//
|
|
162
|
+
// Label Studio Configuration:
|
|
163
|
+
// □ SESSION_COOKIE_SECURE=true
|
|
164
|
+
// □ CSRF_COOKIE_SECURE=true
|
|
165
|
+
// □ Cookie domain matches production (.example.com)
|
|
166
|
+
// □ CSP frame-ancestors restricts iframe embedding
|
|
167
|
+
// □ API token stored in secrets manager
|
|
168
|
+
// □ JWT secret is strong (32+ characters)
|
|
169
|
+
//
|
|
170
|
+
// Things-Factory Configuration:
|
|
171
|
+
// □ LABEL_STUDIO_URL uses HTTPS
|
|
172
|
+
// □ LABEL_STUDIO_API_TOKEN from secrets manager
|
|
173
|
+
// □ Cookie domain matches Label Studio
|
|
174
|
+
// □ CORS properly configured
|
|
175
|
+
//
|
|
176
|
+
// Monitoring:
|
|
177
|
+
// □ Health checks configured
|
|
178
|
+
// □ Application logs centralized
|
|
179
|
+
// □ Alert on service failures
|
|
180
|
+
// □ Database backup enabled
|
|
181
|
+
//
|
|
182
|
+
// ============================================================================
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function bootstrap(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,SAAS,KAAI,CAAC","sourcesContent":["export default function bootstrap() {}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './label-studio-wrapper.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA","sourcesContent":["export * from './label-studio-wrapper.js'\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import './label-studio-wrapper.js';
|
|
2
|
+
import { PageView } from '@things-factory/shell/client';
|
|
3
|
+
export declare class LabelStudioLabelPage extends PageView {
|
|
4
|
+
static styles: import("lit").CSSResult;
|
|
5
|
+
projectId: string;
|
|
6
|
+
pageUpdated(changes: any, lifecycle: any, changedBefore: any): Promise<void>;
|
|
7
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
8
|
+
}
|