qalita 2.2.9__py3-none-any.whl → 2.3.1__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 +3 -3
- qalita/commands/agent.py +99 -11
- qalita/commands/pack.py +122 -149
- qalita/commands/source.py +4 -4
- qalita/internal/utils.py +1 -1
- qalita/web/app.py +2 -2
- qalita/web/blueprints/agents.py +3 -3
- qalita/web/templates/dashboard.html +4 -4
- qalita/web/templates/navbar.html +1 -1
- qalita/web/templates/sources/added.html +2 -2
- qalita/web/templates/sources/edit.html +2 -2
- qalita/web/templates/sources/select-source.html +3 -3
- qalita/web/templates/studio/context-panel.html +1 -1
- qalita/web/templates/studio/index.html +1 -1
- qalita/web/templates/studio/navbar.html +1 -1
- {qalita-2.2.9.dist-info → qalita-2.3.1.dist-info}/METADATA +4 -2
- {qalita-2.2.9.dist-info → qalita-2.3.1.dist-info}/RECORD +20 -20
- {qalita-2.2.9.dist-info → qalita-2.3.1.dist-info}/WHEEL +1 -1
- {qalita-2.2.9.dist-info → qalita-2.3.1.dist-info}/entry_points.txt +0 -0
- {qalita-2.2.9.dist-info → qalita-2.3.1.dist-info/licenses}/LICENSE +0 -0
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
|
-
------------------
|
|
41
|
-
Hello and thanks for using
|
|
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
|
|
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
|
|
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
|
|
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"
|
|
360
|
-
logger.info(f"
|
|
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
|
)
|
|
@@ -465,6 +465,9 @@ def run(
|
|
|
465
465
|
# check routines before checking jobs
|
|
466
466
|
check_routines(config, agent_start_datetime)
|
|
467
467
|
|
|
468
|
+
# try to claim one pending unassigned job compatible with this agent
|
|
469
|
+
claim_unassigned_jobs(config)
|
|
470
|
+
|
|
468
471
|
check_job = send_api_request(
|
|
469
472
|
request=f'/api/v1/agents/{agent_conf["context"]["remote"]["id"]}/jobs/next',
|
|
470
473
|
mode="get",
|
|
@@ -874,7 +877,7 @@ def post_run(
|
|
|
874
877
|
## LOGS
|
|
875
878
|
# Initialize logs_id to None
|
|
876
879
|
logs_id = None
|
|
877
|
-
logger.info(f"Uploading logs to
|
|
880
|
+
logger.info(f"Uploading logs to QALITA Platform...")
|
|
878
881
|
logger.info(f"run_path: {run_path}")
|
|
879
882
|
if os.path.exists(run_path + "/logs.txt"):
|
|
880
883
|
api_url = agent_conf["context"]["local"]["url"]
|
|
@@ -912,12 +915,12 @@ def post_run(
|
|
|
912
915
|
else:
|
|
913
916
|
logger.info(f"No logs.txt file found")
|
|
914
917
|
|
|
915
|
-
logger.info(f"Uploading results to
|
|
918
|
+
logger.info(f"Uploading results to QALITA Platform...")
|
|
916
919
|
|
|
917
920
|
#########################################################
|
|
918
921
|
## Recommendations
|
|
919
922
|
if os.path.exists(run_path + "/recommendations.json"):
|
|
920
|
-
logger.info(f"\tUploading recommendations to
|
|
923
|
+
logger.info(f"\tUploading recommendations to QALITA Platform...")
|
|
921
924
|
|
|
922
925
|
api_url = agent_conf["context"]["local"]["url"]
|
|
923
926
|
registry_id = agent_conf["registries"][0]["id"]
|
|
@@ -949,7 +952,7 @@ def post_run(
|
|
|
949
952
|
#########################################################
|
|
950
953
|
## Schemas
|
|
951
954
|
if os.path.exists(run_path + "/schemas.json"):
|
|
952
|
-
logger.info(f"\tUploading schemas to
|
|
955
|
+
logger.info(f"\tUploading schemas to QALITA Platform...")
|
|
953
956
|
|
|
954
957
|
api_url = agent_conf["context"]["local"]["url"]
|
|
955
958
|
registry_id = agent_conf["registries"][0]["id"]
|
|
@@ -981,7 +984,7 @@ def post_run(
|
|
|
981
984
|
#########################################################
|
|
982
985
|
## Metrics
|
|
983
986
|
if os.path.exists(run_path + "/metrics.json"):
|
|
984
|
-
logger.info(f"\tUploading Metrics to
|
|
987
|
+
logger.info(f"\tUploading Metrics to QALITA Platform...")
|
|
985
988
|
|
|
986
989
|
api_url = agent_conf["context"]["local"]["url"]
|
|
987
990
|
registry_id = agent_conf["registries"][0]["id"]
|
|
@@ -1066,7 +1069,6 @@ def create_scheduled_job(routine, agent_conf):
|
|
|
1066
1069
|
request=f"/api/v2/jobs/create",
|
|
1067
1070
|
mode="post",
|
|
1068
1071
|
data={
|
|
1069
|
-
"agent_id": agent_conf["context"]["remote"]["id"],
|
|
1070
1072
|
"source_id": routine["source"]["id"],
|
|
1071
1073
|
"target_id": routine["target"]["id"] if routine.get("target") else None,
|
|
1072
1074
|
"pack_id": routine["pack"]["id"],
|
|
@@ -1238,3 +1240,89 @@ def check_routines(config, agent_start_datetime):
|
|
|
1238
1240
|
ROUTINE_LAST_SCHEDULED_UTC[routine.get("id")] = datetime.now(timezone.utc)
|
|
1239
1241
|
else:
|
|
1240
1242
|
logger.warning("Can't fetch routines or jobs from the platform")
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
def claim_unassigned_jobs(config):
|
|
1246
|
+
"""Claim one pending unassigned job that this agent can execute.
|
|
1247
|
+
|
|
1248
|
+
Strategy:
|
|
1249
|
+
- Fetch all jobs (v2)
|
|
1250
|
+
- Select first job with status == pending and no agent assigned
|
|
1251
|
+
- Check local capability: source (and target if provided) must exist locally
|
|
1252
|
+
- PUT to assign agent_id to this agent; on success, run job
|
|
1253
|
+
- On contention (another agent already claimed), ignore and return
|
|
1254
|
+
"""
|
|
1255
|
+
try:
|
|
1256
|
+
source_conf = config.load_source_config(verbose=False)
|
|
1257
|
+
agent_conf = config.load_agent_config()
|
|
1258
|
+
local_source_ids = [s["id"] for s in source_conf["sources"] if "id" in s]
|
|
1259
|
+
|
|
1260
|
+
r = send_api_request(
|
|
1261
|
+
request=f"/api/v2/jobs",
|
|
1262
|
+
mode="get",
|
|
1263
|
+
)
|
|
1264
|
+
if r.status_code not in [200, 204]:
|
|
1265
|
+
return
|
|
1266
|
+
jobs = r.json()
|
|
1267
|
+
if not isinstance(jobs, list):
|
|
1268
|
+
return
|
|
1269
|
+
|
|
1270
|
+
def extract_id(maybe_obj, fallback_key):
|
|
1271
|
+
if isinstance(maybe_obj, dict):
|
|
1272
|
+
return maybe_obj.get("id")
|
|
1273
|
+
return maybe_obj if isinstance(maybe_obj, int) else None
|
|
1274
|
+
|
|
1275
|
+
for job in jobs:
|
|
1276
|
+
try:
|
|
1277
|
+
if job.get("status") != "pending":
|
|
1278
|
+
continue
|
|
1279
|
+
# unassigned: support either agent_id field or nested agent object
|
|
1280
|
+
is_unassigned = (
|
|
1281
|
+
(job.get("agent_id") is None or job.get("agent_id") == 0)
|
|
1282
|
+
and not job.get("agent")
|
|
1283
|
+
)
|
|
1284
|
+
if not is_unassigned:
|
|
1285
|
+
continue
|
|
1286
|
+
|
|
1287
|
+
src_id = extract_id(job.get("source"), "source_id") or job.get("source_id")
|
|
1288
|
+
if src_id not in local_source_ids:
|
|
1289
|
+
continue
|
|
1290
|
+
tgt_id = extract_id(job.get("target"), "target_id") or job.get("target_id")
|
|
1291
|
+
if tgt_id is not None and tgt_id not in local_source_ids:
|
|
1292
|
+
continue
|
|
1293
|
+
|
|
1294
|
+
# attempt to claim
|
|
1295
|
+
claim_resp = send_api_request(
|
|
1296
|
+
request=f"/api/v2/jobs/{job['id']}",
|
|
1297
|
+
mode="put",
|
|
1298
|
+
data={
|
|
1299
|
+
"agent_id": agent_conf["context"]["remote"]["id"],
|
|
1300
|
+
},
|
|
1301
|
+
)
|
|
1302
|
+
if claim_resp.status_code != 200:
|
|
1303
|
+
# likely contention: someone else claimed
|
|
1304
|
+
continue
|
|
1305
|
+
|
|
1306
|
+
# extract version ids if present
|
|
1307
|
+
src_ver_id = extract_id(job.get("source_version"), "source_version_id") or job.get("source_version_id")
|
|
1308
|
+
tgt_ver_id = extract_id(job.get("target_version"), "target_version_id") or job.get("target_version_id")
|
|
1309
|
+
pack_id = extract_id(job.get("pack"), "pack_id") or job.get("pack_id")
|
|
1310
|
+
pack_ver_id = extract_id(job.get("pack_version"), "pack_version_id") or job.get("pack_version_id")
|
|
1311
|
+
|
|
1312
|
+
logger.info(f"Claimed unassigned job {job['id']} for source {src_id} pack {pack_id}")
|
|
1313
|
+
job_run(
|
|
1314
|
+
src_id,
|
|
1315
|
+
src_ver_id,
|
|
1316
|
+
tgt_id,
|
|
1317
|
+
tgt_ver_id,
|
|
1318
|
+
pack_id,
|
|
1319
|
+
pack_ver_id,
|
|
1320
|
+
job=job,
|
|
1321
|
+
)
|
|
1322
|
+
# claim and run only one per loop
|
|
1323
|
+
return
|
|
1324
|
+
except Exception as _:
|
|
1325
|
+
# Be resilient; don't break the worker loop on any unexpected job shape
|
|
1326
|
+
continue
|
|
1327
|
+
except Exception as _:
|
|
1328
|
+
return
|
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
|
|
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
|
|
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
|
|
@@ -586,20 +586,37 @@ def publish_new_pack_version(api_url, pack_id, pack_version, registry_id, pack_n
|
|
|
586
586
|
source_dir=source_dir,
|
|
587
587
|
config=config,
|
|
588
588
|
)
|
|
589
|
-
# Best-effort: also update
|
|
589
|
+
# Best-effort: also update metadata (avatar, description, url, visibility, config, readme)
|
|
590
|
+
# and compatibility if provided in properties.yaml so the new version push also refreshes pack details.
|
|
590
591
|
try:
|
|
591
592
|
pack_dir = source_dir or f"./{pack_name}_pack"
|
|
592
593
|
props = load_pack_properties(pack_dir) or {}
|
|
594
|
+
pack_icon = load_base64_encoded_image(os.path.join(pack_dir, "icon.png"))
|
|
595
|
+
readme = load_base64_encoded_text(os.path.join(pack_dir, "README.md"))
|
|
596
|
+
pack_config = load_json_config(os.path.join(pack_dir, "pack_conf.json"))
|
|
597
|
+
pack_type = props.get("type", "")
|
|
598
|
+
pack_description = props.get("description", "")
|
|
599
|
+
pack_url = props.get("url", "")
|
|
600
|
+
pack_visibility = props.get("visibility", "private")
|
|
593
601
|
compat = props.get("compatible_sources")
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
+
|
|
603
|
+
# Update full metadata
|
|
604
|
+
update_pack_metadata(
|
|
605
|
+
api_url,
|
|
606
|
+
pack_id,
|
|
607
|
+
pack_icon,
|
|
608
|
+
pack_config,
|
|
609
|
+
pack_type,
|
|
610
|
+
pack_description,
|
|
611
|
+
pack_url,
|
|
612
|
+
pack_version,
|
|
613
|
+
pack_visibility,
|
|
614
|
+
readme,
|
|
615
|
+
compatible_sources=compat,
|
|
616
|
+
config=config,
|
|
617
|
+
)
|
|
602
618
|
except Exception:
|
|
619
|
+
# Non-fatal if metadata refresh fails; continue to publish version
|
|
603
620
|
pass
|
|
604
621
|
publish_response = _request_with_optional_config(
|
|
605
622
|
config,
|
|
@@ -689,11 +706,89 @@ def handle_version_matching(existing_versions, new_version):
|
|
|
689
706
|
return None
|
|
690
707
|
|
|
691
708
|
|
|
709
|
+
def _push_with_context(agent_conf, pack_properties, pack_directory, config):
|
|
710
|
+
"""Shared push routine used by CLI and Web UI.
|
|
711
|
+
|
|
712
|
+
Expects absolute or relative `pack_directory` and a loaded `pack_properties` dict.
|
|
713
|
+
"""
|
|
714
|
+
# Extract pack details
|
|
715
|
+
pack_name = pack_properties.get("name")
|
|
716
|
+
pack_version = pack_properties.get("version")
|
|
717
|
+
pack_description = pack_properties.get("description", "")
|
|
718
|
+
pack_url = pack_properties.get("url", "")
|
|
719
|
+
pack_type = pack_properties.get("type", "")
|
|
720
|
+
pack_visibility = pack_properties.get("visibility", "private")
|
|
721
|
+
|
|
722
|
+
# Handle pack icon and README/config
|
|
723
|
+
pack_icon = load_base64_encoded_image(os.path.join(pack_directory, "icon.png"))
|
|
724
|
+
readme = load_base64_encoded_text(os.path.join(pack_directory, "README.md"))
|
|
725
|
+
pack_config = load_json_config(os.path.join(pack_directory, "pack_conf.json"))
|
|
726
|
+
|
|
727
|
+
# Check existing packs and versions
|
|
728
|
+
pack_id, existing_versions = find_existing_pack(
|
|
729
|
+
agent_conf["context"]["local"]["url"], pack_name, config=config
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
if pack_id:
|
|
733
|
+
new_version_entry = handle_version_matching(existing_versions, pack_version)
|
|
734
|
+
if not new_version_entry:
|
|
735
|
+
# Try to load compatible_sources from properties.yaml (optional)
|
|
736
|
+
compat = (
|
|
737
|
+
pack_properties.get("compatible_sources")
|
|
738
|
+
if isinstance(pack_properties, dict)
|
|
739
|
+
else None
|
|
740
|
+
)
|
|
741
|
+
update_pack_metadata(
|
|
742
|
+
agent_conf["context"]["local"]["url"],
|
|
743
|
+
pack_id,
|
|
744
|
+
pack_icon,
|
|
745
|
+
pack_config,
|
|
746
|
+
pack_type,
|
|
747
|
+
pack_description,
|
|
748
|
+
pack_url,
|
|
749
|
+
pack_version,
|
|
750
|
+
pack_visibility,
|
|
751
|
+
readme,
|
|
752
|
+
compatible_sources=compat,
|
|
753
|
+
config=config,
|
|
754
|
+
)
|
|
755
|
+
logger.success(
|
|
756
|
+
"Pack metadata updated successfully ! \nIf you wanted to upload a new pack version, you must change the pack [version] attribute in properties.yaml"
|
|
757
|
+
)
|
|
758
|
+
else:
|
|
759
|
+
publish_new_pack_version(
|
|
760
|
+
agent_conf["context"]["local"]["url"],
|
|
761
|
+
pack_id,
|
|
762
|
+
pack_version,
|
|
763
|
+
agent_conf["registries"][0]["id"],
|
|
764
|
+
pack_name,
|
|
765
|
+
source_dir=pack_directory,
|
|
766
|
+
config=config,
|
|
767
|
+
)
|
|
768
|
+
else:
|
|
769
|
+
create_new_pack(
|
|
770
|
+
agent_conf["context"]["local"]["url"],
|
|
771
|
+
agent_conf["registries"][0]["id"],
|
|
772
|
+
pack_name,
|
|
773
|
+
pack_icon,
|
|
774
|
+
pack_config,
|
|
775
|
+
pack_type,
|
|
776
|
+
pack_description,
|
|
777
|
+
pack_url,
|
|
778
|
+
pack_version,
|
|
779
|
+
pack_visibility,
|
|
780
|
+
readme,
|
|
781
|
+
source_dir=pack_directory,
|
|
782
|
+
config=config,
|
|
783
|
+
)
|
|
784
|
+
logger.success("New pack created successfully!")
|
|
785
|
+
|
|
786
|
+
|
|
692
787
|
@pack.command()
|
|
693
788
|
@click.option("-n", "--name", help="Name of the package", envvar="QALITA_PACK_NAME")
|
|
694
789
|
@pass_config
|
|
695
790
|
def push(config, name):
|
|
696
|
-
"""Pushes a package to the
|
|
791
|
+
"""Pushes a package to the QALITA Platform"""
|
|
697
792
|
|
|
698
793
|
try:
|
|
699
794
|
name = check_name(name)
|
|
@@ -709,7 +804,7 @@ def push(config, name):
|
|
|
709
804
|
return
|
|
710
805
|
|
|
711
806
|
logger.info("---------------- Pack Push ----------------")
|
|
712
|
-
logger.info(f"Pushing pack '{name}' to
|
|
807
|
+
logger.info(f"Pushing pack '{name}' to QALITA Platform...")
|
|
713
808
|
|
|
714
809
|
pack_directory = f"./{name}_pack" if not name.endswith("_pack") else f"./{name}"
|
|
715
810
|
|
|
@@ -725,78 +820,14 @@ def push(config, name):
|
|
|
725
820
|
logger.error("Failed to load agent configuration.")
|
|
726
821
|
return
|
|
727
822
|
|
|
728
|
-
#
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
pack_visibility = pack_properties.get("visibility", "private")
|
|
735
|
-
|
|
736
|
-
# Handle pack icon
|
|
737
|
-
pack_icon = load_base64_encoded_image(f"{pack_directory}/icon.png")
|
|
738
|
-
|
|
739
|
-
# Handle README file
|
|
740
|
-
readme = load_base64_encoded_text(f"{pack_directory}/README.md")
|
|
741
|
-
|
|
742
|
-
# Load pack config
|
|
743
|
-
pack_config = load_json_config(f"{pack_directory}/pack_conf.json")
|
|
744
|
-
|
|
745
|
-
# Check existing packs and versions
|
|
746
|
-
pack_id, existing_versions = find_existing_pack(
|
|
747
|
-
agent_conf["context"]["local"]["url"], pack_name, config=config
|
|
823
|
+
# Shared push routine
|
|
824
|
+
_push_with_context(
|
|
825
|
+
agent_conf,
|
|
826
|
+
pack_properties,
|
|
827
|
+
os.path.abspath(pack_directory),
|
|
828
|
+
config,
|
|
748
829
|
)
|
|
749
830
|
|
|
750
|
-
if pack_id:
|
|
751
|
-
# Handle version matching and decide whether to add a new asset or update metadata
|
|
752
|
-
new_version_entry = handle_version_matching(existing_versions, pack_version)
|
|
753
|
-
|
|
754
|
-
if not new_version_entry:
|
|
755
|
-
# Try to load compatible_sources from properties.yaml (optional)
|
|
756
|
-
compat = pack_properties.get("compatible_sources") if isinstance(pack_properties, dict) else None
|
|
757
|
-
update_pack_metadata(
|
|
758
|
-
agent_conf["context"]["local"]["url"],
|
|
759
|
-
pack_id,
|
|
760
|
-
pack_icon,
|
|
761
|
-
pack_config,
|
|
762
|
-
pack_type,
|
|
763
|
-
pack_description,
|
|
764
|
-
pack_url,
|
|
765
|
-
pack_version,
|
|
766
|
-
pack_visibility,
|
|
767
|
-
readme,
|
|
768
|
-
compatible_sources=compat,
|
|
769
|
-
config=config,
|
|
770
|
-
)
|
|
771
|
-
logger.success("Pack metadata updated successfully ! \nIf you wanted to upload a new pack version, you must change the pack [version] attribute in properties.yaml")
|
|
772
|
-
else:
|
|
773
|
-
publish_new_pack_version(
|
|
774
|
-
agent_conf["context"]["local"]["url"],
|
|
775
|
-
pack_id,
|
|
776
|
-
pack_version,
|
|
777
|
-
agent_conf["registries"][0]["id"],
|
|
778
|
-
pack_name,
|
|
779
|
-
source_dir=os.path.abspath(pack_directory),
|
|
780
|
-
config=config,
|
|
781
|
-
)
|
|
782
|
-
else:
|
|
783
|
-
create_new_pack(
|
|
784
|
-
agent_conf["context"]["local"]["url"],
|
|
785
|
-
agent_conf["registries"][0]["id"],
|
|
786
|
-
pack_name,
|
|
787
|
-
pack_icon,
|
|
788
|
-
pack_config,
|
|
789
|
-
pack_type,
|
|
790
|
-
pack_description,
|
|
791
|
-
pack_url,
|
|
792
|
-
pack_version,
|
|
793
|
-
pack_visibility,
|
|
794
|
-
readme,
|
|
795
|
-
source_dir=os.path.abspath(pack_directory),
|
|
796
|
-
config=config,
|
|
797
|
-
)
|
|
798
|
-
logger.success("New pack created successfully!")
|
|
799
|
-
|
|
800
831
|
logger.info("Pack pushed successfully.")
|
|
801
832
|
|
|
802
833
|
except Exception as e:
|
|
@@ -842,72 +873,14 @@ def push_from_directory(config, pack_directory):
|
|
|
842
873
|
logger.error(msg)
|
|
843
874
|
return False, msg
|
|
844
875
|
|
|
845
|
-
#
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
pack_visibility = pack_properties.get("visibility", "private")
|
|
852
|
-
|
|
853
|
-
# Handle pack icon and README
|
|
854
|
-
pack_icon = load_base64_encoded_image(os.path.join(pack_directory, "icon.png"))
|
|
855
|
-
readme = load_base64_encoded_text(os.path.join(pack_directory, "README.md"))
|
|
856
|
-
pack_config = load_json_config(os.path.join(pack_directory, "pack_conf.json"))
|
|
857
|
-
|
|
858
|
-
# Check existing packs and versions
|
|
859
|
-
pack_id, existing_versions = find_existing_pack(
|
|
860
|
-
agent_conf["context"]["local"]["url"], pack_name, config=config
|
|
876
|
+
# Shared push routine
|
|
877
|
+
_push_with_context(
|
|
878
|
+
agent_conf,
|
|
879
|
+
pack_properties,
|
|
880
|
+
pack_directory,
|
|
881
|
+
config,
|
|
861
882
|
)
|
|
862
883
|
|
|
863
|
-
if pack_id:
|
|
864
|
-
new_version_entry = handle_version_matching(existing_versions, pack_version)
|
|
865
|
-
if not new_version_entry:
|
|
866
|
-
# Try to load compatible_sources from properties.yaml (optional)
|
|
867
|
-
compat = pack_properties.get("compatible_sources") if isinstance(pack_properties, dict) else None
|
|
868
|
-
update_pack_metadata(
|
|
869
|
-
agent_conf["context"]["local"]["url"],
|
|
870
|
-
pack_id,
|
|
871
|
-
pack_icon,
|
|
872
|
-
pack_config,
|
|
873
|
-
pack_type,
|
|
874
|
-
pack_description,
|
|
875
|
-
pack_url,
|
|
876
|
-
pack_version,
|
|
877
|
-
pack_visibility,
|
|
878
|
-
readme,
|
|
879
|
-
compatible_sources=compat,
|
|
880
|
-
config=config,
|
|
881
|
-
)
|
|
882
|
-
logger.success("Pack metadata updated successfully ! \nIf you wanted to upload a new pack version, you must change the pack [version] attribute in properties.yaml")
|
|
883
|
-
else:
|
|
884
|
-
publish_new_pack_version(
|
|
885
|
-
agent_conf["context"]["local"]["url"],
|
|
886
|
-
pack_id,
|
|
887
|
-
pack_version,
|
|
888
|
-
agent_conf["registries"][0]["id"],
|
|
889
|
-
pack_name,
|
|
890
|
-
source_dir=pack_directory,
|
|
891
|
-
config=config,
|
|
892
|
-
)
|
|
893
|
-
else:
|
|
894
|
-
create_new_pack(
|
|
895
|
-
agent_conf["context"]["local"]["url"],
|
|
896
|
-
agent_conf["registries"][0]["id"],
|
|
897
|
-
pack_name,
|
|
898
|
-
pack_icon,
|
|
899
|
-
pack_config,
|
|
900
|
-
pack_type,
|
|
901
|
-
pack_description,
|
|
902
|
-
pack_url,
|
|
903
|
-
pack_version,
|
|
904
|
-
pack_visibility,
|
|
905
|
-
readme,
|
|
906
|
-
source_dir=pack_directory,
|
|
907
|
-
config=config,
|
|
908
|
-
)
|
|
909
|
-
logger.success("New pack created successfully!")
|
|
910
|
-
|
|
911
884
|
logger.info("Pack pushed successfully.")
|
|
912
885
|
return True, "Pack pushed successfully."
|
|
913
886
|
except Exception as e:
|
|
@@ -920,7 +893,7 @@ def push_from_directory(config, pack_directory):
|
|
|
920
893
|
@click.option(
|
|
921
894
|
"-n",
|
|
922
895
|
"--name",
|
|
923
|
-
help="The name of the package, it will be used to identify the package in the
|
|
896
|
+
help="The name of the package, it will be used to identify the package in the QALITA platform",
|
|
924
897
|
envvar="QALITA_PACK_NAME",
|
|
925
898
|
)
|
|
926
899
|
def run(name):
|
|
@@ -969,7 +942,7 @@ def run(name):
|
|
|
969
942
|
@click.option(
|
|
970
943
|
"-n",
|
|
971
944
|
"--name",
|
|
972
|
-
help="The name of the package, it will be used to identify the package in the
|
|
945
|
+
help="The name of the package, it will be used to identify the package in the QALITA platform",
|
|
973
946
|
envvar="QALITA_PACK_NAME",
|
|
974
947
|
)
|
|
975
948
|
@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
|
|
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
|
|
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
|
|
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
|
|
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
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
|
|
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"
|
|
39
|
+
print(f"QALITA CLI UI is running. Open {url}")
|
|
40
40
|
serve(app, host=host, port=port)
|
qalita/web/blueprints/agents.py
CHANGED
|
@@ -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>© QALITA</span> —
|
|
378
|
+
<span>© 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>© QALITA</span> —
|
|
414
|
+
<span>© 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>© QALITA</span> —
|
|
454
|
+
<span>© QALITA</span> — QALITA CLI
|
|
455
455
|
</div>
|
|
456
456
|
<div>
|
|
457
457
|
<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>
|
|
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
|
|
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;">
|
|
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>© QALITA</span> —
|
|
325
|
+
<span>© QALITA</span> — QALITA CLI
|
|
326
326
|
</div>
|
|
327
327
|
<div>
|
|
328
328
|
<span id="cli_version"></span>
|
qalita/web/templates/navbar.html
CHANGED
|
@@ -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="
|
|
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>
|
|
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>© QALITA</span> —
|
|
39
|
+
<span>© 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>
|
|
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>© QALITA</span> —
|
|
396
|
+
<span>© 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>
|
|
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%
|
|
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>© QALITA</span> —
|
|
111
|
+
<span>© QALITA</span> — QALITA CLI
|
|
112
112
|
</div>
|
|
113
113
|
<div>
|
|
114
114
|
<span id="cli_version"></span>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<div>
|
|
19
19
|
<div class="studio-setup-title">Setup platform</div>
|
|
20
20
|
<div class="studio-setup-text">
|
|
21
|
-
Your current context doesn't provide
|
|
21
|
+
Your current context doesn't provide QALITA platform credentials.<br><br>
|
|
22
22
|
To use contextual data quality metadata, configure your Platform endpoint and token.
|
|
23
23
|
</div>
|
|
24
24
|
<div class="studio-setup-actions">
|
|
@@ -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>
|
|
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" />
|
|
@@ -2,7 +2,7 @@
|
|
|
2
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
|
|
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"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: qalita
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.1
|
|
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=
|
|
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=
|
|
5
|
-
qalita/commands/pack.py,sha256=
|
|
6
|
-
qalita/commands/source.py,sha256=
|
|
4
|
+
qalita/commands/agent.py,sha256=t4SzLnAOsthAeNU2DCmWEkOexKQb2QQ1xhEzazyMdeM,50660
|
|
5
|
+
qalita/commands/pack.py,sha256=Eu1h-JJEtUBqr6OKPnwE8EuJOQcHpJtZBvKe0XFQaDg,37224
|
|
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=
|
|
12
|
+
qalita/internal/utils.py,sha256=UIXH_BS2ZiP0crARISYHuJMnvajaTSHchpXoP_sZXXs,5746
|
|
13
13
|
qalita/web/__init__.py,sha256=NRcQjZSizkqN0a-LutsN7X9LBQ8MhyazXBSuqzUEmXE,62
|
|
14
|
-
qalita/web/app.py,sha256=
|
|
15
|
-
qalita/web/blueprints/agents.py,sha256=
|
|
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
|
|
@@ -84,18 +84,18 @@ qalita/web/public/studio-logo.svg,sha256=NCFJM0rw6XxKcjCJ7bzih1aGudHAjYB1bWUXcF9
|
|
|
84
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=
|
|
88
|
-
qalita/web/templates/navbar.html,sha256=
|
|
89
|
-
qalita/web/templates/sources/added.html,sha256=
|
|
90
|
-
qalita/web/templates/sources/edit.html,sha256=
|
|
91
|
-
qalita/web/templates/sources/select-source.html,sha256=
|
|
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=
|
|
94
|
-
qalita/web/templates/studio/index.html,sha256=
|
|
95
|
-
qalita/web/templates/studio/navbar.html,sha256
|
|
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
96
|
qalita/web/templates/studio/view-panel.html,sha256=JREfFIabpuAZctAzbE_mT_ZDk65MBWevjRNxQUrO8Pw,25198
|
|
97
|
-
qalita-2.
|
|
98
|
-
qalita-2.
|
|
99
|
-
qalita-2.
|
|
100
|
-
qalita-2.
|
|
101
|
-
qalita-2.
|
|
97
|
+
qalita-2.3.1.dist-info/METADATA,sha256=q5Rw3NHpPohDXswrcEnGPTXDc5-GwrtbCMvlOtx1_EY,2412
|
|
98
|
+
qalita-2.3.1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
|
|
99
|
+
qalita-2.3.1.dist-info/entry_points.txt,sha256=RxEByZDKtsRrsDauuINx9XMVP6k26B_CglUmtH206Qo,47
|
|
100
|
+
qalita-2.3.1.dist-info/licenses/LICENSE,sha256=cZt92dnxw87-VK4HB6KnmYV7mpf4JUdBkAHzFn1kQxM,22458
|
|
101
|
+
qalita-2.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|