tg-prepare 1.0.0__py3-none-any.whl → 1.1.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.

Potentially problematic release.


This version of tg-prepare might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tg_prepare
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Simple UI to handle TextGrid imports visually.
5
5
  Author: Ralf Klammer, Moritz Wilhelm
6
6
  Author-email: ralf.klammer@tu-dresden.de, moritz.wilhelm@tu-dresden.de
@@ -1,46 +1,39 @@
1
- tg_prepare-1.0.0.dist-info/licenses/LICENSE,sha256=deYu6g1OGKm0VUwhM4Octoh8qlzjsiHHxoI-KkCBVBE,11351
1
+ tg_prepare-1.1.0.dist-info/licenses/LICENSE,sha256=deYu6g1OGKm0VUwhM4Octoh8qlzjsiHHxoI-KkCBVBE,11351
2
2
  tgp_backend/__init__.py,sha256=4Q_pjhWDF2eAyPa8bvgIcBIrV0qGKa3uYgvYqTCmKWs,419
3
3
  tgp_backend/auth.py,sha256=hUPd0rc01BTT003xpkdmhNc6o0JztbAdimyDb0B9oTQ,2293
4
4
  tgp_backend/cli.py,sha256=iw_gknn-_m_UFZZUKfkV9aJixG3sVcHIONybNtOG40I,551
5
- tgp_backend/directories.py,sha256=CjrrBOL3Hov0b5SyyPRtMfmfcb3cSsLnTpBGJcI5Dto,2564
5
+ tgp_backend/directories.py,sha256=5w7FeEa0zcW4B_rkM0bLlaKdWUPrvtremlkgcU5W6dA,2385
6
6
  tgp_backend/interfaces.py,sha256=SO7mOdhkd1f7irUBrwFhp5aKx3UKkkUzU9QBYDl0Tvc,91
7
7
  tgp_backend/nextcloud.py,sha256=9p-YT-oN05seWo2zwnfHSbvVa4Am7qONczfR6Fx8pqM,4424
8
- tgp_backend/project.py,sha256=yesTH2eHDJsSmBB4SLE12PAkGE4LdgatgPpAxVraWEk,8877
9
- tgp_backend/tgclient.py,sha256=DXqUQcTT6nwBPzkA3_Nl49bJtLiO-V8kGAI2f46hWiY,2980
8
+ tgp_backend/project.py,sha256=Lsxvy8DTalHqgTkyZmja7nb7icdUinp0KY9DuEVqEmo,8908
9
+ tgp_backend/tgclient.py,sha256=QG2iFPrv2qLL4FRXoEfXzEMJriroiIaNL9rkreGtzuQ,2961
10
10
  tgp_backend/util.py,sha256=PsRO7CGhHZjGubkM39KDuTwJwyfq_Gs7HM-n0DFlIZc,2210
11
11
  tgp_ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- tgp_ui/app.py,sha256=SZp5YeTpNBLndNz4hoUCkc3voTzXNI2wsPZcIN7YLwc,12160
12
+ tgp_ui/app.py,sha256=cso4-T7a4uGgvVaMcFpqMT8to26c-7ASCOiVXVYIaGM,12252
13
13
  tgp_ui/static/css/bootstrap-icons.min.css,sha256=XxUvYRPQvG4RTCkukUmXwvf1N0YF9KQ_ocuWV6O1dk8,85797
14
14
  tgp_ui/static/css/bootstrap.min.css,sha256=djO3wMl9GeaC_u6K-ic4Uj_LKhRUSlUFcsruzS7v5ms,155845
15
15
  tgp_ui/static/css/main.css,sha256=EK8euwgxX8I3qsBiDmIvj8UBIxkSKQZz1mo_OX4Q1FQ,2641
16
16
  tgp_ui/static/css/simpleXML.css,sha256=dfY7UZCiC79BkNOT1hM0GQ6v_yLSxhKCnmV0RZIT9S8,961
17
17
  tgp_ui/static/js/bootstrap.bundle.min.js,sha256=fh8VA992XMpeCZiRuU4xii75UIG6KvHrbUF8yIS_2_4,78743
18
18
  tgp_ui/static/js/jquery.min.js,sha256=_xUj-3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej_m4,89501
