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.
- qalita/__main__.py +213 -9
- qalita/commands/{agent.py → worker.py} +89 -89
- qalita/internal/config.py +26 -19
- qalita/internal/utils.py +1 -1
- qalita/web/app.py +97 -14
- qalita/web/blueprints/context.py +13 -60
- qalita/web/blueprints/dashboard.py +35 -76
- qalita/web/blueprints/helpers.py +154 -63
- qalita/web/blueprints/sources.py +29 -61
- qalita/web/blueprints/{agents.py → workers.py} +108 -185
- qalita-2.5.2.dist-info/METADATA +66 -0
- qalita-2.5.2.dist-info/RECORD +24 -0
- {qalita-2.3.2.dist-info → qalita-2.5.2.dist-info}/WHEEL +1 -1
- qalita-2.5.2.dist-info/entry_points.txt +2 -0
- qalita/web/blueprints/studio.py +0 -1294
- qalita/web/public/chatgpt.svg +0 -3
- qalita/web/public/claude.png +0 -0
- qalita/web/public/favicon.ico +0 -0
- qalita/web/public/gemini.png +0 -0
- qalita/web/public/logo-no-slogan.png +0 -0
- qalita/web/public/logo-white-no-slogan.svg +0 -11
- qalita/web/public/mistral.svg +0 -1
- qalita/web/public/noise.webp +0 -0
- qalita/web/public/ollama.png +0 -0
- qalita/web/public/platform.png +0 -0
- qalita/web/public/sources-logos/alloy-db.png +0 -0
- qalita/web/public/sources-logos/amazon-athena.png +0 -0
- qalita/web/public/sources-logos/amazon-rds.png +0 -0
- qalita/web/public/sources-logos/api.svg +0 -2
- qalita/web/public/sources-logos/avro.svg +0 -20
- qalita/web/public/sources-logos/azure-database-mysql.png +0 -0
- qalita/web/public/sources-logos/azure-database-postgresql.png +0 -0
- qalita/web/public/sources-logos/azure-sql-database.png +0 -0
- qalita/web/public/sources-logos/azure-sql-managed-instance.png +0 -0
- qalita/web/public/sources-logos/azure-synapse-analytics.png +0 -0
- qalita/web/public/sources-logos/azure_blob.svg +0 -1
- qalita/web/public/sources-logos/bigquery.png +0 -0
- qalita/web/public/sources-logos/cassandra.svg +0 -254
- qalita/web/public/sources-logos/clickhouse.png +0 -0
- qalita/web/public/sources-logos/cloud-sql.png +0 -0
- qalita/web/public/sources-logos/cockroach-db.png +0 -0
- qalita/web/public/sources-logos/csv.svg +0 -1
- qalita/web/public/sources-logos/database.svg +0 -3
- qalita/web/public/sources-logos/databricks.png +0 -0
- qalita/web/public/sources-logos/duckdb.png +0 -0
- qalita/web/public/sources-logos/elasticsearch.svg +0 -1
- qalita/web/public/sources-logos/excel.svg +0 -1
- qalita/web/public/sources-logos/file.svg +0 -1
- qalita/web/public/sources-logos/folder.svg +0 -6
- qalita/web/public/sources-logos/gcs.png +0 -0
- qalita/web/public/sources-logos/hdfs.svg +0 -1
- qalita/web/public/sources-logos/ibm-db2.png +0 -0
- qalita/web/public/sources-logos/json.png +0 -0
- qalita/web/public/sources-logos/maria-db.png +0 -0
- qalita/web/public/sources-logos/mongodb.svg +0 -1
- qalita/web/public/sources-logos/mssql.svg +0 -1
- qalita/web/public/sources-logos/mysql.svg +0 -7
- qalita/web/public/sources-logos/oracle.svg +0 -4
- qalita/web/public/sources-logos/parquet.svg +0 -16
- qalita/web/public/sources-logos/picture.png +0 -0
- qalita/web/public/sources-logos/postgresql.svg +0 -22
- qalita/web/public/sources-logos/questdb.png +0 -0
- qalita/web/public/sources-logos/redshift.png +0 -0
- qalita/web/public/sources-logos/s3.svg +0 -34
- qalita/web/public/sources-logos/sap-hana.png +0 -0
- qalita/web/public/sources-logos/sftp.png +0 -0
- qalita/web/public/sources-logos/single-store.png +0 -0
- qalita/web/public/sources-logos/snowflake.png +0 -0
- qalita/web/public/sources-logos/sqlite.svg +0 -104
- qalita/web/public/sources-logos/sqlserver.png +0 -0
- qalita/web/public/sources-logos/starburst.png +0 -0
- qalita/web/public/sources-logos/stream.png +0 -0
- qalita/web/public/sources-logos/teradata.png +0 -0
- qalita/web/public/sources-logos/timescale.png +0 -0
- qalita/web/public/sources-logos/xls.svg +0 -1
- qalita/web/public/sources-logos/xlsx.svg +0 -1
- qalita/web/public/sources-logos/yugabyte-db.png +0 -0
- qalita/web/public/studio-logo.svg +0 -10
- qalita/web/public/studio.css +0 -304
- qalita/web/public/studio.png +0 -0
- qalita/web/public/styles.css +0 -682
- qalita/web/templates/dashboard.html +0 -373
- qalita/web/templates/navbar.html +0 -40
- qalita/web/templates/sources/added.html +0 -57
- qalita/web/templates/sources/edit.html +0 -411
- qalita/web/templates/sources/select-source.html +0 -128
- qalita/web/templates/studio/agent-panel.html +0 -828
- qalita/web/templates/studio/context-panel.html +0 -300
- qalita/web/templates/studio/index.html +0 -79
- qalita/web/templates/studio/navbar.html +0 -14
- qalita/web/templates/studio/view-panel.html +0 -529
- qalita-2.3.2.dist-info/METADATA +0 -58
- qalita-2.3.2.dist-info/RECORD +0 -101
- qalita-2.3.2.dist-info/entry_points.txt +0 -3
- {qalita-2.3.2.dist-info → qalita-2.5.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,411 +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 CLI - {{ title }}</title>
|
|
8
|
-
<link rel="icon" href="/static/favicon.ico" />
|
|
9
|
-
<link rel="stylesheet" href="/static/styles.css" />
|
|
10
|
-
</head>
|
|
11
|
-
|
|
12
|
-
<body style="background-repeat: no-repeat;">
|
|
13
|
-
{% include 'navbar.html' %}
|
|
14
|
-
<div class="container-form">
|
|
15
|
-
<h1>{{ title }}</h1>
|
|
16
|
-
<div class="card">
|
|
17
|
-
{% if error %}
|
|
18
|
-
<div class="alert alert-error">{{ error }}</div>
|
|
19
|
-
{% endif %}
|
|
20
|
-
<div id="validate_result" class="alert alert-info hidden" style="margin-bottom:12px;"></div>
|
|
21
|
-
<form method="post">
|
|
22
|
-
<label style="margin-top: 0px;">Name
|
|
23
|
-
<input type="text" name="name" value="{{ (source.name if source) or '' }}" required />
|
|
24
|
-
</label>
|
|
25
|
-
<input type="hidden" name="original_name" value="{{ (source.name if source) or '' }}" />
|
|
26
|
-
<label>Description
|
|
27
|
-
<input type="text" name="description" value="{{ (source.description if source) or '' }}" />
|
|
28
|
-
</label>
|
|
29
|
-
|
|
30
|
-
<label>Type
|
|
31
|
-
<div class="type-field">
|
|
32
|
-
<img id="edit_type_icon" class="type-icon" src="/static/sources-logos/folder.svg" alt="type" />
|
|
33
|
-
<select name="type" id="edit_type" required>
|
|
34
|
-
{% for t in
|
|
35
|
-
['file','csv','excel','folder','postgresql','mysql','oracle','mssql','sqlite','mongodb','s3','gcs','azure_blob','hdfs']
|
|
36
|
-
%}
|
|
37
|
-
<option value="{{t}}" {% if (source and source.type==t) or (not source and preselected_type and preselected_type==t) %}selected{% endif %}>{{t}}</option>
|
|
38
|
-
{% endfor %}
|
|
39
|
-
</select>
|
|
40
|
-
</div>
|
|
41
|
-
</label>
|
|
42
|
-
|
|
43
|
-
<!-- Dynamic fields by type -->
|
|
44
|
-
<div id="edit_fields_file" class="edit-type-fields hidden">
|
|
45
|
-
<label>File path
|
|
46
|
-
<div class="row" style="grid-template-columns: 1fr auto; align-items: end;">
|
|
47
|
-
<input type="text" id="file_path" name="file_path" style="width: 100%;"
|
|
48
|
-
value="{{ (source.config.path if source and source.config) or '' }}" />
|
|
49
|
-
<button class="btn secondary" type="button" id="btn_browse_file">Browse…</button>
|
|
50
|
-
</div>
|
|
51
|
-
</label>
|
|
52
|
-
</div>
|
|
53
|
-
|
|
54
|
-
<div id="edit_fields_csv" class="edit-type-fields hidden">
|
|
55
|
-
<label>CSV file path
|
|
56
|
-
<div class="row" style="grid-template-columns: 1fr auto; align-items: end;">
|
|
57
|
-
<input type="text" id="csv_path" name="csv_path" style="width: 100%;"
|
|
58
|
-
value="{{ (source.config.path if source and source.config) or '' }}" />
|
|
59
|
-
<button class="btn secondary" type="button" id="btn_browse_csv">Browse…</button>
|
|
60
|
-
</div>
|
|
61
|
-
</label>
|
|
62
|
-
<div class="row">
|
|
63
|
-
<div><label>Delimiter<input type="text" name="csv_delimiter" value="," /></label></div>
|
|
64
|
-
<div><label>Encoding<input type="text" name="csv_encoding" value="utf-8" /></label></div>
|
|
65
|
-
</div>
|
|
66
|
-
<label><input type="checkbox" name="csv_header" checked /> Has header row</label>
|
|
67
|
-
</div>
|
|
68
|
-
|
|
69
|
-
<div id="edit_fields_excel" class="edit-type-fields hidden">
|
|
70
|
-
<label>Excel file path
|
|
71
|
-
<div class="row" style="grid-template-columns: 1fr auto; align-items: end;">
|
|
72
|
-
<input type="text" id="excel_path" name="excel_path" style="width: 100%;"
|
|
73
|
-
value="{{ (source.config.path if source and source.config) or '' }}" />
|
|
74
|
-
<button class="btn secondary" type="button" id="btn_browse_excel">Browse…</button>
|
|
75
|
-
</div>
|
|
76
|
-
</label>
|
|
77
|
-
<div class="row">
|
|
78
|
-
<div><label>Sheet name<input type="text" name="excel_sheet" value="" /></label></div>
|
|
79
|
-
<div><label>Header row index<input type="number" name="excel_header_row" value="1" /></label></div>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
|
|
83
|
-
<div id="edit_fields_folder" class="edit-type-fields hidden">
|
|
84
|
-
<label>Folder path
|
|
85
|
-
<div class="row" style="grid-template-columns: 1fr auto; align-items: end;">
|
|
86
|
-
<input type="text" id="folder_path" name="folder_path"
|
|
87
|
-
value="{{ (source.config.path if source and source.config) or '' }}" />
|
|
88
|
-
<button class="btn secondary" type="button" id="btn_browse_folder">Browse…</button>
|
|
89
|
-
</div>
|
|
90
|
-
</label>
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
<div id="edit_fields_sqlite" class="edit-type-fields hidden">
|
|
94
|
-
<label>SQLite file path
|
|
95
|
-
<div class="row" style="grid-template-columns: 1fr auto; align-items: end;">
|
|
96
|
-
<input type="text" id="sqlite_file_path" name="sqlite_file_path" style="width: 100%;"
|
|
97
|
-
value="{{ (source.config.file_path if source and source.config) or '' }}" />
|
|
98
|
-
<button class="btn secondary" type="button" id="btn_browse_sqlite">Browse…</button>
|
|
99
|
-
</div>
|
|
100
|
-
</label>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
<div id="edit_fields_db" class="edit-type-fields hidden">
|
|
104
|
-
<div class="row">
|
|
105
|
-
<div>
|
|
106
|
-
<label>Host<input type="text" name="db_host"
|
|
107
|
-
value="{{ (source.config.host if source and source.config) or '' }}" /></label>
|
|
108
|
-
</div>
|
|
109
|
-
<div>
|
|
110
|
-
<label>Port<input type="number" name="db_port"
|
|
111
|
-
value="{{ (source.config.port if source and source.config) or '' }}" /></label>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
<div class="row">
|
|
115
|
-
<div>
|
|
116
|
-
<label>Username<input type="text" name="db_username"
|
|
117
|
-
value="{{ (source.config.username if source and source.config) or '' }}" /></label>
|
|
118
|
-
</div>
|
|
119
|
-
<div>
|
|
120
|
-
<label>Password<input type="password" name="db_password"
|
|
121
|
-
value="{{ (source.config.password if source and source.config) or '' }}" /></label>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
<label>Database
|
|
125
|
-
<input type="text" name="db_database"
|
|
126
|
-
value="{{ (source.config.database if source and source.config) or '' }}" />
|
|
127
|
-
</label>
|
|
128
|
-
<label id="db_schema_field" class="hidden">Schema (PostgreSQL/Oracle)
|
|
129
|
-
<input type="text" name="db_schema"
|
|
130
|
-
value="{{ (source.config.schema if source and source.config) or '' }}" />
|
|
131
|
-
</label>
|
|
132
|
-
<label>Tables or SQL (default '*')
|
|
133
|
-
<input type="text" name="db_table_or_query"
|
|
134
|
-
value="{{ (source.config.table_or_query if source and source.config) or '*' }}" />
|
|
135
|
-
</label>
|
|
136
|
-
</div>
|
|
137
|
-
|
|
138
|
-
<div id="edit_fields_mongodb" class="edit-type-fields hidden">
|
|
139
|
-
<div class="row">
|
|
140
|
-
<div>
|
|
141
|
-
<label>Host<input type="text" name="mongo_host"
|
|
142
|
-
value="{{ (source.config.host if source and source.config) or '' }}" /></label>
|
|
143
|
-
</div>
|
|
144
|
-
<div>
|
|
145
|
-
<label>Port<input type="number" name="mongo_port"
|
|
146
|
-
value="{{ (source.config.port if source and source.config) or '' }}" /></label>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
<div class="row">
|
|
150
|
-
<div>
|
|
151
|
-
<label>Username<input type="text" name="mongo_username"
|
|
152
|
-
value="{{ (source.config.username if source and source.config) or '' }}" /></label>
|
|
153
|
-
</div>
|
|
154
|
-
<div>
|
|
155
|
-
<label>Password<input type="password" name="mongo_password"
|
|
156
|
-
value="{{ (source.config.password if source and source.config) or '' }}" /></label>
|
|
157
|
-
</div>
|
|
158
|
-
</div>
|
|
159
|
-
<label>Database<input type="text" name="mongo_database"
|
|
160
|
-
value="{{ (source.config.database if source and source.config) or '' }}" /></label>
|
|
161
|
-
</div>
|
|
162
|
-
|
|
163
|
-
<div id="edit_fields_s3" class="edit-type-fields hidden">
|
|
164
|
-
<label>Bucket<input type="text" name="s3_bucket"
|
|
165
|
-
value="{{ (source.config.bucket if source and source.config) or '' }}" /></label>
|
|
166
|
-
<label>Prefix<input type="text" name="s3_prefix"
|
|
167
|
-
value="{{ (source.config.prefix if source and source.config) or '' }}" /></label>
|
|
168
|
-
<div class="row">
|
|
169
|
-
<div><label>Access key<input type="text" name="s3_access_key"
|
|
170
|
-
value="{{ (source.config.access_key if source and source.config) or '' }}" /></label></div>
|
|
171
|
-
<div><label>Secret key<input type="password" name="s3_secret_key"
|
|
172
|
-
value="{{ (source.config.secret_key if source and source.config) or '' }}" /></label></div>
|
|
173
|
-
</div>
|
|
174
|
-
<label>Region<input type="text" name="s3_region"
|
|
175
|
-
value="{{ (source.config.region if source and source.config) or '' }}" /></label>
|
|
176
|
-
</div>
|
|
177
|
-
|
|
178
|
-
<div id="edit_fields_gcs" class="edit-type-fields hidden">
|
|
179
|
-
<label>Bucket<input type="text" name="gcs_bucket"
|
|
180
|
-
value="{{ (source.config.bucket if source and source.config) or '' }}" /></label>
|
|
181
|
-
<label>Prefix<input type="text" name="gcs_prefix"
|
|
182
|
-
value="{{ (source.config.prefix if source and source.config) or '' }}" /></label>
|
|
183
|
-
<label>Credentials JSON path<input type="text" name="gcs_credentials"
|
|
184
|
-
value="{{ (source.config.credentials_json if source and source.config) or '' }}" /></label>
|
|
185
|
-
</div>
|
|
186
|
-
|
|
187
|
-
<div id="edit_fields_azure" class="edit-type-fields hidden">
|
|
188
|
-
<label>Container<input type="text" name="az_container"
|
|
189
|
-
value="{{ (source.config.container if source and source.config) or '' }}" /></label>
|
|
190
|
-
<label>Prefix<input type="text" name="az_prefix"
|
|
191
|
-
value="{{ (source.config.prefix if source and source.config) or '' }}" /></label>
|
|
192
|
-
<label>Connection string<input type="password" name="az_connection"
|
|
193
|
-
value="{{ (source.config.connection_string if source and source.config) or '' }}" /></label>
|
|
194
|
-
</div>
|
|
195
|
-
|
|
196
|
-
<div id="edit_fields_hdfs" class="edit-type-fields hidden">
|
|
197
|
-
<label>Namenode host<input type="text" name="hdfs_namenode"
|
|
198
|
-
value="{{ (source.config.namenode_host if source and source.config) or '' }}" /></label>
|
|
199
|
-
<label>Port<input type="number" name="hdfs_port"
|
|
200
|
-
value="{{ (source.config.port if source and source.config) or '' }}" /></label>
|
|
201
|
-
<label>User<input type="text" name="hdfs_user"
|
|
202
|
-
value="{{ (source.config.user if source and source.config) or '' }}" /></label>
|
|
203
|
-
<label>Path<input type="text" name="hdfs_path"
|
|
204
|
-
value="{{ (source.config.path if source and source.config) or '' }}" /></label>
|
|
205
|
-
</div>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
<div class="row" style="margin-bottom:12px;">
|
|
209
|
-
<div>
|
|
210
|
-
<label>Visibility
|
|
211
|
-
<div class="vis-field">
|
|
212
|
-
<span id="vis_icon" class="vis-icon" aria-hidden="true"></span>
|
|
213
|
-
<select name="visibility" id="edit_visibility">
|
|
214
|
-
{% for v in ['private','internal','public'] %}
|
|
215
|
-
<option value="{{v}}" {% if source and source.visibility==v %}selected{% endif %}>{{v}}</option>
|
|
216
|
-
{% endfor %}
|
|
217
|
-
</select>
|
|
218
|
-
</div>
|
|
219
|
-
</label>
|
|
220
|
-
</div>
|
|
221
|
-
<div>
|
|
222
|
-
<label><input type="checkbox" name="reference" {% if source and source.reference %}checked{% endif %} />
|
|
223
|
-
Reference</label>
|
|
224
|
-
<label><input type="checkbox" name="sensitive" {% if source and source.sensitive %}checked{% endif %} />
|
|
225
|
-
Sensitive</label>
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
|
|
229
|
-
<div class="actions">
|
|
230
|
-
<button class="btn secondary" type="button" id="btn_validate_form">Validate</button>
|
|
231
|
-
<button class="btn" type="submit">Save</button>
|
|
232
|
-
<a class="btn secondary" href="/">Cancel</a>
|
|
233
|
-
</div>
|
|
234
|
-
</form>
|
|
235
|
-
</div>
|
|
236
|
-
</div>
|
|
237
|
-
|
|
238
|
-
<script>
|
|
239
|
-
const tSel = document.getElementById('edit_type');
|
|
240
|
-
const vSel = document.getElementById('edit_visibility');
|
|
241
|
-
const ICONS = {
|
|
242
|
-
file: 'file.svg', csv: 'csv.svg', excel: 'excel.svg', folder: 'folder.svg', postgresql: 'postgresql.svg', mysql: 'mysql.svg', oracle: 'oracle.svg', mssql: 'mssql.svg', sqlite: 'sqlite.svg', mongodb: 'mongodb.svg', s3: 's3.svg', gcs: 'gcs.png', azure_blob: 'azure_blob.svg', hdfs: 'hdfs.svg'
|
|
243
|
-
};
|
|
244
|
-
function show(id, v) { const el = document.getElementById(id); if (el) { el.classList.toggle('hidden', !v); } }
|
|
245
|
-
function updateTypeIcon() {
|
|
246
|
-
const t = tSel ? tSel.value : 'folder';
|
|
247
|
-
const file = ICONS[t] || 'folder.svg';
|
|
248
|
-
const el = document.getElementById('edit_type_icon');
|
|
249
|
-
if (el) { el.setAttribute('src', '/static/sources-logos/' + file); el.setAttribute('alt', t); }
|
|
250
|
-
}
|
|
251
|
-
function visibilityIconHTML(v) {
|
|
252
|
-
v = (v || '').toLowerCase();
|
|
253
|
-
if (v === 'private') return "<svg width='16' height='16' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'><rect x='3' y='9' width='14' height='8' rx='2' stroke='#374151' stroke-width='2'/><path d='M6 9V7a4 4 0 1 1 8 0v2' stroke='#374151' stroke-width='2' fill='none'/></svg>";
|
|
254
|
-
if (v === 'internal') return "<svg width='16' height='16' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'><rect x='3' y='6' width='14' height='10' rx='2' stroke='#0ea5e9' stroke-width='2'/><path d='M7 6V4h6v2' stroke='#0ea5e9' stroke-width='2'/></svg>";
|
|
255
|
-
if (v === 'public') return "<svg width='16' height='16' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'><circle cx='10' cy='10' r='8' stroke='#16a34a' stroke-width='2'/><path d='M2 10h16M10 2a12 12 0 0 1 0 16M10 2a12 12 0 0 0 0 16' stroke='#16a34a' stroke-width='2'/></svg>";
|
|
256
|
-
return '';
|
|
257
|
-
}
|
|
258
|
-
function updateVisIcon() {
|
|
259
|
-
const el = document.getElementById('vis_icon');
|
|
260
|
-
if (!el) return;
|
|
261
|
-
el.innerHTML = visibilityIconHTML(vSel ? vSel.value : 'private');
|
|
262
|
-
}
|
|
263
|
-
function updateTypeFields() {
|
|
264
|
-
const t = tSel ? tSel.value : 'file';
|
|
265
|
-
['edit_fields_file', 'edit_fields_csv', 'edit_fields_excel', 'edit_fields_folder', 'edit_fields_sqlite', 'edit_fields_db', 'edit_fields_mongodb', 'edit_fields_s3', 'edit_fields_gcs', 'edit_fields_azure', 'edit_fields_hdfs'].forEach(id => show(id, false));
|
|
266
|
-
if (t === 'file') show('edit_fields_file', true);
|
|
267
|
-
if (t === 'csv') show('edit_fields_csv', true);
|
|
268
|
-
if (t === 'excel') show('edit_fields_excel', true);
|
|
269
|
-
if (t === 'folder') show('edit_fields_folder', true);
|
|
270
|
-
if (['mysql', 'postgresql', 'oracle', 'mssql'].includes(t)) show('edit_fields_db', true);
|
|
271
|
-
if (t === 'sqlite') show('edit_fields_sqlite', true);
|
|
272
|
-
if (t === 'mongodb') show('edit_fields_mongodb', true);
|
|
273
|
-
if (t === 's3') show('edit_fields_s3', true);
|
|
274
|
-
if (t === 'gcs') show('edit_fields_gcs', true);
|
|
275
|
-
if (t === 'azure_blob') show('edit_fields_azure', true);
|
|
276
|
-
if (t === 'hdfs') show('edit_fields_hdfs', true);
|
|
277
|
-
// Toggle schema field only for postgres/oracle
|
|
278
|
-
const schemaField = document.getElementById('db_schema_field');
|
|
279
|
-
if (schemaField) {
|
|
280
|
-
schemaField.classList.toggle('hidden', !(t === 'postgresql' || t === 'oracle'));
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (tSel) {
|
|
284
|
-
tSel.addEventListener('change', updateTypeIcon);
|
|
285
|
-
tSel.addEventListener('change', updateTypeFields);
|
|
286
|
-
}
|
|
287
|
-
if (vSel) { vSel.addEventListener('change', updateVisIcon); }
|
|
288
|
-
// Initialize on DOMContentLoaded to ensure elements exist
|
|
289
|
-
document.addEventListener('DOMContentLoaded', function () {
|
|
290
|
-
updateTypeIcon();
|
|
291
|
-
updateVisIcon();
|
|
292
|
-
updateTypeFields();
|
|
293
|
-
|
|
294
|
-
const browseFile = document.getElementById('btn_browse_file');
|
|
295
|
-
const browseFolder = document.getElementById('btn_browse_folder');
|
|
296
|
-
if (browseFile) {
|
|
297
|
-
browseFile.addEventListener('click', async () => {
|
|
298
|
-
try {
|
|
299
|
-
const res = await fetch('/sources/pick-file');
|
|
300
|
-
const data = await res.json();
|
|
301
|
-
if (data.path) {
|
|
302
|
-
const fp = document.getElementById('file_path');
|
|
303
|
-
if (fp) fp.value = data.path;
|
|
304
|
-
}
|
|
305
|
-
} catch (e) { /* ignore */ }
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
const browseCsv = document.getElementById('btn_browse_csv');
|
|
309
|
-
if (browseCsv) {
|
|
310
|
-
browseCsv.addEventListener('click', async () => {
|
|
311
|
-
try {
|
|
312
|
-
const res = await fetch('/sources/pick-file');
|
|
313
|
-
const data = await res.json();
|
|
314
|
-
if (data.path) {
|
|
315
|
-
const fp = document.getElementById('csv_path');
|
|
316
|
-
if (fp) fp.value = data.path;
|
|
317
|
-
}
|
|
318
|
-
} catch (e) { /* ignore */ }
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
const browseExcel = document.getElementById('btn_browse_excel');
|
|
322
|
-
if (browseExcel) {
|
|
323
|
-
browseExcel.addEventListener('click', async () => {
|
|
324
|
-
try {
|
|
325
|
-
const res = await fetch('/sources/pick-file');
|
|
326
|
-
const data = await res.json();
|
|
327
|
-
if (data.path) {
|
|
328
|
-
const fp = document.getElementById('excel_path');
|
|
329
|
-
if (fp) fp.value = data.path;
|
|
330
|
-
}
|
|
331
|
-
} catch (e) { /* ignore */ }
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
const browseSqlite = document.getElementById('btn_browse_sqlite');
|
|
335
|
-
if (browseSqlite) {
|
|
336
|
-
browseSqlite.addEventListener('click', async () => {
|
|
337
|
-
try {
|
|
338
|
-
const res = await fetch('/sources/pick-file');
|
|
339
|
-
const data = await res.json();
|
|
340
|
-
if (data.path) {
|
|
341
|
-
const fp = document.getElementById('sqlite_file_path');
|
|
342
|
-
if (fp) fp.value = data.path;
|
|
343
|
-
}
|
|
344
|
-
} catch (e) { /* ignore */ }
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
if (browseFolder) {
|
|
348
|
-
browseFolder.addEventListener('click', async () => {
|
|
349
|
-
try {
|
|
350
|
-
const res = await fetch('/sources/pick-folder');
|
|
351
|
-
const data = await res.json();
|
|
352
|
-
if (data.path) {
|
|
353
|
-
const dp = document.getElementById('folder_path');
|
|
354
|
-
if (dp) dp.value = data.path;
|
|
355
|
-
}
|
|
356
|
-
} catch (e) { /* ignore */ }
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Validate current form without saving
|
|
361
|
-
const btnValidate = document.getElementById('btn_validate_form');
|
|
362
|
-
if (btnValidate) {
|
|
363
|
-
btnValidate.addEventListener('click', async () => {
|
|
364
|
-
const form = btnValidate.closest('form');
|
|
365
|
-
const box = document.getElementById('validate_result');
|
|
366
|
-
if (!form || !box) return;
|
|
367
|
-
try {
|
|
368
|
-
btnValidate.disabled = true;
|
|
369
|
-
box.classList.add('hidden');
|
|
370
|
-
box.textContent = '';
|
|
371
|
-
const fd = new FormData(form);
|
|
372
|
-
const res = await fetch('/sources/validate', { method: 'POST', body: fd });
|
|
373
|
-
const j = await res.json();
|
|
374
|
-
const ok = !!(j && j.ok);
|
|
375
|
-
box.classList.remove('alert-error', 'alert-info');
|
|
376
|
-
box.classList.add(ok ? 'alert-info' : 'alert-error');
|
|
377
|
-
box.textContent = j && j.message ? j.message : (ok ? 'Valid.' : 'Invalid.');
|
|
378
|
-
box.classList.remove('hidden');
|
|
379
|
-
} catch (e) {
|
|
380
|
-
if (box) {
|
|
381
|
-
box.classList.remove('hidden');
|
|
382
|
-
box.classList.remove('alert-info');
|
|
383
|
-
box.classList.add('alert-error');
|
|
384
|
-
box.textContent = 'Validation failed due to a network error.';
|
|
385
|
-
}
|
|
386
|
-
} finally {
|
|
387
|
-
btnValidate.disabled = false;
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
</script>
|
|
393
|
-
<div class="footer">
|
|
394
|
-
<div class="inner">
|
|
395
|
-
<div>
|
|
396
|
-
<span>© QALITA</span> — QALITA CLI
|
|
397
|
-
</div>
|
|
398
|
-
<div>
|
|
399
|
-
<span id="cli_version"></span>
|
|
400
|
-
</div>
|
|
401
|
-
</div>
|
|
402
|
-
<script>
|
|
403
|
-
(function () {
|
|
404
|
-
fetch('/static/version.json').then(r => r.json()).then(v => {
|
|
405
|
-
const el = document.getElementById('cli_version'); if (el) { el.textContent = (v && v.version) ? `CLI v${v.version}` : ''; }
|
|
406
|
-
}).catch(() => { });
|
|
407
|
-
})();
|
|
408
|
-
</script>
|
|
409
|
-
</body>
|
|
410
|
-
|
|
411
|
-
</html>
|
|
@@ -1,128 +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 CLI - Select source</title>
|
|
8
|
-
<link rel="icon" href="/static/favicon.ico" />
|
|
9
|
-
<link rel="stylesheet" href="/static/styles.css" />
|
|
10
|
-
</head>
|
|
11
|
-
|
|
12
|
-
<body style="background-repeat: no-repeat;">
|
|
13
|
-
{% include 'navbar.html' %}
|
|
14
|
-
<div class="container-form">
|
|
15
|
-
<h1>Select a source type</h1>
|
|
16
|
-
<div class="card">
|
|
17
|
-
{% set CATEGORIES = [
|
|
18
|
-
('Flat files', [
|
|
19
|
-
('csv','CSV','csv.svg', True),
|
|
20
|
-
('json','JSON','json.png', False),
|
|
21
|
-
('parquet','Parquet','parquet.svg', False),
|
|
22
|
-
('excel','Excel','excel.svg', True),
|
|
23
|
-
('file','File','file.svg', True),
|
|
24
|
-
]),
|
|
25
|
-
('Relational databases', [
|
|
26
|
-
('clickhouse','ClickHouse','clickhouse.png', False),
|
|
27
|
-
('ibm_db2','IBM Db2','ibm-db2.png', False),
|
|
28
|
-
('mariadb','MariaDB','maria-db.png', False),
|
|
29
|
-
('mssql','Microsoft SQL Server','mssql.svg', True),
|
|
30
|
-
('mysql','MySQL','mysql.svg', True),
|
|
31
|
-
('oracle','Oracle','oracle.svg', True),
|
|
32
|
-
('postgresql','PostgreSQL','postgresql.svg', True),
|
|
33
|
-
('sap_hana','SAP HANA','sap-hana.png', False),
|
|
34
|
-
('teradata','Teradata','teradata.png', False),
|
|
35
|
-
('yugabytedb','YugabyteDB','yugabyte-db.png', False),
|
|
36
|
-
('cockroachdb','CockroachDB','cockroach-db.png', False),
|
|
37
|
-
('sqlite','SQLite','sqlite.svg', True),
|
|
38
|
-
]),
|
|
39
|
-
('No SQL databases', [
|
|
40
|
-
('elasticsearch','Elasticsearch','elasticsearch.svg', False),
|
|
41
|
-
('cassandra','Cassandra','cassandra.svg', False),
|
|
42
|
-
('mongodb','MongoDB','mongodb.svg', True),
|
|
43
|
-
]),
|
|
44
|
-
('Data storages', [
|
|
45
|
-
('folder','Folder','folder.svg', True),
|
|
46
|
-
('s3','Amazon S3','s3.svg', True),
|
|
47
|
-
('azure_blob','Azure Blob Storage','azure_blob.svg', True),
|
|
48
|
-
('gcs','Google Cloud Storage','gcs.png', True),
|
|
49
|
-
('hdfs','HDFS','hdfs.svg', True),
|
|
50
|
-
]),
|
|
51
|
-
('Cloud databases', [
|
|
52
|
-
('alloydb','AlloyDB for PostgreSQL','alloy-db.png', False),
|
|
53
|
-
('aurora','Amazon Aurora','amazon-rds.png', False),
|
|
54
|
-
('rds_mysql','Amazon RDS for MySQL','amazon-rds.png', False),
|
|
55
|
-
('rds_postgresql','Amazon RDS for PostgreSQL','amazon-rds.png', False),
|
|
56
|
-
('rds_sqlserver','Amazon RDS for SQL Server','amazon-rds.png', False),
|
|
57
|
-
('azure_mysql','Azure Database for MySQL','azure-database-mysql.png', False),
|
|
58
|
-
('azure_postgresql','Azure Database for PostgreSQL','azure-database-postgresql.png', False),
|
|
59
|
-
('azure_sql_database','Azure SQL Database','azure-sql-database.png', False),
|
|
60
|
-
('azure_sql_managed_instance','Azure SQL Managed Instance','azure-sql-managed-instance.png', False),
|
|
61
|
-
('cloudsql_mysql','Cloud SQL for MySQL','mysql.svg', False),
|
|
62
|
-
('cloudsql_postgresql','Cloud SQL for PostgreSQL','postgresql.svg', False),
|
|
63
|
-
('cloudsql_sqlserver','Cloud SQL for SQL Server','mssql.svg', False),
|
|
64
|
-
]),
|
|
65
|
-
('SaaS databases', [
|
|
66
|
-
('databricks','Databricks','databricks.png', False),
|
|
67
|
-
('singlestoredb','SingleStoreDB','single-store.png', False),
|
|
68
|
-
('snowflake','Snowflake','snowflake.png', False),
|
|
69
|
-
('starburst','Starburst','starburst.png', False),
|
|
70
|
-
]),
|
|
71
|
-
('Data warehouses', [
|
|
72
|
-
('athena','Amazon Athena','amazon-athena.png', False),
|
|
73
|
-
('redshift','Amazon Redshift','redshift.png', False),
|
|
74
|
-
('synapse','Azure Synapse Analytics','azure-synapse-analytics.png', False),
|
|
75
|
-
('bigquery','Google BigQuery','bigquery.png', False),
|
|
76
|
-
]),
|
|
77
|
-
('Time series databases', [
|
|
78
|
-
('questdb','QuestDB','questdb.png', False),
|
|
79
|
-
('timescale','Timescale','timescale.png', False),
|
|
80
|
-
]),
|
|
81
|
-
] %}
|
|
82
|
-
{% for category, items in CATEGORIES %}
|
|
83
|
-
<div style="margin-bottom:16px;">
|
|
84
|
-
<h2 style="margin:0 0 8px 0;">{{ category }}</h2>
|
|
85
|
-
<div style="display:grid;grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px;">
|
|
86
|
-
{% for value, label, icon, implemented in items %}
|
|
87
|
-
{% if implemented %}
|
|
88
|
-
<a href="/sources/add?type={{ value }}" class="btn light" style="display:flex;flex-direction:column;align-items:center;gap:10px;padding:16px;">
|
|
89
|
-
<img src="/static/sources-logos/{{ icon }}" alt="{{ label }}" style="width:40px;height:40px;object-fit:contain;border-radius:6px;" onerror="this.onerror=null;this.src='/static/sources-logos/file.svg'" />
|
|
90
|
-
<span style="font-weight:600;">{{ label }}</span>
|
|
91
|
-
</a>
|
|
92
|
-
{% else %}
|
|
93
|
-
<div class="btn light" style="background-color: #f0f0f0; display:flex;flex-direction:column;align-items:center;gap:10px;padding:16px;opacity:0.5;cursor:not-allowed;">
|
|
94
|
-
<img src="/static/sources-logos/{{ icon }}" alt="{{ label }} (coming soon)" title="Not yet implemented" style="width:40px;height:40px;object-fit:contain;border-radius:6px;" onerror="this.onerror=null;this.src='/static/sources-logos/file.svg'" />
|
|
95
|
-
<span style="font-weight:600;">{{ label }}</span>
|
|
96
|
-
</div>
|
|
97
|
-
{% endif %}
|
|
98
|
-
{% endfor %}
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
{% endfor %}
|
|
102
|
-
<div class="actions" style="margin-top:16px;">
|
|
103
|
-
<a class="btn" href="mailto:contact@qalita.io?subject=Suggest%20a%20new%20source%20type&body=Hi%20QALITA%20team%2C%0A%0AI%27d%20like%20to%20suggest%20support%20for%20this%20source%20type%3A%20%5Bplease%20describe%5D%0A%0AThanks!">Suggest a new source type</a>
|
|
104
|
-
<a class="btn secondary" href="/">Cancel</a>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
<div class="footer">
|
|
109
|
-
<div class="inner">
|
|
110
|
-
<div>
|
|
111
|
-
<span>© QALITA</span> — QALITA CLI
|
|
112
|
-
</div>
|
|
113
|
-
<div>
|
|
114
|
-
<span id="cli_version"></span>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
</div>
|
|
118
|
-
<script>
|
|
119
|
-
(function () {
|
|
120
|
-
fetch('/static/version.json').then(r => r.json()).then(v => {
|
|
121
|
-
const el = document.getElementById('cli_version'); if (el) { el.textContent = (v && v.version) ? `CLI v${v.version}` : ''; }
|
|
122
|
-
}).catch(() => { });
|
|
123
|
-
})();
|
|
124
|
-
</script>
|
|
125
|
-
</body>
|
|
126
|
-
|
|
127
|
-
</html>
|
|
128
|
-
|