qalita 2.3.2__py3-none-any.whl → 2.5.2__py3-none-any.whl

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.
Files changed (95) hide show
  1. qalita/__main__.py +213 -9
  2. qalita/commands/{agent.py → worker.py} +89 -89
  3. qalita/internal/config.py +26 -19
  4. qalita/internal/utils.py +1 -1
  5. qalita/web/app.py +97 -14
  6. qalita/web/blueprints/context.py +13 -60
  7. qalita/web/blueprints/dashboard.py +35 -76
  8. qalita/web/blueprints/helpers.py +154 -63
  9. qalita/web/blueprints/sources.py +29 -61
  10. qalita/web/blueprints/{agents.py → workers.py} +108 -185
  11. qalita-2.5.2.dist-info/METADATA +66 -0
  12. qalita-2.5.2.dist-info/RECORD +24 -0
  13. {qalita-2.3.2.dist-info → qalita-2.5.2.dist-info}/WHEEL +1 -1
  14. qalita-2.5.2.dist-info/entry_points.txt +2 -0
  15. qalita/web/blueprints/studio.py +0 -1294
  16. qalita/web/public/chatgpt.svg +0 -3
  17. qalita/web/public/claude.png +0 -0
  18. qalita/web/public/favicon.ico +0 -0
  19. qalita/web/public/gemini.png +0 -0
  20. qalita/web/public/logo-no-slogan.png +0 -0
  21. qalita/web/public/logo-white-no-slogan.svg +0 -11
  22. qalita/web/public/mistral.svg +0 -1
  23. qalita/web/public/noise.webp +0 -0
  24. qalita/web/public/ollama.png +0 -0
  25. qalita/web/public/platform.png +0 -0
  26. qalita/web/public/sources-logos/alloy-db.png +0 -0
  27. qalita/web/public/sources-logos/amazon-athena.png +0 -0
  28. qalita/web/public/sources-logos/amazon-rds.png +0 -0
  29. qalita/web/public/sources-logos/api.svg +0 -2
  30. qalita/web/public/sources-logos/avro.svg +0 -20
  31. qalita/web/public/sources-logos/azure-database-mysql.png +0 -0
  32. qalita/web/public/sources-logos/azure-database-postgresql.png +0 -0
  33. qalita/web/public/sources-logos/azure-sql-database.png +0 -0
  34. qalita/web/public/sources-logos/azure-sql-managed-instance.png +0 -0
  35. qalita/web/public/sources-logos/azure-synapse-analytics.png +0 -0
  36. qalita/web/public/sources-logos/azure_blob.svg +0 -1
  37. qalita/web/public/sources-logos/bigquery.png +0 -0
  38. qalita/web/public/sources-logos/cassandra.svg +0 -254
  39. qalita/web/public/sources-logos/clickhouse.png +0 -0
  40. qalita/web/public/sources-logos/cloud-sql.png +0 -0
  41. qalita/web/public/sources-logos/cockroach-db.png +0 -0
  42. qalita/web/public/sources-logos/csv.svg +0 -1
  43. qalita/web/public/sources-logos/database.svg +0 -3
  44. qalita/web/public/sources-logos/databricks.png +0 -0
  45. qalita/web/public/sources-logos/duckdb.png +0 -0
  46. qalita/web/public/sources-logos/elasticsearch.svg +0 -1
  47. qalita/web/public/sources-logos/excel.svg +0 -1
  48. qalita/web/public/sources-logos/file.svg +0 -1
  49. qalita/web/public/sources-logos/folder.svg +0 -6
  50. qalita/web/public/sources-logos/gcs.png +0 -0
  51. qalita/web/public/sources-logos/hdfs.svg +0 -1
  52. qalita/web/public/sources-logos/ibm-db2.png +0 -0
  53. qalita/web/public/sources-logos/json.png +0 -0
  54. qalita/web/public/sources-logos/maria-db.png +0 -0
  55. qalita/web/public/sources-logos/mongodb.svg +0 -1
  56. qalita/web/public/sources-logos/mssql.svg +0 -1
  57. qalita/web/public/sources-logos/mysql.svg +0 -7
  58. qalita/web/public/sources-logos/oracle.svg +0 -4
  59. qalita/web/public/sources-logos/parquet.svg +0 -16
  60. qalita/web/public/sources-logos/picture.png +0 -0
  61. qalita/web/public/sources-logos/postgresql.svg +0 -22
  62. qalita/web/public/sources-logos/questdb.png +0 -0
  63. qalita/web/public/sources-logos/redshift.png +0 -0
  64. qalita/web/public/sources-logos/s3.svg +0 -34
  65. qalita/web/public/sources-logos/sap-hana.png +0 -0
  66. qalita/web/public/sources-logos/sftp.png +0 -0
  67. qalita/web/public/sources-logos/single-store.png +0 -0
  68. qalita/web/public/sources-logos/snowflake.png +0 -0
  69. qalita/web/public/sources-logos/sqlite.svg +0 -104
  70. qalita/web/public/sources-logos/sqlserver.png +0 -0
  71. qalita/web/public/sources-logos/starburst.png +0 -0
  72. qalita/web/public/sources-logos/stream.png +0 -0
  73. qalita/web/public/sources-logos/teradata.png +0 -0
  74. qalita/web/public/sources-logos/timescale.png +0 -0
  75. qalita/web/public/sources-logos/xls.svg +0 -1
  76. qalita/web/public/sources-logos/xlsx.svg +0 -1
  77. qalita/web/public/sources-logos/yugabyte-db.png +0 -0
  78. qalita/web/public/studio-logo.svg +0 -10
  79. qalita/web/public/studio.css +0 -304
  80. qalita/web/public/studio.png +0 -0
  81. qalita/web/public/styles.css +0 -682
  82. qalita/web/templates/dashboard.html +0 -373
  83. qalita/web/templates/navbar.html +0 -40
  84. qalita/web/templates/sources/added.html +0 -57
  85. qalita/web/templates/sources/edit.html +0 -411
  86. qalita/web/templates/sources/select-source.html +0 -128
  87. qalita/web/templates/studio/agent-panel.html +0 -828
  88. qalita/web/templates/studio/context-panel.html +0 -300
  89. qalita/web/templates/studio/index.html +0 -79
  90. qalita/web/templates/studio/navbar.html +0 -14
  91. qalita/web/templates/studio/view-panel.html +0 -529
  92. qalita-2.3.2.dist-info/METADATA +0 -58
  93. qalita-2.3.2.dist-info/RECORD +0 -101
  94. qalita-2.3.2.dist-info/entry_points.txt +0 -3
  95. {qalita-2.3.2.dist-info → qalita-2.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,300 +0,0 @@
1
- <div id="context_panel_root" style="position:relative;">
2
- <div id="backend_status_dot" title="Checking backend..."
3
- style="position:absolute; top:10px; right:10px; width:10px; height:10px; border-radius:50%; background:#9ca3af; box-shadow:0 0 0 1px #e5e7eb;">
4
- </div>
5
- <div id="ctx_error" style="display:none; margin:0 0 8px 0; padding:8px 10px; border:1px solid #fecaca; background:#fef2f2; color:#b91c1c; border-radius:6px; font-size:12px;"></div>
6
- <div class="right" style="display:flex;align-items:center;gap:8px;">
7
- <p style="margin: 0px; min-width: 130px;">Platform Context</p>
8
- <select id="ctx_select" class="studio-input" style="margin-top: 0px; cursor:pointer;"></select>
9
- </div>
10
- <div id="projects_container"
11
- style="margin-top:10px; display:grid; grid-template-columns: repeat( auto-fit, minmax(200px, 1fr) ); gap:10px;">
12
- </div>
13
- <div id="issues_container"
14
- style="margin-top:10px; display:grid; grid-template-columns: repeat( auto-fit, minmax(200px, 1fr) ); gap:10px;">
15
- </div>
16
- <div id="setup_platform_card" class="studio-setup-card" style="display:none;">
17
- <div style="display:flex; align-items:flex-start; gap:10px;">
18
- <div>
19
- <div class="studio-setup-title">Setup platform</div>
20
- <div class="studio-setup-text">
21
- Your current context doesn't provide QALITA platform credentials.<br><br>
22
- To use contextual data quality metadata, configure your Platform endpoint and token.
23
- </div>
24
- <div class="studio-setup-actions">
25
- <a class="studio-setup-doc-btn" href="https://cloud.platform.qalita.io/signup" target="_blank"
26
- rel="noopener noreferrer">Create a free account</a>
27
- </div>
28
- <div class="studio-setup-actions">
29
- <a class="studio-setup-doc-btn outlined" href="https://doc.qalita.io/docs/studio" target="_blank"
30
- rel="noopener noreferrer">Open documentation</a>
31
- </div>
32
- </div>
33
- </div>
34
- </div>
35
- </div>
36
- <script>
37
- (function () {
38
- function setCtxError(msg) {
39
- try {
40
- var el = document.getElementById('ctx_error');
41
- if (!el) return;
42
- if (!msg) { el.style.display = 'none'; el.textContent = ''; return; }
43
- el.textContent = String(msg);
44
- el.style.display = 'block';
45
- } catch (e) { /* noop */ }
46
- }
47
- function showSetupCardIfNeeded(status) {
48
- try {
49
- var card = document.getElementById('setup_platform_card');
50
- if (!card) return;
51
- var configured = !!(status && status.configured);
52
- var endpointPresent = !!(status && status.endpoint_present);
53
- var tokenPresent = !!(status && status.token_present);
54
- // Show card if either endpoint or token is missing
55
- if (!endpointPresent || !tokenPresent) {
56
- card.style.display = 'block';
57
- } else {
58
- card.style.display = 'none';
59
- }
60
- } catch (e) { /* noop */ }
61
- }
62
- function checkBackend() {
63
- var dot = document.getElementById('backend_status_dot');
64
- if (dot) { dot.style.background = '#9ca3af'; dot.title = 'Checking backend...'; }
65
- // Use server-side proxy to avoid CORS and rely on current context
66
- fetch('/studio/check-backend')
67
- .then(function (r) { return r.json(); })
68
- .then(function (j) {
69
- var isOk = !!(j && j.ok);
70
- var url = (j && j.url) ? String(j.url) : '';
71
- var code = (j && j.status != null) ? String(j.status) : 'N/A';
72
- if (dot) { dot.style.background = isOk ? '#10b981' : '#ef4444'; dot.title = (isOk ? 'Backend reachable: ' : 'Backend not reachable: ') + (url || '(unknown)') + ' (HTTP ' + code + ')'; }
73
- setCtxError(isOk ? '' : ('Backend not reachable: ' + (url || '(unknown)') + ' (HTTP ' + code + ')'));
74
- showSetupCardIfNeeded(j || {});
75
- })
76
- .catch(function () { if (dot) { dot.style.background = '#ef4444'; dot.title = 'Backend check failed'; } setCtxError('Backend check failed'); });
77
- }
78
- function renderIssues(items) {
79
- var root = document.getElementById('issues_container');
80
- if (!root) return;
81
- root.innerHTML = '';
82
- if (!Array.isArray(items) || !items.length) {
83
- var e = document.createElement('div');
84
- e.className = 'muted';
85
- e.textContent = 'No issues';
86
- root.appendChild(e);
87
- return;
88
- }
89
- var params = new URLSearchParams(window.location.search);
90
- var selectedId = params.get('issue_id');
91
- items.forEach(function (it) {
92
- var id = String(it.id || it.issue_id || '');
93
- var title = it.title || it.name || ('Issue ' + id);
94
- var status = it.status || it.state || '';
95
- var card = document.createElement('div');
96
- card.className = 'card';
97
- card.style.cursor = 'pointer';
98
- card.style.padding = '8px 10px';
99
- card.style.border = '1px solid #e5e7eb';
100
- card.style.borderRadius = '8px';
101
- card.style.background = '#ffffff';
102
- card.innerHTML = '<div style="font-weight:600; color:#111827;">' + title + '</div>' +
103
- '<div class="muted" style="font-size:12px;">' + (status ? ('Status: ' + status) : '') + '</div>' +
104
- '<div class="muted" style="font-size:12px;">#' + id + '</div>';
105
- try {
106
- // Persist full issue object for agent context usage
107
- sessionStorage.setItem('studio_issue_' + id, JSON.stringify(it));
108
- } catch (e) { /* ignore */ }
109
- if (selectedId && id === selectedId) {
110
- card.style.boxShadow = '0 0 0 2px rgba(65,105,225,0.35)';
111
- }
112
- card.addEventListener('click', function () {
113
- var p = new URLSearchParams(window.location.search);
114
- var currentlySelected = (selectedId && selectedId === id);
115
- if (currentlySelected) { p.delete('issue_id'); }
116
- else { p.set('issue_id', id); }
117
- var newUrl = window.location.pathname + (p.toString() ? ('?' + p.toString()) : '');
118
- window.history.replaceState({}, '', newUrl);
119
- try { window.dispatchEvent(new Event('popstate')); } catch (e) { }
120
- try { if (!currentlySelected) { sessionStorage.setItem('studio_issue_' + id, JSON.stringify(it)); } } catch (e) { }
121
- // update highlight
122
- renderIssues(items);
123
- // ensure local conversations synced only on select
124
- if (!currentlySelected) {
125
- try { fetch('/studio/sync-conversations?issue_id=' + encodeURIComponent(id)).then(function () { /*noop*/ }).catch(function () { }); } catch (e) { }
126
- }
127
- });
128
- root.appendChild(card);
129
- });
130
- }
131
- function getProjectInitials(name) {
132
- try {
133
- if (!name) return '?';
134
- var parts = String(name).trim().split(/\s+/).filter(Boolean);
135
- var initials = parts.slice(0, 2).map(function (p) { return p[0]; }).join('').toUpperCase();
136
- return initials || '?';
137
- } catch (e) { return '?'; }
138
- }
139
- function renderProjects(items) {
140
- var root = document.getElementById('projects_container');
141
- if (!root) return;
142
- root.innerHTML = '';
143
- if (!Array.isArray(items) || !items.length) {
144
- var e = document.createElement('div');
145
- e.className = 'muted';
146
- e.textContent = 'No projects';
147
- root.appendChild(e);
148
- return;
149
- }
150
- var params = new URLSearchParams(window.location.search);
151
- var selectedId = params.get('project_id');
152
- items.forEach(function (it) {
153
- var id = String(it.id || it.project_id || it.uid || it.key || '');
154
- var title = it.name || it.title || it.key || ('Project ' + id);
155
- var description = it.description || '';
156
- var avatar = it.avatar || '';
157
- var initials = getProjectInitials(title);
158
- var avatarHtml = avatar
159
- ? '<img src="' + avatar + '" alt="' + initials + '" style="width:28px;height:28px;border-radius:50%;object-fit:cover;border:1px solid #e5e7eb;" />'
160
- : '<div style="width:28px;height:28px;border-radius:50%;background:#f3f4f6;color:#374151;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;border:1px solid #e5e7eb;">' + initials + '</div>';
161
- var card = document.createElement('div');
162
- card.className = 'card';
163
- card.style.cursor = 'pointer';
164
- card.style.padding = '8px 10px';
165
- card.style.border = '1px solid #e5e7eb';
166
- card.style.borderRadius = '8px';
167
- card.style.background = '#ffffff';
168
- card.innerHTML = '<div style="display:flex;align-items:center;gap:10px;">' +
169
- avatarHtml +
170
- '<div style="min-width:0;">' +
171
- '<div style="font-weight:600;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">' + title + '</div>' +
172
- (description ? '<div class="muted" style="font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">' + description + '</div>' : '') +
173
- '<div class="muted" style="font-size:12px;">#' + id + '</div>' +
174
- '</div>' +
175
- '</div>';
176
- try {
177
- sessionStorage.setItem('studio_project_' + id, JSON.stringify(it));
178
- } catch (e) { /* ignore */ }
179
- if (selectedId && id === selectedId) {
180
- card.style.boxShadow = '0 0 0 2px rgba(65,105,225,0.35)';
181
- }
182
- card.addEventListener('click', function () {
183
- var p = new URLSearchParams(window.location.search);
184
- var currentlySelected = (selectedId && selectedId === id);
185
- if (currentlySelected) { p.delete('project_id'); }
186
- else { p.set('project_id', id); }
187
- var newUrl = window.location.pathname + (p.toString()?('?' + p.toString()):'');
188
- window.history.replaceState({}, '', newUrl);
189
- try { window.dispatchEvent(new Event('popstate')); } catch(e){}
190
- try { if (!currentlySelected) { sessionStorage.setItem('studio_project_' + id, JSON.stringify(it)); } } catch (e) { }
191
- renderProjects(items);
192
- // Reload issues to reflect potential project scoping on server
193
- loadIssues();
194
- try { if (window.StudioViewPanel && typeof window.StudioViewPanel.reload === 'function') { window.StudioViewPanel.reload(); } } catch(e){}
195
- });
196
- root.appendChild(card);
197
- });
198
- }
199
- function loadIssues() {
200
- var projectId = '';
201
- try { projectId = new URLSearchParams(window.location.search).get('project_id') || ''; } catch (e) { projectId = ''; }
202
- var url = '/context/issues' + (projectId ? ('?project_id=' + encodeURIComponent(projectId)) : '');
203
- function extractIssueSourceId(it) {
204
- try {
205
- if (!it || typeof it !== 'object') return '';
206
- if (it.source_id != null) return String(it.source_id);
207
- if (it.sourceId != null) return String(it.sourceId);
208
- if (it.source && (it.source.id != null || it.source.source_id != null)) return String(it.source.id != null ? it.source.id : it.source.source_id);
209
- if (it.data && (it.data.source_id != null)) return String(it.data.source_id);
210
- } catch (e) { }
211
- return '';
212
- }
213
- function normalizeSourceIds(j) {
214
- try {
215
- var arr = [];
216
- if (!j) return arr;
217
- var root = (j.items != null ? j.items : (j.data != null ? j.data : (j.results != null ? j.results : j)));
218
- if (!Array.isArray(root)) root = [root];
219
- root.forEach(function (it) { if (it) { var id = String(it.id != null ? it.id : (it.source_id != null ? it.source_id : '')); if (id) arr.push(id); } });
220
- return arr;
221
- } catch (e) { return []; }
222
- }
223
- fetch(url)
224
- .then(function (r) { return r.json(); })
225
- .then(function (j) {
226
- var items = (j && j.ok) ? (j.items || []) : [];
227
- if (!j || !j.ok) { setCtxError((j && (j.message || j.error)) || 'Failed to load issues'); } else { setCtxError(''); }
228
- if (!projectId) { renderIssues(items); return; }
229
- // Client-side filter by project sources for robustness
230
- var srcUrl = '/studio/sources?project_id=' + encodeURIComponent(projectId);
231
- fetch(srcUrl)
232
- .then(function (r) { return r.json(); })
233
- .then(function (sj) {
234
- var sourceIds = normalizeSourceIds(sj);
235
- var set = {};
236
- sourceIds.forEach(function (id) { set[String(id)] = true; });
237
- var filtered = items.filter(function (it) { var sid = extractIssueSourceId(it); return sid && set[sid]; });
238
- renderIssues(filtered);
239
- })
240
- .catch(function () { setCtxError('Failed to load project sources'); renderIssues([]); });
241
- })
242
- .catch(function () { setCtxError('Failed to load issues'); renderIssues([]); });
243
- }
244
- function loadProjects() {
245
- function normalizeProjects(j) {
246
- try {
247
- if (!j) return [];
248
- if (Array.isArray(j)) return j;
249
- // Common wrappers
250
- if (Array.isArray(j.items)) return j.items;
251
- if (Array.isArray(j.data)) return j.data;
252
- if (Array.isArray(j.results)) return j.results;
253
- if (j.data && Array.isArray(j.data.items)) return j.data.items;
254
- if (j.projects && Array.isArray(j.projects)) return j.projects;
255
- // Single object cases
256
- if (j.items && typeof j.items === 'object') return [j.items];
257
- if (j.data && typeof j.data === 'object' && !Array.isArray(j.data)) return [j.data];
258
- if (typeof j === 'object' && (j.id != null || j.name != null)) return [j];
259
- } catch (e) { /* ignore */ }
260
- return [];
261
- }
262
- fetch('/studio/projects')
263
- .then(function (r) { return r.json(); })
264
- .then(function (j) {
265
- var items = normalizeProjects(j && (j.items != null ? j.items : j));
266
- if (!j) { setCtxError('Failed to load projects'); } else { setCtxError(''); }
267
- renderProjects(items);
268
- })
269
- .catch(function () { setCtxError('Failed to load projects'); renderProjects([]); });
270
- }
271
- function loadContexts() {
272
- fetch('/contexts').then(r => r.json()).then(j => {
273
- var sel = document.getElementById('ctx_select'); if (!sel) return;
274
- sel.innerHTML = '';
275
- var opt = document.createElement('option');
276
- opt.value = ''; opt.textContent = 'Default context'; sel.appendChild(opt);
277
- (j.items || []).forEach(function (it) {
278
- var o = document.createElement('option');
279
- o.value = it.path; o.textContent = it.name; sel.appendChild(o);
280
- });
281
- if (j.selected) { sel.value = j.selected; }
282
- }).catch(() => { });
283
- }
284
- function onSelect() {
285
- var sel = document.getElementById('ctx_select'); if (!sel) return;
286
- fetch('/context/select', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: sel.value }) })
287
- .then(() => { window.location.reload(); })
288
- .catch(() => { window.location.reload(); });
289
- }
290
- document.addEventListener('DOMContentLoaded', function () {
291
- loadContexts();
292
- var sel = document.getElementById('ctx_select'); if (sel) sel.addEventListener('change', onSelect);
293
- checkBackend();
294
- loadProjects();
295
- loadIssues();
296
- // On navigation (back/forward), re-render selection highlight
297
- window.addEventListener('popstate', function () { loadProjects(); loadIssues(); });
298
- });
299
- })();
300
- </script>
@@ -1,79 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="utf-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>QALITA Studio</title>
8
- <link rel="icon" href="/static/studio.png" />
9
- <link rel="stylesheet" href="/static/styles.css" />
10
- <link rel="stylesheet" href="/static/studio.css" />
11
- </head>
12
-
13
- <body class="studio" style="background-repeat: no-repeat;">
14
- {% include 'studio/navbar.html' %}
15
- <div class="studio-panels" id="studio_panels">
16
- <section class="panel" id="panel_context" style="flex: 0 0 18%; margin-top: 40px;">
17
- {% include 'studio/context-panel.html' %}
18
- </section>
19
- <div class="resizer" data-resizer="left-center"></div>
20
- <section class="panel" id="panel_view" style="flex: 0 0 49%;">
21
- {% include 'studio/view-panel.html' %}
22
- </section>
23
- <div class="resizer" data-resizer="center-right"></div>
24
- <section class="panel" id="panel_agent" style="display:flex; padding-right:20px; flex-direction:column; overflow:hidden; flex: 0 0 33%;">
25
- {% include 'studio/agent-panel.html' %}
26
- </section>
27
- </div>
28
-
29
- <script>
30
- (function () {
31
- const container = document.getElementById('studio_panels');
32
- if (!container) return;
33
- const panels = container.querySelectorAll('.panel');
34
- const resizers = container.querySelectorAll('.resizer');
35
-
36
- let active = null;
37
- let startX = 0;
38
- let startWidths = [];
39
-
40
- function onMouseDown(e) {
41
- active = e.target;
42
- startX = e.clientX;
43
- startWidths = Array.from(panels).map(p => p.getBoundingClientRect().width);
44
- container.classList.add('dragging');
45
- window.addEventListener('mousemove', onMouseMove);
46
- window.addEventListener('mouseup', onMouseUp);
47
- e.preventDefault();
48
- }
49
-
50
- function onMouseMove(e) {
51
- if (!active) return;
52
- const dx = e.clientX - startX;
53
- const min = 263;
54
- if (active.dataset.resizer === 'left-center') {
55
- let w0 = Math.max(min, startWidths[0] + dx);
56
- let w1 = Math.max(min, startWidths[1] - dx);
57
- panels[0].style.flex = '0 0 ' + w0 + 'px';
58
- panels[1].style.flex = '0 0 ' + w1 + 'px';
59
- } else if (active.dataset.resizer === 'center-right') {
60
- let w1 = Math.max(min, startWidths[1] + dx);
61
- let w2 = Math.max(min, startWidths[2] - dx);
62
- panels[1].style.flex = '0 0 ' + w1 + 'px';
63
- panels[2].style.flex = '0 0 ' + w2 + 'px';
64
- }
65
- }
66
-
67
- function onMouseUp() {
68
- container.classList.remove('dragging');
69
- window.removeEventListener('mousemove', onMouseMove);
70
- window.removeEventListener('mouseup', onMouseUp);
71
- active = null;
72
- }
73
-
74
- resizers.forEach(r => r.addEventListener('mousedown', onMouseDown));
75
- })();
76
- </script>
77
- </body>
78
-
79
- </html>
@@ -1,14 +0,0 @@
1
- <div class="topbar studio-navbar">
2
- <div class="brand" style="max-width:100%; padding: 6px 23px;">
3
- <div class="left">
4
- <a href="/" style="display:flex;align-items:flex-end;gap:5px;text-decoration:none;color:inherit;">
5
- <img src="/static/logo-white-no-slogan.svg" alt="Logo QALITA" width="25" height="25"
6
- style="height:25px;" />
7
- <span style="font-size: 20px; font-weight: 300; color: #ffffff;">Studio</span>
8
- <span class="badge"
9
- style="font-size: 10px; margin-bottom: 3px; background-color: #ffffff; color: #000000; border-radius: 4px; padding: 2px 8px;">Alpha
10
- 0</span>
11
- </a>
12
- </div>
13
- </div>
14
- </div>