19
- tgp_ui/static/js/jstree.min.js,sha256=bLd6OqSD4Ff3ueyKs1cvu_mHhlFps_7SJ0P660kwuE4,141969
20
- tgp_ui/static/js/main.js,sha256=NB5xXJXLVLsUznce-RQjYll4pLlGI44EzzEc0gIMRzQ,15621
19
+ tgp_ui/static/js/main.js,sha256=mTrA94R8ZeBYaFPs4NtIdTZ1RKdRnFjwqaIKdB7UW8k,17169
21
20
  tgp_ui/static/js/simpleXML.js,sha256=jEkZe3TuiHuEt6V7If_1EmqYIgTywssJ3OwOQzOFYNg,8065
22
21
  tgp_ui/templates/collection.html,sha256=WnYAH_5kJ6CzvVIqGk8XU_TZmhIrcOXggBoImyuGVZE,11416
23
- tgp_ui/templates/empty.html,sha256=__5AerKuSBFUn2yZGxEmjYzuGmmy81xYxm18ipU7dow,63
24
22
  tgp_ui/templates/file_tree.html,sha256=IKWp5MLUvnFF65cIUIxU4Jf5wi9Fg8koSXD96Mk328E,1640
25
23
  tgp_ui/templates/file_upload.html,sha256=fIelltVaTnqUqxBZoMy859IWbuwqNjrDZbVh9JlYl-g,1004
26
- tgp_ui/templates/jsfiler.html,sha256=TV27S3qWYe183zw7Bp8IGbPyyfESELpct_er_nysep0,134
27
- tgp_ui/templates/layout.html,sha256=6-rL9yIUoGei3M34ydTo4BUitR6y855chhClatG_0Bs,2766
28
- tgp_ui/templates/layout2.html,sha256=xtm3Uw-aE0iFaGsc7LvzQuPRdaQ5Lrt3tsFm6yH1_tI,4940
29
- tgp_ui/templates/macros.html,sha256=FFSPrllz12E6MJElpGFtZFbAS8PowAdY9Un9eqQX418,4047
30
- tgp_ui/templates/main.html,sha256=Aub0atvoi7f4GQWlV0P6RNHq08GHy2obyeDnrtkORo8,173
24
+ tgp_ui/templates/layout.html,sha256=eB80fnfUw8q_PEO6wY8eefjnRUbqwZEbHCFAK8ccQaY,5026
25
+ tgp_ui/templates/macros.html,sha256=zpbduAoTNj5OD2o_9z1IY6pPm_KX8kSOSWWN264kWB4,4253
31
26
  tgp_ui/templates/nxc_file_tree.html,sha256=i8nLf71c9vUyAP46eC6BdJJVXgAJcJd4xcIv7vW6Y9k,1275
32
27
  tgp_ui/templates/nxc_login.html,sha256=tDxqHYPZqsY2ZNnkn4a5bMOYiD8ybcNRpzSq7MvMWCo,1269
33
28
  tgp_ui/templates/nxc_tab.html,sha256=9HWCa7UZKxL0fZasT_g6uozI64L-497Y2LppPPTHF2M,517
34
- tgp_ui/templates/project.html,sha256=11xH5_Y3w_g0hjND1XChv84F-D5wqlcOuYfTAuo37Ng,970
35
- tgp_ui/templates/project_nxc.html,sha256=Id0-9gRt4QnuavhHnSe6GXNsvCk-MAsNr3r3zkU5KD4,1468
36
- tgp_ui/templates/projects.html,sha256=X4NBmnTOCGpDEotHYjhm0g6wqJH_2DHFp9As2m1tjq4,3345
37
- tgp_ui/templates/publish.html,sha256=zEB3AdT3K8qLqDec10xzftNJpkTr_NI0aN8ZvZnS844,5612
29
+ tgp_ui/templates/project.html,sha256=35oPO8yPMXqJSjtXZrXegrhIqmutECY_nk1ZYPFwAsc,1106
30
+ tgp_ui/templates/projects.html,sha256=zUPCTPa129aTwfo-ZpMkhkmQvcO7HPY0TXwAi7MnIOE,3344
31
+ tgp_ui/templates/publication.html,sha256=TXCHCE2198cHFmN4_l4JNmq0nQoy8GwnESePjRfjliU,9357
38
32
  tgp_ui/templates/storage.html,sha256=ZgLIawovCTkgQy7aX3QB0cMlQj4uiby68c8aJFQ_HNw,1985
