qalita 2.2.8__py3-none-any.whl → 2.3.0__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 CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  import os
5
5
  import click
6
-
6
+
7
7
  from qalita.internal.utils import logger, get_version
8
8
  from qalita.internal.config import Config
9
9
 
@@ -37,8 +37,8 @@ pass_config = click.make_pass_decorator(Config, ensure=True)
37
37
  @click.pass_context
38
38
  def cli(ctx, ui=False, port=7070, host="localhost"):
39
39
  """
40
- ------------------ Qalita Platform Command Line Interface ------------------\n\r
41
- Hello and thanks for using Qalita Platform to monitor and ensure the quality of your data. \n\r
40
+ ------------------ QALITA Platform Command Line Interface ------------------\n\r
41
+ Hello and thanks for using QALITA Platform to monitor and ensure the quality of your data. \n\r
42
42
  ----------------------------------------------------------------------------\n\r
43
43
  Please, Help us improve our service by reporting any bug by filing a bug report, Thanks ! \n\r
44
44
  mail : contact@qalita.io \n\r
qalita/commands/agent.py CHANGED
@@ -56,7 +56,7 @@ ROUTINE_LAST_SCHEDULED_UTC = {}
56
56
  )
57
57
  @pass_config
58
58
  def agent(config, name, mode, token, url):
59
- """Manage Qalita Platform Agents"""
59
+ """Manage QALITA Platform Agents"""
60
60
 
61
61
  all_check_pass = True
62
62
 
@@ -200,7 +200,7 @@ def send_alive(config, config_file, mode="", status="online"):
200
200
 
201
201
  @pass_config
202
202
  def authenticate(config, user_id):
203
- """Authenticate the agent to the Qalita Platform"""
203
+ """Authenticate the agent to the QALITA Platform"""
204
204
  try:
205
205
  r = send_request.__wrapped__(
206
206
  config,
@@ -345,7 +345,7 @@ def authenticate(config, user_id):
345
345
  @pass_config
346
346
  def login(config):
347
347
  """