39
- tgp_ui/templates/tei_browser.html,sha256=Djq9GMIf3imMvYIWMWwNYCAL95pi3gV42VIdTJpZ_eM,372
40
33
  tgp_ui/templates/tei_explorer.html,sha256=YPLYZcgsqvA2AAL8NQ61Eo1ekwn3FEQf6pB58lLLL8U,2472
41
34
  tgp_ui/templates/xpath_parser_modal_content.html,sha256=Hm3VNtXbmEUIPFihGnE11AcSRdvMGro73IKjvDJAAqg,1573
42
- tg_prepare-1.0.0.dist-info/METADATA,sha256=6JqeJip2M-knbJylyAaYRVJoTeRVrOd5YCuVfUJk8pY,532
43
- tg_prepare-1.0.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
44
- tg_prepare-1.0.0.dist-info/entry_points.txt,sha256=mbsfiEA8_fQdrFUE_oabDi-Syw8jjli37Ms7tawDDhs,78
45
- tg_prepare-1.0.0.dist-info/top_level.txt,sha256=ueOyX_KdozreQJD_HRs6kAsvGNO4vfM9B_QqqhdyRPI,19
46
- tg_prepare-1.0.0.dist-info/RECORD,,
35
+ tg_prepare-1.1.0.dist-info/METADATA,sha256=tJr1V2ztaQCVSpNpwO4Y9HYN2btX9knxnl7uSnBMmhE,532
36
+ tg_prepare-1.1.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
37
+ tg_prepare-1.1.0.dist-info/entry_points.txt,sha256=mbsfiEA8_fQdrFUE_oabDi-Syw8jjli37Ms7tawDDhs,78
38
+ tg_prepare-1.1.0.dist-info/top_level.txt,sha256=ueOyX_KdozreQJD_HRs6kAsvGNO4vfM9B_QqqhdyRPI,19
39
+ tg_prepare-1.1.0.dist-info/RECORD,,
@@ -28,7 +28,6 @@ def generateList(path=None):
28
28
  for name in os.listdir(path):
29
29
  fullpath = "%s/%s" % (path, name)
30
30
  if not name.startswith("."):
31
- print(name)
32
31
  if os.path.isdir(fullpath):
33
32
  dList.append({"fullpath": fullpath, "name": name})
34
33
  else:
@@ -79,7 +78,4 @@ def generateList(path=None):
79
78
 
80
79
  file_list_dict.append(temp_file)
81
80
 
82
- # log.debug("generateList - dir_list_dict: %s" % dir_list_dict)
83
- # print("generateList - file_list_dict: %s" % file_list_dict)
84
- # print(tp_dict)
85
81
  return dir_list_dict, file_list_dict
tgp_backend/project.py CHANGED
@@ -16,6 +16,8 @@ from tg_model.yaml import ( # type: ignore
16
16
  ProjectConfig,
17
17
  )
18
18
 
19
+ from tg_model.project import Project as TGMProject
20
+
19
21
  from tgp_backend.tgclient import TGclient
20
22
  from tgp_backend.util import config, list_files_and_folders
21
23
 
@@ -33,6 +35,7 @@ class Project(object):
33
35
  self._main_config = None
34
36
  self._collections = None
35
37
  self._nextcloud = None
38
+ self.tgm_project = TGMProject(self.metadatapath)
36
39
 
37
40
  def create(self):
38
41
  if not os.path.exists(self.fullpath):
@@ -62,7 +65,6 @@ class Project(object):
62
65
  file.save(filepath)
63
66
 
64
67
  def list_files_and_folders(self):
65
- print(self.datapath)
66
68
  return list_files_and_folders(self.datapath)
67
69
 
68
70
  @property
@@ -211,17 +213,16 @@ class TGProject(object):
211
213
  return False
212
214
 
213
215
  # step 1: create required metadata
214
- for c_name in self.collections:
215
- collection = self.collections[c_name]
216
- collection["modeler"].render_collection()
216
+ self.project.tgm_project.render_project()
217
217
 
218
218
  # step 2: push project to textgrid server
219
219
  for collection_name in self.collections:
220
220
  collection = self.collections[collection_name]
221
- self.tg_client.put_aggregation(
222
- self.tg_project_id,
223
- collection["modeler"].get_collection_path(),
224
- )
221
+ print(collection["modeler"].get_collection_path())
222
+ # self.tg_client.put_aggregation(
223
+ # self.tg_project_id,
224
+ # collection["modeler"].get_collection_path(),
225
+ # )
225
226
 
226
227
 
227
228
  class CollectionParser(object):
@@ -247,7 +248,6 @@ class CollectionParser(object):
247
248
  results = []
248
249
  for element in self.elements:
249
250
  result = element["tei_parser"].find(xpath)
250
- print(result)
251
251
  if result is not None:
252
252
  results.append(
253
253
  {
tgp_backend/tgclient.py CHANGED
@@ -89,4 +89,3 @@ class TGclient(object):
89
89
  threaded=True,
90
90
  ignore_warnings=True,
91
91
  )
92
- print(res)
tgp_ui/app.py CHANGED
@@ -106,17 +106,6 @@ def startup(path):
106
106
  # *****************
107
107
  # VIEWS
108
108
  # *****************
109
- @app.route(
110
- "/sidebar",
111
- methods=["GET", "POST"],
112
- )
113
- def sidebar():
114
-
115
- return render_template(
116
- "layout2.html",
117
- )
118
-
119
-
120
109
  @app.route(
121
110
  "/xpath_parser_modal/<string:projectname>/<string:title>",
122
111
  methods=["GET", "POST"],
@@ -162,6 +151,15 @@ def collection(projectname, name):
162
151
  )
163
152
 
164
153
 
154
+ @app.route("/publication/<string:projectname>", methods=["GET", "POST"])
155
+ def publication(projectname):
156
+ project = Project(projectname)
157
+ return render_template(
158
+ "publication.html",
159
+ project=project,
160
+ )
161
+
162
+
165
163
  @app.route("/project/<string:projectname>", methods=["GET", "POST"])
166
164
  def project(projectname=None):
167
165
  params = {
tgp_ui/static/js/main.js CHANGED
@@ -51,7 +51,6 @@ const checkXPath = function (e) {
51
51
  const self = $(this);
52
52
  const tab = self.closest('form').find(
53
53
  '.tab-pane.tei-explorer-content.loaded');
54
- console.log(self.closest('.row').find('input[name=xpath]').val())
55
54
  $.ajax({
56
55
  url: self.data('url'),
57
56
  method: 'GET',
@@ -114,17 +113,35 @@ const saveCollectionSettings = function (e) {
114
113
  data[d.name] = d.value;
115
114
  })
116
115
 
117
- // loop through multi-inputs
118
- self.find('.multi-input').each(function (i, d1) {
119
- console.log(d1)
120
- let multi_input = $(d1);
116
+ self.find('.multi-input-xpath').each(function (i, mix) {
117
+ let multi_input = $(mix);
121
118
  if (data[multi_input.data('name')] === undefined) {
122
119
  data[multi_input.data('name')] = [];
123
120
  }
124
121
  // get all keys and values for each multi-input
125
122
  let item = {};
126
- multi_input.find('input').each(function (i, d2) {
127
- item[$(d2).data('key')] = $(d2).val();
123
+ multi_input.find('input').each(function (i, mix_input) {
124
+ const key = $(mix_input).data('key');
125
+ const type = $(mix_input).data('type');
126
+ if (item[key] === undefined) {
127
+ item[key] = {};
128
+ }
129
+ item[key][type] = $(mix_input).val();
130
+ });
131
+ console.table(item)
132
+ data[multi_input.data('name')].push(JSON.stringify(item))
133
+
134
+ })
135
+ // loop through multi-inputs with fixed values
136
+ self.find('.multi-input-fixed').each(function (i, mif) {
137
+ let multi_input = $(mif);
138
+ if (data[multi_input.data('name')] === undefined) {
139
+ data[multi_input.data('name')] = [];
140
+ }
141
+ // get all keys and values for each multi-input
142
+ let item = {};
143
+ multi_input.find('input').each(function (i, mif_input) {
144
+ item[$(mif_input).data('key')] = $(mif_input).val();
128
145
  });
129
146
  data[multi_input.data('name')].push(JSON.stringify(item))
130
147
  })
@@ -143,7 +160,6 @@ const saveCollectionSettings = function (e) {
143
160
  for (const [key, value] of Object.entries(_data)) {
144
161
  data[key] = JSON.stringify(value);
145
162
  }
146
- console.table(data)
147
163
 
148
164
  $.ajax({
149
165
  url: self.attr('action'),
@@ -319,6 +335,22 @@ const loadCollectionTab = function (e) {
319
335
  })
320
336
  }
321
337
  }
338
+ // Helper function to load the publication tab for a specific project
339
+ const _loadPublicationTab = function (projectname) {
340
+ // Select the tab element for the given project
341
+ const tab = $('#tab_publish_' + projectname);
342
+ tab.show(); // Make the tab visible
343
+ $('.tab-pane.active').hide(); // Hide the currently active tab
344
+ // Load the tab content via AJAX with the project name as data
345
+ tab.load(tab.data('url'), { projectname: projectname });
346
+ }
347
+
348
+ // Event handler to load the publication tab when triggered
349
+ const loadPublicationTab = function (e) {
350
+ const self = $(this); // Reference the clicked element
351
+ // Call the helper function with the project name from the data attribute
352
+ _loadPublicationTab(self.data('projectname'));
353
+ }
322
354
 
323
355
  // this function replaces (kind of) the normal submit
324
356
  // by sending the form data via ajax and reloading the tab content
@@ -327,10 +359,10 @@ const tabSubmit = function (e) {
327
359
  const self = $(this);
328
360
  const submit_icons = self.find('button[type=submit] span');
329
361
  submit_icons.toggle();
362
+
330
363
  $.post(self.attr('action'), self.serialize(), function (response) {
331
364
  if (response.response === 'OK') {
332
- submit_icons.toggle();
333
- // console.log(response)
365
+ _loadPublicationTab(self.data('projectname'));
334
366
  }
335
367
  })
336
368
  }
@@ -344,6 +376,7 @@ const selectTGProject = function (e) {
344
376
  .removeClass('bi-circle');
345
377
  $.post(self.data('url'), self.data(), function (response) {
346
378
  if (response.response === 'OK') {
379
+ _loadPublicationTab(self.data('projectname'));
347
380
  }
348
381
  })
349
382
  }
@@ -376,8 +409,7 @@ const deleteTGProject = function (e) {
376
409
  spans.toggle();
377
410
  // send delete request to server
378
411
  $.post(self.data('url'), function () {
379
- // hide spinner & show trash icon
380
- self.find('span').toggle();
412
+ _loadPublicationTab(self.data('projectname'));
381
413
  });
382
414
  // get the hits of the project
383
415
  getTGProjectHits(
@@ -435,8 +467,10 @@ $(document).ready(function () {
435
467
  // show xpath (of a 'dynamic attribute') in TEI Explorer
436
468
  $(document).on('click', '.show-xpath-in-tei-explorer', showXPathInTEIExplorer);
437
469
 
438
-
439
470
  // ##PUBLISH##
471
+ // load publication tab content
472
+ $(document).on('click', '.publication-tab', loadPublicationTab);
473
+
440
474
  // this is generic form-submit for all forms with class 'tab-submit'
441
475
  $(document).on('submit', 'form.tab-submit', tabSubmit);
442
476
  // select a listed TextGrid-Project
@@ -444,6 +478,7 @@ $(document).ready(function () {
444
478
  // delete a listed TextGrid-Project
445
479
  $(document).on('click', 'a.delete-tg-project', deleteTGProject);
446
480
 
481
+ // ###PROJECTS###
447
482
  $('#deleteProject').on('show.bs.modal', function (event) {
448
483
  const pressed_button = $(event.relatedTarget);
449
484
  const target_input = $(this).find('input[name=projectname]');
@@ -7,51 +7,92 @@
7
7
  <meta name="description" content="" />
8
8
  <meta name="author" content="" />
9
9
  <title>{{ title }}</title>
10
- <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}" />
10
+ <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='img/favicon.ico') }}" />
11
11
  <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" />
12
12
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
13
13
  <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/simpleXML.css') }}" />
14
14
  <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/main.css') }}" />
15
-
16
- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/jstree.min.css') }}" />
17
- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/jsfiler.min.css') }}" />
18
15
  </head>
19
16
 
20
17
  <body>
21
- <nav class="navbar navbar-expand-md navbar-dark bg-secondary">
22
- <div class="container-fluid">
23
- <a class="navbar-brand" href="/">{{ title }}</a>
24
- <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
25
- data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
26
- aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
27
- <div class="collapse navbar-collapse" id="navbarSupportedContent">
28
- <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
29
- <li class="nav-item">
30
- <a class="nav-link" href="{{ url_for('projects') }}">Projects</a>
31
- </li>
32
- </ul>
18
+ <div class="wrapper">
19
+ <aside id="sidebar" class="expand">
20
+ <div class="d-flex">
21
+ <button class="toggle-btn" type="button">
22
+ <i class="bi bi-grid"></i>
23
+ </button>
24
+ <div class="sidebar-logo">
25
+ <a href="#">{{ title }}</a>
26
+ </div>
33
27
  </div>
28
+ <ul class="sidebar-nav">
29
+ <li class="sidebar-item">
30
+ <a href={{ url_for("projects") }} class="sidebar-link" title="Projects">
31
+ <i class="bi bi-view-list"></i>
32
+ <span>Overview</span>
33
+ </a>
34
+ </li>
35
+ {% for project in get_projects() %}
36
+ <li class="sidebar-item">
37
+ <a href="{{ url_for('project', projectname=project.name) }}" class="sidebar-link"
38
+ data-bs-target="#project_{{ loop.index }}" aria-expanded="false"
39
+ aria-controls="project_{{ loop.index }}">
40
+ {% if current_project == project.name %}
41
+ <i class="bi bi-circle-fill"></i>
42
+ {% else %}
43
+ <i class="bi bi-circle"></i>
44
+ {% endif %}
45
+ <span>{{ project.name }}</span>
46
+ </a>
47
+ <ul id="project_{{ loop.index }}"
48
+ class="sidebar-dropdown nav list-unstyled ps-3 {{ 'collapse' if current_project != project.name }}"
49
+ data-bs-parent="#sidebar">
50
+ <li class="sidebar-item">
51
+ <a class="sidebar-link nav-link" data-bs-toggle="tab" href="#tab_storage" role="tab"
52
+ aria-controls="tab_storage" aria-selected="false">
53
+ <i class="bi bi-folder2-open"></i>
54
+ Storage
55
+ </a>
56
+ </li>
57
+ {% for c in project.collections %}
58
+ {% set collection_config = project.collections[c]['config'] %}
59
+ <li class="sidebar-item">
60
+ <a class="sidebar-link nav-link collection-tab" data-bs-toggle="tab" href="#tab_{{ c }}"
61
+ role="tab" aria-controls="tab_{{ c }} aria-selected=" false"
62
+ data-url="{{ url_for('collection', projectname=project.name, name=c) }}"
63
+ data-name="{{ c }}">
64
+ <i class="spinner-border spinner-border-sm" role="status" style="display:none;"></i>
65
+ <i class="bi bi-{{ loop.index }}-circle"></i>
66
+ {{collection_config.short_title}}
67
+ </a>
68
+ </li>
69
+ {% endfor %}
70
+ <li class="sidebar-item">
71
+ <a class="sidebar-link nav-link publication-tab" data-bs-toggle="tab" href="#tab_publish"
72
+ role="tab" aria-controls="tab_publish" data-projectname="{{ project.name }}"
73
+ aria-selected="false">
74
+ <i class="bi bi-cloud-upload"></i>
75
+ Publish
76
+ </a>
77
+ </li>
78
+ </ul>
79
+ </li>
80
+ {% endfor %}
81
+ </aside>
82
+ <div class="main p-3">
83
+ <div class="text-center">
84
+ <h1>
85
+ <span>
86
+ {{ sub_title }}
87
+ </span>
88
+ </h1>
89
+ </div>
90
+ {% block content %}{% endblock content %}
34
91
  </div>
35
- </nav>
36
- <div class="container mt-3">
37
- <h1>
38
- <span>
39
- {{ sub_title }}
40
- </span>
41
- </h1>
42
- <p> {{sub_description}} </p>
43
- {% if error_msg %}
44
- <div class="alert alert-danger text-center">
45
- {{ error_msg }}
46
- </div>
47
- {% endif %}
48
- {% block content %}{% endblock content %}
49
92
  </div>
50
93
  <script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
51
94
  <script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
52
95
  <script src="{{ url_for('static', filename='js/simpleXML.js') }}"></script>
53
- <script src="{{ url_for('static', filename='js/jstree.min.js') }}"></script>
54
- <script src="{{ url_for('static', filename='js/jsfiler.min.js') }}"></script>
55
96
  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
56
97
  </script>
57
98
  </body>
@@ -1,3 +1,21 @@
1
+ {% macro form_field_with_xpath(label, field_key, elem, has_next=False) %}
2
+ <div class="mb-2 row">
3
+ <div class="col-12 {{'pb-2 border-top' if has_next }}">
4
+ <label class="form-label">{{label}}
5
+ <a href="#" class="badge text-dark remove-multi-field">
6
+ <span class="bi bi-trash"></span>
7
+ </a>
8
+ </label>
9
+ <div class="input-group">
10
+ <input type="text" class="form-control" data-key="{{ field_key }}" data-type="value" placeholder="Value"
11
+ value="{{ elem['value'] if elem and elem.get('value') }}">
12
+ <input type="text" class="form-control" data-key="{{ field_key }}" data-type="xpath" placeholder="XPath"
13
+ value="{{ elem['xpath'] if elem and elem.get('xpath') }}">
14
+ </div>
15
+ </div>
16
+ </div>
17
+ {% endmacro %}
18
+
1
19
  {% macro multi_input(type, heading, elements, version=1) %}
2
20
  <div class="border-top mb-3 row">
3
21
  <label class="col-sm-12 col-form-label">
@@ -10,30 +28,15 @@
10
28
  </label>
11
29
  </div>
12
30
  {% for item in elements or [None] %}
13
- <div class="multi-input" data-name="{{ type }}">
14
- {% if version == 1 %}
15
- <div class="mb-3 row">
16
- <label class="col-lg-2 col-form-label">ID
17
- <a href="#" class="badge text-dark remove-multi-field">
18
- <span class="bi bi-trash"></span>
19
- </a>
20
- </label>
21
- <div class="col-lg-4">
22
- <input type="text" class="form-control" data-key="id" value="{{ item['id'] if item['id'] }}">
23
- </div>
24
- <label class="col-lg-2 col-form-label">URL</label>
25
- <div class="col-lg-4">
26
- <input type="text" class="form-control" data-key="url" value="{{ item['url'] if item['url'] }}">
27
- </div>
28
- </div>
29
- <div class="mb-3 row">
30
- <label class="col-lg-2 col-form-label">Value</label>
31
- <div class="col-lg-10 {{'pb-2 border-bottom' if loop.nextitem }}">
32
- <input type="text" class="form-control" data-key="value" value="{{ item['value'] if item['value'] }}">
33
- </div>
34
- </div>
35
- {% elif version == 2 %}
36
- <div class="mb-3 row {{'pb-2 border-bottom' if loop.nextitem }}">
31
+ {% if version == 1 %}
32
+ <div class="multi-input-xpath" data-name="{{ type }}">
33
+ {{ form_field_with_xpath('ID', 'id', item.get('id') if item) }}
34
+ {{ form_field_with_xpath('URL', 'url', item.get('url') if item) }}
35
+ {{ form_field_with_xpath('Value', 'value', item.get('value') if item, has_next=loop.nextitem) }}
36
+ </div>
37
+ {% elif version == 2 %}
38
+ <div class="multi-input-fixed" data-name="{{ type }}">
39
+ <div class="mb-3 row {{'pb-2 border-bottom' if not loop.last }}">
37
40
  <label class="col-lg-2 col-form-label">
38
41
  Fullname
39
42
  </label>
@@ -51,8 +54,8 @@
51
54
  </a>
52
55
  </div>
53
56
  </div>
54
- {% endif %}
55
57
  </div>
58
+ {% endif %}
56
59
  {% endfor %}
57
60
  {% endmacro %}
58
61
 
@@ -1,4 +1,4 @@
1
- {% extends 'layout2.html' %}
1
+ {% extends 'layout.html' %}
2
2
  {% block content %}
3
3
  <div class="row">
4
4
  <div class="tab-content pt-2" id="tab-content">
@@ -10,8 +10,9 @@
10
10
  <div class="tab-pane {{ 'active' if tab==collection_config.short_title }}" id="tab_{{ c }}" role="tabpanel">
11
11
  </div>
12
12
  {% endfor %}
13
- <div class="tab-pane {{'active' if tab=='publish' }}" id="tab_publish" role="tabpanel">
14
- {% include 'publish.html' %}
13
+ <div class="tab-pane {{'active' if tab=='publish' }}" id="tab_publish_{{ project.name }}"
14
+ data-url="{{ url_for('publication', projectname=project.name) }}" role="tabpanel">
15
+ <span class="spinner-border spinner-border-sm" role="status"></span>
15
16
  </div>
16
17
  </div>
17
18
  </div>
@@ -1,4 +1,4 @@
1
- {% extends 'layout2.html' %}
1
+ {% extends 'layout.html' %}
2
2
  {% block content %}
3
3
  <div class="row row-cols-xxl-6 row-cols-lg-4 row-cols-md-2">
4
4
  {% for project in projects%}