348
- Register the agent to the Qalita Platform
348
+ Register the agent to the QALITA Platform
349
349
  """
350
350
  if config.verbose:
351
351
  logger.info("Verbose mode enabled")
@@ -356,8 +356,8 @@ def login(config):
356
356
  r = send_request(request=f"{config.url}/api/v1/version", mode="get")
357
357
  if r.status_code == 200:
358
358
  if r.json()["version"] != get_version():
359
- logger.info(f"Qalita Platform Version : {r.json()['version']}")
360
- logger.info(f"Qalita CLI Version : {get_version()}")
359
+ logger.info(f"QALITA Platform Version : {r.json()['version']}")
360
+ logger.info(f"QALITA CLI Version : {get_version()}")
361
361
  logger.info(
362
362
  "Make sure you are using compatible versions for the platform and the cli,\n\t> check compatibility matrix on the documentation <"
363
363
  )
@@ -874,7 +874,7 @@ def post_run(
874
874
  ## LOGS
875
875
  # Initialize logs_id to None
876
876
  logs_id = None
877
- logger.info(f"Uploading logs to Qalita Platform...")
877
+ logger.info(f"Uploading logs to QALITA Platform...")
878
878
  logger.info(f"run_path: {run_path}")
879
879
  if os.path.exists(run_path + "/logs.txt"):
880
880
  api_url = agent_conf["context"]["local"]["url"]
@@ -912,12 +912,12 @@ def post_run(
912
912
  else:
913
913
  logger.info(f"No logs.txt file found")
914
914
 
915
- logger.info(f"Uploading results to Qalita Platform...")
915
+ logger.info(f"Uploading results to QALITA Platform...")
916
916
 
917
917
  #########################################################
918
918
  ## Recommendations
919
919
  if os.path.exists(run_path + "/recommendations.json"):
920
- logger.info(f"\tUploading recommendations to Qalita Platform...")
920
+ logger.info(f"\tUploading recommendations to QALITA Platform...")
921
921
 
922
922
  api_url = agent_conf["context"]["local"]["url"]
923
923
  registry_id = agent_conf["registries"][0]["id"]
@@ -949,7 +949,7 @@ def post_run(
949
949
  #########################################################
950
950
  ## Schemas
951
951
  if os.path.exists(run_path + "/schemas.json"):
952
- logger.info(f"\tUploading schemas to Qalita Platform...")
952
+ logger.info(f"\tUploading schemas to QALITA Platform...")
953
953
 
954
954
  api_url = agent_conf["context"]["local"]["url"]
955
955
  registry_id = agent_conf["registries"][0]["id"]
@@ -981,7 +981,7 @@ def post_run(
981
981
  #########################################################
982
982
  ## Metrics
983
983
  if os.path.exists(run_path + "/metrics.json"):
984
- logger.info(f"\tUploading Metrics to Qalita Platform...")
984
+ logger.info(f"\tUploading Metrics to QALITA Platform...")
985
985
 
986
986
  api_url = agent_conf["context"]["local"]["url"]
987
987
  registry_id = agent_conf["registries"][0]["id"]
qalita/commands/pack.py CHANGED
@@ -241,7 +241,7 @@ def check_name(name):
241
241
  @click.option("-p", "--pack", type=int, help="Pack ID")
242
242
  @click.pass_context
243
243
  def pack(ctx, pack):
244
- """Manage Qalita Platform Packs"""
244
+ """Manage QALITA Platform Packs"""
245
245
  ctx.ensure_object(dict)
246
246
  ctx.obj["PACK"] = pack
247
247
 
@@ -416,7 +416,7 @@ def validate_pack_directory(pack_directory: str) -> int:
416
416
  @click.option(
417
417
  "-n",
418
418
  "--name",
419
- help="The name of the package, it will be used to identify the package in the Qalita platform",
419
+ help="The name of the package, it will be used to identify the package in the QALITA platform",
420
420
  envvar="QALITA_PACK_NAME",
421
421
  )
422
422
  @pass_config
@@ -693,7 +693,7 @@ def handle_version_matching(existing_versions, new_version):
693
693
  @click.option("-n", "--name", help="Name of the package", envvar="QALITA_PACK_NAME")
694
694
  @pass_config
695
695
  def push(config, name):
696
- """Pushes a package to the Qalita Platform"""
696
+ """Pushes a package to the QALITA Platform"""
697
697
 
698
698
  try:
699
699
  name = check_name(name)
@@ -709,7 +709,7 @@ def push(config, name):
709
709
  return
710
710
 
711
711
  logger.info("---------------- Pack Push ----------------")
712
- logger.info(f"Pushing pack '{name}' to Qalita Platform...")
712
+ logger.info(f"Pushing pack '{name}' to QALITA Platform...")
713
713
 
714
714
  pack_directory = f"./{name}_pack" if not name.endswith("_pack") else f"./{name}"
715
715
 
@@ -920,7 +920,7 @@ def push_from_directory(config, pack_directory):
920
920
  @click.option(
921
921
  "-n",
922
922
  "--name",
923
- help="The name of the package, it will be used to identify the package in the Qalita platform",
923
+ help="The name of the package, it will be used to identify the package in the QALITA platform",
924
924
  envvar="QALITA_PACK_NAME",
925
925
  )
926
926
  def run(name):
@@ -969,7 +969,7 @@ def run(name):
969
969
  @click.option(
970
970
  "-n",
971
971
  "--name",
972
- help="The name of the package, it will be used to identify the package in the Qalita platform",
972
+ help="The name of the package, it will be used to identify the package in the QALITA platform",
973
973
  envvar="QALITA_PACK_NAME",
974
974
  )
975
975
  @pass_config
qalita/commands/source.py CHANGED
@@ -15,7 +15,7 @@ from qalita.internal.request import send_api_request
15
15
  @click.option("-s", "--source", type=int, help="Source ID")
16
16
  @click.pass_context
17
17
  def source(ctx, source):
18
- """Manage Qalita Platform Sources"""
18
+ """Manage QALITA Platform Sources"""
19
19
  ctx.ensure_object(dict)
20
20
  ctx.obj["SOURCE"] = source
21
21
 
@@ -264,13 +264,13 @@ def validate():
264
264
  )
265
265
  @pass_config
266
266
  def push(config, skip_validate):
267
- """Publish a source to the Qalita Platform"""
267
+ """Publish a source to the QALITA Platform"""
268
268
  if not skip_validate:
269
269
  validate_source()
270
270
  else:
271
271
  logger.warning("Skipping source validation as requested.")
272
272
  logger.info("------------- Source Publishing -------------")
273
- logger.info("Publishing sources to the Qalita Platform...")
273
+ logger.info("Publishing sources to the QALITA Platform...")
274
274
 
275
275
  invalid_count = 0 # To count failed publishing sources
276
276
  agent_conf = config.load_agent_config()
@@ -638,7 +638,7 @@ def push_single_programmatic(config, source_name: str, approve_public: bool = Fa
638
638
  @source.command()
639
639
  @pass_config
640
640
  def add(config):
641
- """Add a source to the local Qalita Config"""
641
+ """Add a source to the local QALITA Config"""
642
642
 
643
643
  # initialize the source dict
644
644
  source = {}
qalita/internal/utils.py CHANGED
@@ -14,7 +14,7 @@ logger = init_logging()
14
14
 
15
15
 
16
16
  def get_version():
17
- return "2.2.8"
17
+ return "2.3.0"
18
18
 
19
19
 
20
20
  def make_tarfile(output_filename, source_dir):
qalita/web/app.py CHANGED
@@ -7,7 +7,7 @@ from flask import Flask
7
7
  from waitress import serve
8
8
 
9
9
  def create_app(config_obj) -> Flask:
10
- """Application factory for the Qalita CLI UI."""
10
+ """Application factory for the QALITA CLI UI."""
11
11
  app = Flask(
12
12
  __name__,
13
13
  static_folder=os.path.join(os.path.dirname(__file__), "public"),
@@ -36,5 +36,5 @@ def create_app(config_obj) -> Flask:
36
36
  def run_dashboard_ui(config_obj, host: str = "localhost", port: int = 7070):
37
37
  app = create_app(config_obj)
38
38
  url = f"http://{host}:{port}"
39
- print(f"Qalita CLI UI is running. Open {url}")
39
+ print(f"QALITA CLI UI is running. Open {url}")
40
40
  serve(app, host=host, port=port)
@@ -375,7 +375,7 @@ def open_agent_run(run_name: str):
375
375
  <div class="footer">
376
376
  <div class="inner">
377
377
  <div>
378
- <span>&copy; QALITA</span> — Qalita CLI
378
+ <span>&copy; QALITA</span> — QALITA CLI
379
379
  </div>
380
380
  <div>
381
381
  <span id="cli_version"></span>
@@ -411,7 +411,7 @@ def open_agent_run(run_name: str):
411
411
  <div class="footer">
412
412
  <div class="inner">
413
413
  <div>
414
- <span>&copy; QALITA</span> — Qalita CLI
414
+ <span>&copy; QALITA</span> — QALITA CLI
415
415
  </div>
416
416
  <div>
417
417
  <span id="cli_version"></span>
@@ -451,7 +451,7 @@ def open_agent_run(run_name: str):
451
451
  <div class="footer">
452
452
  <div class="inner">
453
453
  <div>
454
- <span>&copy; QALITA</span> — Qalita CLI
454
+ <span>&copy; QALITA</span> — QALITA CLI
455
455
  </div>
456
456
  <div>
457
457
  <span id="cli_version"></span>
@@ -3,15 +3,15 @@
3
3
  --studio-primary: #4169e1;
4
4
  /* royal blue */
5
5
  --studio-primary-600: #3657c7;
6
- --studio-bg: #0f1115;
6
+ --studio-bg: #f3f7ff;
7
7
  --studio-surface: #12161c;
8
- --studio-surface-2: #161b23;
8
+ --studio-surface-2: #9b9b9b;
9
9
  --studio-border: #1e2633;
10
+ --studio-border-2: #283242;
10
11
  --studio-text: #3a3d43;
11
12
  --studio-muted: #9ca3af;
12
13
  --studio-accent: #4169e1;
13
14
  color: var(--studio-text);
14
- background: linear-gradient(180deg, var(--studio-bg), var(--studio-surface));
15
15
  min-height: 100vh;
16
16
  display: flex;
17
17
  flex-direction: column;
@@ -53,9 +53,14 @@
53
53
  .studio .card {
54
54
  background: var(--studio-surface);
55
55
  border-color: var(--studio-border);
56
- box-shadow: 0 2px 14px rgba(0, 0, 0, .25);
57
56
  }
58
57
 
58
+ .studio .card:hover {
59
+ background: var(--studio-surface-2);
60
+ border-color: var(--studio-border-2);
61
+ }
62
+
63
+
59
64
  /* Buttons */
60
65
  .studio .btn,
61
66
  .studio-btn {
@@ -135,6 +140,9 @@
135
140
  background: #0F4862;
136
141
  color: #ffffff;
137
142
  border-bottom: none;
143
+ position: absolute;
144
+ width: 260px;
145
+ border-bottom-right-radius: 15px;
138
146
  }
139
147
 
140
148
  .studio-navbar .brand span,
@@ -161,7 +169,7 @@
161
169
  .studio-panels {
162
170
  display: flex;
163
171
  width: 100%;
164
- height: calc(100vh - 42px);
172
+ height: calc(100vh);
165
173
  overflow-x: hidden;
166
174
  }
167
175
 
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - Dashboard</title>
7
+ <title>QALITA CLI - Dashboard</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -88,10 +88,10 @@
88
88
  <h3>Documentation</h3>
89
89
  </div>
90
90
  </div>
91
- <p>Learn how to use Qalita and its features.</p>
91
+ <p>Learn how to use QALITA and its features.</p>
92
92
  <div>
93
93
  <a href="https://doc.qalita.io" target="_blank" rel="noopener noreferrer"><button class="btn black-white"
94
- type="button" style="width:100%;padding:12px 16px;">Qalita Docs</button></a>
94
+ type="button" style="width:100%;padding:12px 16px;">QALITA Docs</button></a>
95
95
  </div>
96
96
  </div>
97
97
  </div>
@@ -322,7 +322,7 @@
322
322
  <div class="footer">
323
323
  <div class="inner">
324
324
  <div>
325
- <span>&copy; QALITA</span> — Qalita CLI
325
+ <span>&copy; QALITA</span> — QALITA CLI
326
326
  </div>
327
327
  <div>
328
328
  <span id="cli_version"></span>
@@ -2,7 +2,7 @@
2
2
  <div class="brand">
3
3
  <div class="left">
4
4
  <a href="/" style="display:flex;align-items:center;gap:8px;text-decoration:none;color:inherit;">
5
- <img src="/static/logo-no-slogan.png" alt="Qalita" />
5
+ <img src="/static/logo-no-slogan.png" alt="QALITA" />
6
6
  <span>CLI</span>
7
7
  </a>
8
8
  </div>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - Source added</title>
7
+ <title>QALITA CLI - Source added</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -36,7 +36,7 @@
36
36
  <div class="footer">
37
37
  <div class="inner">
38
38
  <div>
39
- <span>&copy; QALITA</span> — Qalita CLI
39
+ <span>&copy; QALITA</span> — QALITA CLI
40
40
  </div>
41
41
  <div>
42
42
  <span id="cli_version"></span>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - {{ title }}</title>
7
+ <title>QALITA CLI - {{ title }}</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -393,7 +393,7 @@
393
393
  <div class="footer">
394
394
  <div class="inner">
395
395
  <div>
396
- <span>&copy; QALITA</span> — Qalita CLI
396
+ <span>&copy; QALITA</span> — QALITA CLI
397
397
  </div>
398
398
  <div>
399
399
  <span id="cli_version"></span>
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita CLI - Select source</title>
7
+ <title>QALITA CLI - Select source</title>
8
8
  <link rel="icon" href="/static/favicon.ico" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  </head>
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
  {% endfor %}
102
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>
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
104
  <a class="btn secondary" href="/">Cancel</a>
105
105
  </div>
106
106
  </div>
@@ -108,7 +108,7 @@
108
108
  <div class="footer">
109
109
  <div class="inner">
110
110
  <div>
111
- <span>&copy; QALITA</span> — Qalita CLI
111
+ <span>&copy; QALITA</span> — QALITA CLI
112
112
  </div>
113
113
  <div>
114
114
  <span id="cli_version"></span>
@@ -2,6 +2,7 @@
2
2
  <div id="backend_status_dot" title="Checking backend..."
3
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
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>
5
6
  <div class="right" style="display:flex;align-items:center;gap:8px;">
6
7
  <p style="margin: 0px; min-width: 130px;">Platform Context</p>
7
8
  <select id="ctx_select" class="studio-input" style="margin-top: 0px; cursor:pointer;"></select>
@@ -17,7 +18,7 @@
17
18
  <div>
18
19
  <div class="studio-setup-title">Setup platform</div>
19
20
  <div class="studio-setup-text">
20
- Your current context doesn't provide Qalita platform credentials.<br><br>
21
+ Your current context doesn't provide QALITA platform credentials.<br><br>
21
22
  To use contextual data quality metadata, configure your Platform endpoint and token.
22
23
  </div>
23
24
  <div class="studio-setup-actions">
@@ -34,6 +35,15 @@
34
35
  </div>
35
36
  <script>
36
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
+ }
37
47
  function showSetupCardIfNeeded(status) {
38
48
  try {
39
49
  var card = document.getElementById('setup_platform_card');
@@ -60,9 +70,10 @@
60
70
  var url = (j && j.url) ? String(j.url) : '';
61
71
  var code = (j && j.status != null) ? String(j.status) : 'N/A';
62
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 + ')'));
63
74
  showSetupCardIfNeeded(j || {});
64
75
  })
65
- .catch(function () { if (dot) { dot.style.background = '#ef4444'; dot.title = 'Backend check failed'; } });
76
+ .catch(function () { if (dot) { dot.style.background = '#ef4444'; dot.title = 'Backend check failed'; } setCtxError('Backend check failed'); });
66
77
  }
67
78
  function renderIssues(items) {
68
79
  var root = document.getElementById('issues_container');
@@ -213,6 +224,7 @@
213
224
  .then(function (r) { return r.json(); })
214
225
  .then(function (j) {
215
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(''); }
216
228
  if (!projectId) { renderIssues(items); return; }
217
229
  // Client-side filter by project sources for robustness
218
230
  var srcUrl = '/studio/sources?project_id=' + encodeURIComponent(projectId);
@@ -225,9 +237,9 @@
225
237
  var filtered = items.filter(function (it) { var sid = extractIssueSourceId(it); return sid && set[sid]; });
226
238
  renderIssues(filtered);
227
239
  })
228
- .catch(function () { renderIssues([]); });
240
+ .catch(function () { setCtxError('Failed to load project sources'); renderIssues([]); });
229
241
  })
230
- .catch(function () { renderIssues([]); });
242
+ .catch(function () { setCtxError('Failed to load issues'); renderIssues([]); });
231
243
  }
232
244
  function loadProjects() {
233
245
  function normalizeProjects(j) {
@@ -251,9 +263,10 @@
251
263
  .then(function (r) { return r.json(); })
252
264
  .then(function (j) {
253
265
  var items = normalizeProjects(j && (j.items != null ? j.items : j));
266
+ if (!j) { setCtxError('Failed to load projects'); } else { setCtxError(''); }
254
267
  renderProjects(items);
255
268
  })
256
- .catch(function () { renderProjects([]); });
269
+ .catch(function () { setCtxError('Failed to load projects'); renderProjects([]); });
257
270
  }
258
271
  function loadContexts() {
259
272
  fetch('/contexts').then(r => r.json()).then(j => {
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="utf-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <title>Qalita Studio</title>
7
+ <title>QALITA Studio</title>
8
8
  <link rel="icon" href="/static/studio.png" />
9
9
  <link rel="stylesheet" href="/static/styles.css" />
10
10
  <link rel="stylesheet" href="/static/studio.css" />
@@ -13,11 +13,11 @@
13
13
  <body class="studio" style="background-repeat: no-repeat;">
14
14
  {% include 'studio/navbar.html' %}
15
15
  <div class="studio-panels" id="studio_panels">
16
- <section class="panel" id="panel_context" style="flex: 0 0 22%;">
16
+ <section class="panel" id="panel_context" style="flex: 0 0 18%; margin-top: 40px;">
17
17
  {% include 'studio/context-panel.html' %}
18
18
  </section>
19
19
  <div class="resizer" data-resizer="left-center"></div>
20
- <section class="panel" id="panel_view" style="flex: 0 0 45%;">
20
+ <section class="panel" id="panel_view" style="flex: 0 0 49%;">
21
21
  {% include 'studio/view-panel.html' %}
22
22
  </section>
23
23
  <div class="resizer" data-resizer="center-right"></div>
@@ -50,7 +50,7 @@
50
50
  function onMouseMove(e) {
51
51
  if (!active) return;
52
52
  const dx = e.clientX - startX;
53
- const min = 200;
53
+ const min = 263;
54
54
  if (active.dataset.resizer === 'left-center') {
55
55
  let w0 = Math.max(min, startWidths[0] + dx);
56
56
  let w1 = Math.max(min, startWidths[1] - dx);
@@ -1,8 +1,8 @@
1
1
  <div class="topbar studio-navbar">
2
- <div class="brand" style="max-width:100%; padding: 5px 20px;">
2
+ <div class="brand" style="max-width:100%; padding: 6px 23px;">
3
3
  <div class="left">
4
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"
5
+ <img src="/static/logo-white-no-slogan.svg" alt="Logo QALITA" width="25" height="25"
6
6
  style="height:25px;" />
7
7
  <span style="font-size: 20px; font-weight: 300; color: #ffffff;">Studio</span>
8
8
  <span class="badge"
@@ -8,6 +8,8 @@
8
8
  <p>Here will be displayed contextualized data.</p>
9
9
  </div>
10
10
 
11
+ <div id="vp_error" style="display:none; margin:8px 0; padding:8px 10px; border:1px solid #fecaca; background:#fef2f2; color:#b91c1c; border-radius:6px; font-size:12px;"></div>
12
+
11
13
  <div id="vp_image" style="display:none; height:100%; overflow:auto;">
12
14
  <img id="vp_image_img" alt="image" style="max-width:100%; height:auto; display:block; margin: 0 auto;" />
13
15
  </div>
@@ -57,6 +59,66 @@
57
59
  var vpTableTbl = document.getElementById('vp_table_tbl');
58
60
  var vpSources = document.getElementById('vp_sources');
59
61
  var vpSourcesContainer = document.getElementById('vp_sources_container');
62
+ // Table incremental rendering state
63
+ var tableState = { headers: [], rows: [], rendered: 0, pageSize: 200, isLoading: false, endReached: false };
64
+ var tableScrollHandler = null;
65
+
66
+ // --- Icons helpers (use public/sources-logos files) ---
67
+ function getIconSrcForType(type) {
68
+ var t = String(type || '').toLowerCase();
69
+ function src(name) { return '/static/sources-logos/' + name; }
70
+ if (!t) return src('database.svg');
71
+ if (t.indexOf('folder') !== -1) return src('folder.svg');
72
+ if (t === 'file') return src('file.svg');
73
+ if (t.indexOf('image') !== -1 || t.indexOf('png') !== -1 || t.indexOf('jpg') !== -1 || t.indexOf('jpeg') !== -1) return src('picture.png');
74
+ if (t.indexOf('csv') !== -1) return src('csv.svg');
75
+ if (t.indexOf('xlsx') !== -1) return src('xlsx.svg');
76
+ if (t.indexOf('xls') !== -1) return src('xls.svg');
77
+ if (t.indexOf('excel') !== -1) return src('excel.svg');
78
+ if (t.indexOf('json') !== -1) return src('json.png');
79
+ if (t.indexOf('parquet') !== -1) return src('parquet.svg');
80
+ if (t.indexOf('avro') !== -1) return src('avro.svg');
81
+ if (t.indexOf('s3') !== -1) return src('s3.svg');
82
+ if (t.indexOf('gcs') !== -1) return src('gcs.png');
83
+ if (t.indexOf('azure_blob') !== -1 || t.indexOf('azure-blob') !== -1) return src('azure_blob.svg');
84
+ if (t.indexOf('hdfs') !== -1) return src('hdfs.svg');
85
+ if (t.indexOf('postgres') !== -1) return src('postgresql.svg');
86
+ if (t.indexOf('mysql') !== -1) return src('mysql.svg');
87
+ if (t.indexOf('mssql') !== -1 || t.indexOf('sqlserver') !== -1) return src('mssql.svg');
88
+ if (t.indexOf('sqlite') !== -1) return src('sqlite.svg');
89
+ if (t.indexOf('oracle') !== -1) return src('oracle.svg');
90
+ if (t.indexOf('redshift') !== -1) return src('redshift.png');
91
+ if (t.indexOf('snowflake') !== -1) return src('snowflake.png');
92
+ if (t.indexOf('clickhouse') !== -1) return src('clickhouse.png');
93
+ if (t.indexOf('duckdb') !== -1) return src('duckdb.png');
94
+ if (t.indexOf('databricks') !== -1) return src('databricks.png');
95
+ if (t.indexOf('cassandra') !== -1) return src('cassandra.svg');
96
+ if (t.indexOf('elasticsearch') !== -1) return src('elasticsearch.svg');
97
+ if (t.indexOf('mongodb') !== -1) return src('mongodb.svg');
98
+ if (t.indexOf('cockroach') !== -1) return src('cockroach-db.png');
99
+ if (t.indexOf('yugabyte') !== -1) return src('yugabyte-db.png');
100
+ if (t.indexOf('questdb') !== -1) return src('questdb.png');
101
+ if (t.indexOf('timescale') !== -1) return src('timescale.png');
102
+ if (t.indexOf('alloy') !== -1) return src('alloy-db.png');
103
+ if (t.indexOf('cloud sql') !== -1 || t.indexOf('cloud-sql') !== -1) return src('cloud-sql.png');
104
+ if (t.indexOf('athena') !== -1) return src('amazon-athena.png');
105
+ if (t.indexOf('rds') !== -1) return src('amazon-rds.png');
106
+ if (t.indexOf('bigquery') !== -1) return src('bigquery.png');
107
+ if (t.indexOf('synapse') !== -1) return src('azure-synapse-analytics.png');
108
+ if (t.indexOf('single') !== -1 && t.indexOf('store') !== -1) return src('single-store.png');
109
+ if (t.indexOf('starburst') !== -1) return src('starburst.png');
110
+ if (t.indexOf('teradata') !== -1) return src('teradata.png');
111
+ if (t.indexOf('hana') !== -1 || t.indexOf('sap') !== -1) return src('sap-hana.png');
112
+ if (t.indexOf('sftp') !== -1) return src('sftp.png');
113
+ if (t.indexOf('stream') !== -1) return src('stream.png');
114
+ if (t.indexOf('api') !== -1) return src('api.svg');
115
+ return src('database.svg');
116
+ }
117
+ function iconHtmlForType(type) {
118
+ var src = getIconSrcForType(type);
119
+ var title = String(type || '').toUpperCase();
120
+ return '<img src="' + src + '" alt="' + title.replace(/"/g, '') + '" title="' + title.replace(/"/g, '') + '" style="width:16px;height:16px;object-fit:contain;margin-right:6px;vertical-align:middle;" />';
121
+ }
60
122
 
61
123
  function hideAll() {
62
124
  [vpImage, vpPdf, vpText, vpJson, vpTable].forEach(function (el) { if (el) el.style.display = 'none'; });
@@ -80,8 +142,27 @@
80
142
  return { headers: headers, rows: body };
81
143
  }
82
144
 
83
- function renderTable(data) {
84
- // data may be: { headers, rows } or { items } or { csv }
145
+ function appendTableRows(count) {
146
+ var tbody = vpTableTbl.querySelector('tbody');
147
+ var start = tableState.rendered;
148
+ var end = Math.min(start + (count != null ? count : tableState.pageSize), tableState.rows.length);
149
+ for (var i = start; i < end; i++) {
150
+ var r = tableState.rows[i];
151
+ var tr = document.createElement('tr');
152
+ r.forEach(function (c) {
153
+ var td = document.createElement('td');
154
+ td.textContent = c == null ? '' : String(c);
155
+ td.style.borderBottom = '1px solid #f3f4f6';
156
+ td.style.padding = '6px 8px';
157
+ tr.appendChild(td);
158
+ });
159
+ tbody.appendChild(tr);
160
+ }
161
+ tableState.rendered = end;
162
+ if (end >= tableState.rows.length) { tableState.endReached = true; }
163
+ }
164
+ function setupTableIncrementalRendering(data) {
165
+ // Normalize data to headers/rows
85
166
  var headers = [];
86
167
  var rows = [];
87
168
  if (data && Array.isArray(data.headers) && Array.isArray(data.rows)) {
@@ -93,13 +174,19 @@
93
174
  var parsed = toRowsFromCsv(data.csv);
94
175
  headers = parsed.headers; rows = parsed.rows;
95
176
  }
177
+ // Reset state
178
+ tableState.headers = headers || [];
179
+ tableState.rows = Array.isArray(rows) ? rows : [];
180
+ tableState.rendered = 0;
181
+ tableState.endReached = false;
182
+ // Build header
96
183
  var thead = vpTableTbl.querySelector('thead');
97
184
  var tbody = vpTableTbl.querySelector('tbody');
98
185
  thead.innerHTML = '';
99
186
  tbody.innerHTML = '';
100
- if (headers && headers.length) {
187
+ if (tableState.headers.length) {
101
188
  var trh = document.createElement('tr');
102
- headers.forEach(function (h) {
189
+ tableState.headers.forEach(function (h) {
103
190
  var th = document.createElement('th');
104
191
  th.textContent = String(h);
105
192
  th.style.textAlign = 'left';
@@ -112,20 +199,25 @@
112
199
  });
113
200
  thead.appendChild(trh);
114
201
  }
115
- if (rows && rows.length) {
116
- rows.forEach(function (r) {
117
- var tr = document.createElement('tr');
118
- r.forEach(function (c) {
119
- var td = document.createElement('td');
120
- td.textContent = c == null ? '' : String(c);
121
- td.style.borderBottom = '1px solid #f3f4f6';
122
- td.style.padding = '6px 8px';
123
- tr.appendChild(td);
202
+ // Initial 200-row preview
203
+ appendTableRows(tableState.pageSize);
204
+ // Attach scroll listener for infinite scroll
205
+ if (tableScrollHandler && vpTable) { try { vpTable.removeEventListener('scroll', tableScrollHandler); } catch (e) { } }
206
+ tableScrollHandler = function () {
207
+ if (!vpTable || tableState.endReached || tableState.isLoading) return;
208
+ var remaining = (vpTable.scrollHeight - vpTable.scrollTop - vpTable.clientHeight);
209
+ if (remaining < 200) {
210
+ tableState.isLoading = true;
211
+ // Lazy append next chunk after a frame to keep UI responsive
212
+ requestAnimationFrame(function () {
213
+ appendTableRows(tableState.pageSize);
214
+ tableState.isLoading = false;
124
215
  });
125
- tbody.appendChild(tr);
126
- });
127
- }
216
+ }
217
+ };
218
+ if (vpTable) vpTable.addEventListener('scroll', tableScrollHandler);
128
219
  }
220
+ function renderTable(data) { setupTableIncrementalRendering(data); }
129
221
 
130
222
  function pretty(obj) {
131
223
  try { return JSON.stringify(obj, null, 2); } catch (e) { return String(obj); }
@@ -186,6 +278,12 @@
186
278
  function writeViewLabels(map) {
187
279
  try { sessionStorage.setItem('studio_view_labels', JSON.stringify(map || {})); } catch (e) { }
188
280
  }
281
+ function readViewTypes() {
282
+ try { return JSON.parse(sessionStorage.getItem('studio_view_types') || '{}'); } catch (e) { return {}; }
283
+ }
284
+ function writeViewTypes(map) {
285
+ try { sessionStorage.setItem('studio_view_types', JSON.stringify(map || {})); } catch (e) { }
286
+ }
189
287
  function currentSourceId() { try { return new URLSearchParams(window.location.search).get('source_id') || ''; } catch (e) { return ''; } }
190
288
  function ensureViewTab(id) {
191
289
  if (!id) return;
@@ -229,6 +327,7 @@
229
327
  var tabs = readViewTabs();
230
328
  var selectedId = currentSourceId();
231
329
  var labels = readViewLabels();
330
+ var types = readViewTypes();
232
331
  function removeViewTab(id) {
233
332
  var list = readViewTabs().filter(function (t) { return t !== id; });
234
333
  writeViewTabs(list);
@@ -256,7 +355,9 @@
256
355
  container.style.cssText = 'display:inline-flex; align-items:center; gap:4px; border:1px solid #e5e7eb; background:' + (id === selectedId ? '#eef2ff' : '#ffffff') + '; color:#111827; padding:2px 4px; border-radius:6px; white-space:nowrap;';
257
356
  var labelBtn = document.createElement('button');
258
357
  var label = (labels && labels[id]) ? String(labels[id]) : ('Source ' + id);
259
- labelBtn.textContent = label;
358
+ var typeForId = (types && types[id]) ? String(types[id]) : '';
359
+ var icon = iconHtmlForType(typeForId);
360
+ labelBtn.innerHTML = icon + '<span>' + label.replace(/</g, '&lt;') + '</span>';
260
361
  labelBtn.title = label;
261
362
  labelBtn.style.cssText = 'background:transparent; border:0; color:inherit; padding:2px 4px; cursor:pointer;';
262
363
  labelBtn.addEventListener('click', function () {
@@ -283,8 +384,9 @@
283
384
  function showError(message) {
284
385
  try {
285
386
  hideAll();
286
- if (vpTextPre) vpTextPre.textContent = String(message || 'Error');
287
- if (vpText) vpText.style.display = 'block';
387
+ var err = document.getElementById('vp_error');
388
+ if (err) { err.textContent = String(message || 'Error'); err.style.display = 'block'; }
389
+ if (vpText) vpText.style.display = 'none';
288
390
  } catch (e) { /* noop */ }
289
391
  }
290
392
  async function loadFromUrl() {
@@ -293,12 +395,13 @@
293
395
  try { if (vpSources) vpSources.style.display = srcId ? 'none' : 'block'; } catch (e) { }
294
396
  if (!srcId) { try { hideAll(); } catch (e) { } return; }
295
397
  try {
296
- var limit = readUrlParam('limit');
297
- var url = '/sources/preview?source_id=' + encodeURIComponent(srcId) + (limit ? ('&limit=' + encodeURIComponent(limit)) : '') + '&verbose=1';
398
+ // Always fetch full preview; render 200 rows first, then lazy-load more client-side
399
+ var url = '/sources/preview?source_id=' + encodeURIComponent(srcId) + '&verbose=1';
298
400
  console.log('[ViewPanel] fetching preview:', url);
299
401
  var r = await fetch(url);
300
402
  var j = await r.json();
301
403
  if (j && j.ok && j.view) {
404
+ var err = document.getElementById('vp_error'); if (err) { err.style.display = 'none'; err.textContent = ''; }
302
405
  if (j.debug) console.log('[ViewPanel] debug:', j.debug);
303
406
  setView(j.view);
304
407
  ensureViewTab(srcId);
@@ -362,7 +465,8 @@
362
465
  card.style.opacity = '0.5';
363
466
  card.style.filter = 'grayscale(100%)';
364
467
  }
365
- card.innerHTML = '<div style="font-weight:600; color:#111827;">' + name + '</div>' +
468
+ var icon = iconHtmlForType(type);
469
+ card.innerHTML = '<div style="font-weight:600; color:#111827; display:flex; align-items:center; gap:6px;">' + icon + '<span>' + name.replace(/</g, '&lt;') + '</span></div>' +
366
470
  '<div class="muted" style="font-size:12px;">' + (type ? ('Type: ' + type) : '') + '</div>' +
367
471
  '<div class="muted" style="font-size:12px;">#' + id + '</div>';
368
472
  if (selectedId && id === selectedId) {
@@ -400,12 +504,16 @@
400
504
  // Build and cache labels map for view tabs
401
505
  try {
402
506
  var labelsMap = readViewLabels();
507
+ var typesMap = readViewTypes();
403
508
  items.forEach(function (it) {
404
509
  var id = String(it.id || it.source_id || '');
405
510
  var name = it.name || (it.source && it.source.name) || ('Source ' + id);
511
+ var type = it.type || (it.source && it.source.type) || '';
406
512
  if (id) labelsMap[id] = String(name);
513
+ if (id) typesMap[id] = String(type);
407
514
  });
408
515
  writeViewLabels(labelsMap);
516
+ writeViewTypes(typesMap);
409
517
  // Re-render tabs to reflect labels instead of IDs
410
518
  try { renderViewTabs(); } catch (e) { }
411
519
  } catch (e) { }
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: qalita
3
- Version: 2.2.8
3
+ Version: 2.3.0
4
4
  Summary: QALITA Platform Command Line Interface
5
+ License-File: LICENSE
5
6
  Author: QALITA SAS
6
7
  Author-email: contact@qalita.io
7
8
  Requires-Python: >=3.10,<4.0
@@ -17,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
17
18
  Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
20
22
  Classifier: Topic :: Software Development :: Quality Assurance
21
23
  Requires-Dist: azure-storage-blob (>=12.19.1,<13.0.0)
22
24
  Requires-Dist: boto3 (>=1.34.81,<2.0.0)
@@ -1,18 +1,18 @@
1
1
  qalita/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- qalita/__main__.py,sha256=NzpokI5DXvS9GY4fxZ_evNZ_6vkfT6Ni9nvnw11_Kbw,2522
2
+ qalita/__main__.py,sha256=mUdL2kKMsr47UP2GIJwBNcDR4yZv-ApcSH-tfcRL03g,2518
3
3
  qalita/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- qalita/commands/agent.py,sha256=wQ3h6THv8W2TvLraeW8xZ1S8sOua-vJaPhA40oISZls,47113
5
- qalita/commands/pack.py,sha256=SPBMpbSCnwmXsCRwZGK_-q2jkZL0DBsDMMtTpVTox8k,39029
6
- qalita/commands/source.py,sha256=q1peZCzd6lX3b3bAJ4M8Te22tjji3qXQ-fyn-JQ3RYM,30945
4
+ qalita/commands/agent.py,sha256=HhgJA3ni6D49xxMMoCJthLYFVR5yYCPEr8GI41Vvfnw,47113
5
+ qalita/commands/pack.py,sha256=xnH-uAnaqMnyVnO7KZ2DNqmd9AgF_j5AgjDE1OnG6d0,39029
6
+ qalita/commands/source.py,sha256=ObRD2CcDynGbMrmj__FhWvPvR0H6HEn5QSLNR8awQUQ,30945
7
7
  qalita/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  qalita/internal/config.py,sha256=P9UU3BH-CIH68-qZjmnk8juzZZ5HJ701hrY6EvrPFOA,4081
9
9
  qalita/internal/error_patterns.py,sha256=QDFNZEoTmqVOHkiGFljstY6VOhux7d4p8FIL3pKzwtQ,1447
10
10
  qalita/internal/logger.py,sha256=4xWy2BZII89nUw4tKrLXFPOlVGONm8KUBgzX2XZ3u7g,1868
11
11
  qalita/internal/request.py,sha256=s-rE9kKRhV9IEveclB2YjAY8FRevKb6qjblM8-PbV20,6209
12
- qalita/internal/utils.py,sha256=bMYH6WnrkMyFyARxoHEkbt4kk7aP-AGBYn1X76i5nkg,5746
12
+ qalita/internal/utils.py,sha256=5Q9P4skA6KKkd4OvIrVH6VPniNud05L-Zr0zt395Nc4,5746
13
13
  qalita/web/__init__.py,sha256=NRcQjZSizkqN0a-LutsN7X9LBQ8MhyazXBSuqzUEmXE,62
14
- qalita/web/app.py,sha256=4srnqeTYsn8PAGcnDDTyjiKcwETNpzlAr20U138LXC8,1323
15
- qalita/web/blueprints/agents.py,sha256=fmOnBRZVvVVMzJtYzWvSP1Q_IcIj4qRDN2n6NrK1K-g,17367
14
+ qalita/web/app.py,sha256=92M2K7vxDIYaI81D-zvdj4VfCsaTTDs6KJZu6dy5s6U,1323
15
+ qalita/web/blueprints/agents.py,sha256=q_SqdSzzHMsstSzEjHGtq75jFt3wQ6p3atjOSzKgiUw,17367
16
16
  qalita/web/blueprints/context.py,sha256=wIcfBtu3l9qwMe5IPa0VQShELsY3ENPt4Q9OO3L8EsE,6451
17
17
  qalita/web/blueprints/dashboard.py,sha256=R_1_oAM-Ol0kx5GZkKTaB8c5vjdz-iIK-SGu2RIHE_w,7454
18
18
  qalita/web/blueprints/helpers.py,sha256=Hnulyrd-YrHoz2LtGCKCq9MgUeoNoNECTyGDap2DFYI,12724
@@ -81,21 +81,21 @@ qalita/web/public/sources-logos/xls.svg,sha256=ckgO7s5pv9numYYFJboxvGQ_P3fLA1zz-
81
81
  qalita/web/public/sources-logos/xlsx.svg,sha256=ckgO7s5pv9numYYFJboxvGQ_P3fLA1zz-2xiERcz2bE,2044
82
82
  qalita/web/public/sources-logos/yugabyte-db.png,sha256=-sGA5gqwSIHlGqk6LHNQ5EogsywwKXiWbKXS3PluYKI,5212
83
83
  qalita/web/public/studio-logo.svg,sha256=NCFJM0rw6XxKcjCJ7bzih1aGudHAjYB1bWUXcF9W19U,620463
84
- qalita/web/public/studio.css,sha256=smR0Pyofp8m8Zm7M6CMl63DHe2yO_Nt-lXL0B1ppHZY,4983
84
+ qalita/web/public/studio.css,sha256=bHWyfPUbtYU8jDUKepNY6K0Am4qeG7ewQ_nnKnh4M6M,5060
85
85
  qalita/web/public/studio.png,sha256=9kLYN5c8nqK7TKT8UHjfPSKBI60zDFsIcYFbWw3cVfY,461702
86
86
  qalita/web/public/styles.css,sha256=xmy_c0fmUKBEgPF2L_qrQ2eC1erw-zcAndpMQMjHJbM,10486
87
- qalita/web/templates/dashboard.html,sha256=I3oQz8nlHCAvoH4cZdfZESig_bWeESuzWkY6R77gJ40,17045
88
- qalita/web/templates/navbar.html,sha256=j3w3t60Qtg3D53EQ9RHXcEz226Sorkd4SNNJ795q9po,1916
89
- qalita/web/templates/sources/added.html,sha256=kQ37fVzv4mjLDQmJwBhZ81zf-89ZYXNsKz6Vglmr5Rs,1938
90
- qalita/web/templates/sources/edit.html,sha256=LzsgUa6NWAHfF7lOB7utbFT3hw_9brEQKZiK0R2J-TI,19723
91
- qalita/web/templates/sources/select-source.html,sha256=2lEbV2XLybv9wvolEblSC12PAlth-9ms87Xz9X0wwxI,6179
87
+ qalita/web/templates/dashboard.html,sha256=pAuWMRaSjInqNitecf4mkI2eX-UeqpC37Jbc_tGCeuk,17045
88
+ qalita/web/templates/navbar.html,sha256=W0eBuH_vrs4GyxkSzxsppOchkgtvnKM-uc07mP5mkdA,1916
89
+ qalita/web/templates/sources/added.html,sha256=uTu5jofRi9t9pvWRnc9AtD9B396DvnqDo6HoajVU3DA,1938
90
+ qalita/web/templates/sources/edit.html,sha256=DM5i3Y__MMG0PzJm--OXQSo5PbI4fcRo4UYHm2qGMxA,19723
91
+ qalita/web/templates/sources/select-source.html,sha256=dBTEpCu8KTjmiOG_gBIUFEdGAnGmnV8EFQid7chsVA0,6179
92
92
  qalita/web/templates/studio/agent-panel.html,sha256=cc_zcUgkQHwxBz2_Nkvw3BCO3L_zhQDcrnp0woMwI_A,38790
93
- qalita/web/templates/studio/context-panel.html,sha256=Ha2-lBKGRXgJuK2TJzy49CpN3v-5oiYN0CBkWhpOwoE,14324
94
- qalita/web/templates/studio/index.html,sha256=ixnrVLf2xKZ6WI7wqNmPiGaUGBs1nFmeZvgwwCXT_B8,2805
95
- qalita/web/templates/studio/navbar.html,sha256=khOQq7Por2aGWNA5Dspgx7xoXXfEU3Hnen0pXBRyOHY,746
96
- qalita/web/templates/studio/view-panel.html,sha256=RUn12jBOV6D771UWDNljiUy_VPWjhy0tbiWTbGxoeng,18581
97
- qalita-2.2.8.dist-info/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
98
- qalita-2.2.8.dist-info/METADATA,sha256=QKNEnP9J8qRTLm2SwgIQ2URxwkZnhuiq1WSVv2hzk2A,2339
99
- qalita-2.2.8.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
100
- qalita-2.2.8.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
101
- qalita-2.2.8.dist-info/RECORD,,
93
+ qalita/web/templates/studio/context-panel.html,sha256=M8yfYcJQ_2WSwnOLlCTQETzctzL-rjlKLF7PlAUV0PU,15312
94
+ qalita/web/templates/studio/index.html,sha256=NI7zF-4cHQ3id-a_R3GNQ8gQ2Bw4A6liyEZ53AO0QOU,2823
95
+ qalita/web/templates/studio/navbar.html,sha256=IQZ7TFOXv3r5yZmP9f1v7BMUCQU8mOajMV82UPeY3cg,746
96
+ qalita/web/templates/studio/view-panel.html,sha256=JREfFIabpuAZctAzbE_mT_ZDk65MBWevjRNxQUrO8Pw,25198
97
+ qalita-2.3.0.dist-info/METADATA,sha256=KFd1LHzaTXeRvTkC2GgwBUvn8ZWfkaXyJMQtwl_hbrE,2412
98
+ qalita-2.3.0.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
99
+ qalita-2.3.0.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
100
+ qalita-2.3.0.dist-info/licenses/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
101
+ qalita-2.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any