tg-prepare 1.1.0__py3-none-any.whl → 2.1.0b2__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.

Files changed (70) hide show
  1. {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/METADATA +3 -3
  2. tg_prepare-2.1.0b2.dist-info/RECORD +78 -0
  3. {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/WHEEL +1 -1
  4. tg_prepare-2.1.0b2.dist-info/projects/.secret_key +1 -0
  5. tgp_backend/__init__.py +3 -4
  6. tgp_backend/config.py +31 -0
  7. tgp_backend/directories.py +6 -8
  8. tgp_backend/nextcloud.py +40 -19
  9. tgp_backend/project.py +172 -45
  10. tgp_backend/session_manager.py +47 -0
  11. tgp_backend/util.py +73 -25
  12. tgp_ui/app.py +43 -335
  13. tgp_ui/routes/__init__.py +0 -0
  14. tgp_ui/routes/collection.py +272 -0
  15. tgp_ui/routes/data.py +228 -0
  16. tgp_ui/routes/project.py +102 -0
  17. tgp_ui/routes/publication.py +129 -0
  18. tgp_ui/routes/tabs.py +34 -0
  19. tgp_ui/routes/views.py +62 -0
  20. tgp_ui/static/css/bootstrap.min.css.map +1 -0
  21. tgp_ui/static/css/navbar.css +92 -0
  22. tgp_ui/static/img/favicon.ico +0 -0
  23. tgp_ui/static/img/textgrid-logo.svg +1 -0
  24. tgp_ui/static/js/collectionManager.js +60 -0
  25. tgp_ui/static/js/fileManager.js +186 -0
  26. tgp_ui/static/js/main.js +32 -485
  27. tgp_ui/static/js/modalManager.js +105 -0
  28. tgp_ui/static/js/navbarManager.js +151 -0
  29. tgp_ui/static/js/projectManager.js +60 -0
  30. tgp_ui/static/js/require.js +5 -0
  31. tgp_ui/static/js/sidebarManager.js +32 -0
  32. tgp_ui/static/js/tabManager.js +79 -0
  33. tgp_ui/templates/details/empty_container.html +16 -0
  34. tgp_ui/templates/details/manage_collection.html +205 -0
  35. tgp_ui/templates/includes/set_session_id_form.html +16 -0
  36. tgp_ui/templates/includes/upload_form.html +131 -0
  37. tgp_ui/templates/layout.html +9 -48
  38. tgp_ui/templates/macros.html +79 -72
  39. tgp_ui/templates/modal/delete_project.html +25 -0
  40. tgp_ui/templates/modal/empty_container.html +9 -0
  41. tgp_ui/templates/modal/file_explorer_content.html +34 -0
  42. tgp_ui/templates/modal/file_explorer_main.html +22 -0
  43. tgp_ui/templates/modal/file_explorer_nextcloud.html +27 -0
  44. tgp_ui/templates/modal/github_modal.html +29 -0
  45. tgp_ui/templates/modal/nextcloud_login.html +48 -0
  46. tgp_ui/templates/modal/tei_explorer.html +58 -0
  47. tgp_ui/templates/modal/xpath_parser.html +52 -0
  48. tgp_ui/templates/project_main.html +36 -0
  49. tgp_ui/templates/project_navbar.html +81 -0
  50. tgp_ui/templates/{projects.html → projects_main.html} +13 -28
  51. tgp_ui/templates/tab_final_upload.html +29 -0
  52. tgp_ui/templates/tabs/check_result.html +90 -0
  53. tgp_ui/templates/tabs/edit_project.html +113 -0
  54. tgp_ui/templates/tabs/empty_container.html +12 -0
  55. tgp_ui/templates/tabs/import_data.html +138 -0
  56. tgp_ui/templates/tabs/manage_collections.html +88 -0
  57. tgp_ui/templates/tabs/select_directories.html +41 -0
  58. tgp_ui/templates/tabs/upload.html +42 -0
  59. tgp_ui/templates/tabs/validate_metadata.html +227 -0
  60. tg_prepare-1.1.0.dist-info/RECORD +0 -39
  61. tgp_ui/templates/collection.html +0 -194
  62. tgp_ui/templates/file_upload.html +0 -24
  63. tgp_ui/templates/nxc_file_tree.html +0 -33
  64. tgp_ui/templates/project.html +0 -26
  65. tgp_ui/templates/storage.html +0 -49
  66. tgp_ui/templates/tei_explorer.html +0 -48
  67. tgp_ui/templates/xpath_parser_modal_content.html +0 -37
  68. {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/entry_points.txt +0 -0
  69. {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/licenses/LICENSE +0 -0
  70. {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,131 @@
1
+ <!DOCTYPE html>
2
+ <div class="row">
3
+ {% set tg_session_id = project.main_config.get_tg_session_id(instance) %}
4
+
5
+ <!-- Left column: Project management -->
6
+ {% if not tg_session_id %}
7
+ <div class="col-12 text-center">
8
+ <!-- Show note when no session ID is set -->
9
+ <div class="alert alert-warning fst-italic">
10
+ <h6 class="fw-bold">Attention</h6>
11
+ <p>
12
+ <b>You need to provide a "TgAuth Session ID" in order to publish your project to
13
+ TextGrid-{{ instance|capitalize }} Instance!</b>
14
+ </p>
15
+ <ol class="mb-0">
16
+ <li>Please first go to <a href="{{ get_textgrid_login_url(instance) }}" target="_blank">this
17
+ page</a>!
18
+ (You may need to log in via DARIAH-AAI)</li>
19
+ <li>Then click on "More Details" and copy the "TgAuth Session ID" to your clipboard.</li>
20
+ <li>Finally, paste it into the input field below and save it.</li>
21
+ </ol>
22
+ </div>
23
+ </div>
24
+ {% endif %}
25
+
26
+ <div class="col-lg-7 mb-4 mb-lg-0">
27
+ <div class="bg-light rounded p-4 h-100">
28
+
29
+ <h4 class="mb-3">Set Session ID of TextGrid-{{ instance|capitalize }} Instance</h4>
30
+ <form class="row js-tab-submit" method="POST"
31
+ action="{{ url_for('publication.save_session_id', projectname=project.path, instance=instance) }}">
32
+ <input type="hidden" name="selected_instance" value="{{ instance }}">
33
+ <div class="col-9">
34
+ <input type="text" class="form-control" name="tg_auth_session_id" placeholder="TgAuth Session ID"
35
+ value="{{ tg_session_id if tg_session_id }}">
36
+ </div>
37
+ <div class="col-3">
38
+ <button type="submit" class="btn btn-primary w-100" style="min-width: 48px;">
39
+ <span class="bi bi-floppy2-fill"></span>
40
+ <span class="spinner-border spinner-border-sm" style="display:none;" role="status"
41
+ aria-hidden="true"></span>
42
+ </button>
43
+ </div>
44
+ </form>
45
+
46
+ {% if tg_session_id %}
47
+ <h4 class="my-3 border-top pt-3">Select from existing projects</h4>
48
+ <div class="row pb-1">
49
+ {% set tg_project_id = project.main_config.get_tg_project_id(instance) %}
50
+ {% for tg_project in project.get_tgp(instance).get_tg_projects() %}
51
+ <div class="col-md-6 mb-3">
52
+ <div
53
+ class="card h-100 {{'border-primary' if tg_project_id == tg_project.id else 'border-secondary'}}">
54
+ <div class="card-body">
55
+ <h5 class="card-title text-truncate">{{ tg_project.name }}</h5>
56
+ <p class="card-text text-muted mb-1">({{ tg_project.contents }} Elements)</p>
57
+ <p class="card-text text-muted small"><i>ID: {{ tg_project.id }}</i></p>
58
+ </div>
59
+ <div class="card-footer d-flex justify-content-between align-items-center">
60
+ <form method="POST" class="js-tab-submit"
61
+ action="{{ url_for('publication.save_tg_project_id', projectname=project.path, instance=instance, tg_project_id=tg_project.id) }}">
62
+ <button type="submit" class="btn btn-sm btn-outline-primary">
63
+ {% if tg_project_id == tg_project.id %}
64
+ <span class="bi bi-check-circle-fill text-primary"></span> Selected
65
+ {% else %}
66
+ <span class="bi bi-circle"></span> Select
67
+ {% endif %}
68
+ </button>
69
+ </form>
70
+ <form method="POST" class="js-tab-submit"
71
+ action="{{ url_for('publication.delete_tg_project_id', projectname=project.path, instance=instance, tg_project_id=tg_project.id) }}">
72
+ <button type="submit" class="btn btn-sm btn-outline-danger" title="Delete project">
73
+ <span class="bi bi-trash"></span> Delete
74
+ </button>
75
+ </form>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ {% endfor %}
80
+ </div>
81
+ <h5 class="border-top pt-3 pb-2">New project:</h5>
82
+ <form class="row tab-submit js-tab-submit" method="POST"
83
+ action="{{ url_for('publication.create_tg_project', projectname=project.path, instance=instance) }}">
84
+ <div class="col-9">
85
+ <input type="text" class="form-control" name="tg_projectname" placeholder="TG Projectname" required>
86
+ </div>
87
+ <div class="col-3">
88
+ <button type="submit" class="btn btn-primary w-100">
89
+ <span class="bi bi-pencil-square"></span>
90
+ <span class="spinner-border spinner-border-sm" style="display:none;" role="status"
91
+ aria-hidden="true"></span>
92
+ </button>
93
+ </div>
94
+ </form>
95
+ </div>
96
+ {% endif %}
97
+ </div>
98
+
99
+ <!-- Rechte Spalte: Upload -->
100
+ <div class="col-lg-5 border-start">
101
+ <div class="bg-light rounded p-4 h-100">
102
+ {% if tg_session_id %}
103
+ <div class="text-center mb-4">
104
+ <h4 class="mb-2"><i
105
+ class="bi bi-cloud-upload {% if instance == 'test' %}text-primary{% else %}text-danger{% endif %} me-2"></i>Upload
106
+ to {{ instance|capitalize }} Instance</h4>
107
+ {% if instance == 'test' %}
108
+ <span class="badge bg-warning text-dark mb-2">
109
+ This upload is for <b>testing purposes</b>.
110
+ </span>
111
+ {% else %}
112
+ <span class="badge bg-danger text-light mb-2">
113
+ This starts a <b>real publication</b>.
114
+ <br />
115
+ Please ensure all data is correct.
116
+ </span>
117
+ {% endif %}
118
+ </div>
119
+ <form method="POST"
120
+ action="{{ url_for('publication.upload_project', projectname=project.path, instance=instance) }}"
121
+ class="w-100 js-tab-submit">
122
+ <button type="submit"
123
+ class="btn {% if instance == 'test' %}btn-success{% else %}btn-danger{% endif %} w-100 py-3"
124
+ style="font-size:1.25rem;">
125
+ <i class="bi bi-rocket-takeoff me-2"></i>Upload to {{ instance|capitalize }} Instance
126
+ </button>
127
+ </form>
128
+ {% endif %}
129
+ </div>
130
+ </div>
131
+ </div>
@@ -12,6 +12,7 @@
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
+ <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/navbar.css') }}" />
15
16
  </head>
16
17
 
17
18
  <body>
@@ -27,14 +28,14 @@
27
28
  </div>
28
29
  <ul class="sidebar-nav">
29
30
  <li class="sidebar-item">
30
- <a href={{ url_for("projects") }} class="sidebar-link" title="Projects">
31
+ <a href="{{ url_for('views.overview') }}" class="sidebar-link" title="Projects">
31
32
  <i class="bi bi-view-list"></i>
32
33
  <span>Overview</span>
33
34
  </a>
34
35
  </li>
35
36
  {% for project in get_projects() %}
36
- <li class="sidebar-item">
37
- <a href="{{ url_for('project', projectname=project.name) }}" class="sidebar-link"
37
+ <li class="sidebar-item project-btn">
38
+ <a href="{{ url_for('views.project_view', projectname=project.name) }}" class="sidebar-link"
38
39
  data-bs-target="#project_{{ loop.index }}" aria-expanded="false"
39
40
  aria-controls="project_{{ loop.index }}">
40
41
  {% if current_project == project.name %}
@@ -42,59 +43,19 @@
42
43
  {% else %}
43
44
  <i class="bi bi-circle"></i>
44
45
  {% endif %}
45
- <span>{{ project.name }}</span>
46
+ <span class="projectname">{{ project.name }}</span>
46
47
  </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>
48
+
79
49
  </li>
80
50
  {% endfor %}
51
+ </ul>
81
52
  </aside>
82
53
  <div class="main p-3">
83
- <div class="text-center">
84
- <h1>
85
- <span>
86
- {{ sub_title }}
87
- </span>
88
- </h1>
89
- </div>
90
54
  {% block content %}{% endblock content %}
55
+ {% include 'modal/empty_container.html' %}
91
56
  </div>
92
57
  </div>
93
- <script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
94
- <script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
95
- <script src="{{ url_for('static', filename='js/simpleXML.js') }}"></script>
96
- <script src="{{ url_for('static', filename='js/main.js') }}"></script>
97
- </script>
58
+ <script data-main="/static/js/main" src="{{ url_for('static', filename='js/require.js') }}"></script>
98
59
  </body>
99
60
 
100
61
  </html>
@@ -1,94 +1,101 @@
1
- {% macro form_field_with_xpath(label, field_key, elem, has_next=False) %}
1
+ {% macro multi_input(_items, input_name) %}
2
+ {% set items = _items or [None] %}
3
+ {% for item in items %}
4
+ <div class="input-group mb-2">
5
+ <input type="text" class="form-control" title="Name" name="{{input_name}}_name" placeholder="e.g.: Jane Doe"
6
+ value="{{ item.fullname or item.name }}" required>
7
+ <input type="url" class="form-control" title="URL" name="{{input_name}}_url" value="{{ item.url or '' }}"
8
+ placeholder="e.g.: https://orcid.org/0000-0001-2345-6789">
9
+ {% if loop.first %}
10
+ <button class="input-group-text add-multi-input">
11
+ <i class="bi bi-plus-circle-dotted"></i>
12
+ </button>
13
+ {% else %}
14
+ <button class="input-group-text remove-multi-input">
15
+ <i class="bi bi-dash-circle-dotted"></i>
16
+ </button>
17
+ {% endif %}
18
+ </div>
19
+ {% endif %}
20
+ {% endfor %}
21
+ {% endmacro %}
22
+
23
+ {% macro form_field_with_xpath(type, label, field_key, elem, delete_button=False) %}
2
24
  <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>
25
+ <div class="col-12 d-flex justify-content-between align-items-center">
26
+ <label class="form-label mb-0">
27
+ {{ label }}
8
28
  </label>
29
+ {% if delete_button %}
30
+ <a href="#" class="badge text-dark remove-multi-field-classification ms-3">
31
+ <span class="bi bi-trash"></span>
32
+ </a>
33
+ {% endif %}
34
+ </div>
35
+ <div class="col-12">
9
36
  <div class="input-group">
10
37
  <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') }}">
38
+ value="{{ elem['value'] if elem and elem.get('value') }}" name="{{ type }}-{{ field_key }}-value">
12
39
  <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') }}">
40
+ value="{{ elem['xpath'] if elem and elem.get('xpath') }}" name="{{ type }}-{{ field_key }}-xpath">
14
41
  </div>
15
42
  </div>
16
43
  </div>
17
44
  {% endmacro %}
18
45
 
19
- {% macro multi_input(type, heading, elements, version=1) %}
20
- <div class="border-top mb-3 row">
21
- <label class="col-sm-12 col-form-label">
22
- <div class="d-flex justify-content-between align-items-center">
23
- <b>{{ heading }}</b>
24
- <a href="#" class="add-multi-input btn btn-md" title="Add {{ heading }}">
25
- <span class="bi bi-plus-circle"></span>
26
- </a>
27
- </div>
28
- </label>
29
- </div>
30
- {% for item in elements or [None] %}
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 }}">
40
- <label class="col-lg-2 col-form-label">
41
- Fullname
46
+ {% macro classification_input(type, heading, elements) %}
47
+ <div class="border-bottom mb-3 row">
48
+ <div class="d-flex justify-content-between align-items-center">
49
+ <label class="form-label text-center flex-grow-1 mb-0">
50
+ <i>{{ heading }}</i>
42
51
  </label>
43
- <div class="col-lg-4">
44
- <input type="text" class="form-control" data-key="fullname"
45
- value="{{ item['fullname'] if item['fullname'] }}">
46
- </div>
47
- <label class="col-lg-1 col-form-label">URL</label>
48
- <div class="col-lg-4 ">
49
- <input type="text" class="form-control" data-key="url" value="{{ item['url'] if item['url'] }}">
50
- </div>
51
- <div class="col-lg-1 mt-lg-0 mt-2">
52
- <a href="#" class="btn btn-md remove-multi-field">
53
- <span class="bi bi-trash"></span>
54
- </a>
55
- </div>
52
+ <a href="#" class="add-multi-input-classifications btn btn-md ms-3" title="Add {{ heading }}">
53
+ <span class="bi bi-plus-circle"></span>
54
+ </a>
56
55
  </div>
57
56
  </div>
58
- {% endif %}
57
+ {% for item in elements or [None] %}
58
+ <div class="multi-input {{'mb-3 pb-3 border-bottom' if loop.nextitem }}" data-name="{{ type }}">
59
+ {{ form_field_with_xpath(type, 'ID', 'id', item.get('id') if item, delete_button=True) }}
60
+ {{ form_field_with_xpath(type, 'URL', 'url', item.get('url') if item) }}
61
+ {{ form_field_with_xpath(type, 'Value', 'value', item.get('value') if item) }}
62
+ </div>
59
63
  {% endfor %}
60
64
  {% endmacro %}
61
65
 
62
- {% macro xpath_or_value_input(heading, input_name, item, collection_parser, is_subsection=True) %}
63
- <div class="mb-1 row gap-1 align-items-center xpath-or-value-input">
64
- <label class="col-lg-2 col-form-label">
65
- {% if is_subsection %}
66
- {{ heading }}
67
- {% else %}
68
- <b>{{ heading }}</b>
69
- {% endif %}
66
+
67
+ {% macro xpath_or_value_input(heading, input_name, item, collection_parser, required=False) %}
68
+ <div class="mb-3">
69
+ <label class="form-label">
70
+ <span>{{ heading }}</span>
71
+ {% if required %}<span class="text-danger">*</span>{% endif %}
70
72
  </label>
71
- <div class="col-lg-5">
72
- <div class="form-floating">
73
- <input type="text" class="form-control" id="valueInput_{{ input_name }}" data-name="{{ input_name }}"
74
- data-type="value" value="{{ item['value'] if item['value'] }}" placeholder="Value">
75
- <label for="valueInput_{{ input_name }}">Value</label>
73
+ <div class="row g-2">
74
+ <!-- Value Input -->
75
+ <div class="col-lg-6">
76
+ <input type="text" class="form-control" id="valueInput_{{ input_name }}" name="{{ input_name }}_value"
77
+ value="{{ item['value'] if item['value'] }}" placeholder="Value">
76
78
  </div>
77
- </div>
78
- <div class="col-lg-4 position-relative">
79
- <div class="form-floating">
80
- <input type="text" class="form-control" id="xpathInput_{{ input_name }}" data-name="{{ input_name }}"
81
- data-type="xpath" value="{{ item['xpath'] if item['xpath'] }}" placeholder="XPath">
82
- <label for="xpathInput_{{ input_name }}">XPath</label>
79
+
80
+ <!-- XPath Input -->
81
+ <div class="col-lg-6 position-relative">
82
+ <input type="text" class="form-control" id="xpathInput_{{ input_name }}" name="{{ input_name }}_xpath"
83
+ value="{{ item['xpath'] if item['xpath'] }}" placeholder="XPath">
84
+ <a href="#" class="load-modal" title="Hitrate of xpath (in %) - CLICK to see results"
85
+ data-args_xpath="{{ item['xpath'] }}"
86
+ data-url="{{ url_for('collection.modal_xpath_parser', projectname=project.name, collectionname=collectionname) }}">
87
+ <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-success"
88
+ data-bs-placement="top" title="Hitrate of XPath in percentage">
89
+ {{ collection_parser.test_xpath(item['xpath'])['count']['percentage'] if item['xpath'] else '-' }}
90
+ </span>
91
+ </a>
83
92
  </div>
84
- <a href="#" class="show-xpath-in-tei-explorer" title="Hitrate of xpath (in %) - CLICK to see results"
85
- data-url="{{ url_for('xpath_parser_modal', projectname=project.name, title=collection_title) }}"
86
- data-xpath="{{ item['xpath'] }}">
87
- <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-success"
88
- data-bs-toggle="tooltip" data-bs-placement="top" title="Hitrate of XPath in percentage">
89
- {{ collection_parser.test_xpath(item['xpath'])['count']['percentage'] if item['xpath'] else '-' }}
90
- </span>
91
- </a>
92
93
  </div>
93
94
  </div>
95
+ {% endmacro %}
96
+
97
+ {% macro required_fields_disclaimer() %}
98
+ <div class="mb-3 mt-3">
99
+ <small class="text-muted"><span class="text-danger">*</span> indicates required fields</small>
100
+ </div>
94
101
  {% endmacro %}
@@ -0,0 +1,25 @@
1
+ <div class="modal fade" id="deleteProject" tabindex="-1" aria-labelledby="deleteProjectLabel" aria-hidden="true">
2
+ <div class="modal-dialog">
3
+ <div class="modal-content">
4
+ <form action="{{ url_for('project.delete_project', projectname=projectname) }}" method="POST"
5
+ data-reload-location="1">
6
+ <div class="modal-header">
7
+ <h5 class="modal-title" id="deleteProjectLabel">
8
+ <span>Delete Project</span>
9
+ </h5>
10
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
11
+ </div>
12
+ <div class="modal-body">
13
+ <p>Are you sure you want to delete the project
14
+ <p><strong>{{ projectname }}</strong>?</p>
15
+ This action cannot be undone.</p>
16
+ <p>All associated data will be permanently removed.</p>
17
+ </div>
18
+ <div class="modal-footer">
19
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
20
+ <button type="submit" class="btn btn-danger">Delete</button>
21
+ </div>
22
+ </form>
23
+ </div>
24
+ </div>
25
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="modal fade" id="genericModalContainer" tabindex="-1" aria-hidden="true">
2
+ <div class="modal-dialog modal-dialog-centered">
3
+ <div class="modal-body text-center bg-transparent border-0">
4
+ <div class="spinner-border text-white" style="width: 4rem; height: 4rem;" role="status">
5
+ <span class="visually-hidden">Loading...</span>
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -0,0 +1,34 @@
1
+ {% for item in items %}
2
+ <div class="list-group-item border-0">
3
+ <div class="d-flex align-items-center">
4
+ <div style="width: {{ item.depth * 1.2 }}rem"></div>
5
+ {% if item.type == 'folder' %}
6
+ <div class="form-check me-1">
7
+ {% if item.contains_xml or show_all_folders %}
8
+ {% if show_checkbox %}
9
+ <input class="form-check-input nextcloud-folder" type="checkbox" name="selected_folder"
10
+ value="{{ item.path }}" {{'checked' if item.path in selected_directories else '' }}>
11
+ {% endif %}
12
+ <label class="form-check-label">
13
+ <i class="bi bi-folder-fill text-warning me-1"></i>
14
+ {{ item.name }}
15
+ </label>
16
+ {% else %}
17
+ <i class="bi bi-folder-fill text-warning me-1"></i>
18
+ <span>{{ item.name }}</span>
19
+ {% endif %}
20
+ </div>
21
+ {% else %}
22
+ <i class="bi bi-file-text me-1 small"></i>
23
+ <span style="font-size: 0.7rem;">{{ item.name }}</span>
24
+ {% endif %}
25
+ </div>
26
+ {% if item.type == 'folder' and item.children.count > 0 %}
27
+ <div class="mt-1">
28
+ {% with items=item.children.list %}
29
+ {% include 'modal/file_explorer_content.html' %}
30
+ {% endwith %}
31
+ </div>
32
+ {% endif %}
33
+ </div>
34
+ {% endfor %}
@@ -0,0 +1,22 @@
1
+ <div class="modal fade" id="folderModal{{ index }}" tabindex="-1">
2
+ <div class="modal-dialog modal-lg">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <h5 class="modal-title">
6
+ <i class="bi bi-folder2-open text-warning me-2"></i>
7
+ {{ folder.name }}
8
+ </h5>
9
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
10
+ </div>
11
+ <div class="modal-body">
12
+ {% if folder.children.count > 0 %}
13
+ {% with items=folder.children.list %}
14
+ {% include 'modal/file_explorer_content.html' %}
15
+ {% endwith %}
16
+ {% else %}
17
+ <p class="text-muted text-center py-3">Dieser Ordner ist leer</p>
18
+ {% endif %}
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </div>
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html>
2
+ <!-- Nextcloud <tree> Modal -->
3
+ <div class="modal-dialog modal-dialog-scrollable modal-lg">
4
+ <form class="modal-content js-modal-submit" data-reload-location="true"
5
+ action="{{ url_for('data.download_nextcloud', projectname=project.name) }}" method="POST"
6
+ id="nextcloudUploadForm">
7
+ <div class="modal-header">
8
+ <h5 class="modal-title" id="nextcloudModalLabel">Nextcloud Folders</h5>
9
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
10
+ </div>
11
+ <div class="modal-body">
12
+ {% for item in items %}
13
+ {% if item.type == 'folder' %}
14
+ {% with folder=item, index=loop.index %}
15
+ {% include 'modal/file_explorer_content.html' %}
16
+ {% endwith %}
17
+ {% endif %}
18
+ {% endfor %}
19
+ </div>
20
+ <div class="modal-footer">
21
+ <button type="submit" class="btn btn-success">Download selected</button>
22
+ <button type="button" name="form_type" value="logout"
23
+ data-url="{{ url_for('data.modal_nextcloud', projectname=project.name, logout=True) }}"
24
+ class="load-modal btn btn-danger">Logout</button>
25
+ </div>
26
+ </form>
27
+ </div>
@@ -0,0 +1,29 @@
1
+ <div class="modal fade" id="githubModal" tabindex="-1">
2
+ <div class="modal-dialog">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <h5 class="modal-title">Clone from GitHub</h5>
6
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
7
+ </div>
8
+ <div class="modal-body">
9
+ <form class="reloadModal" action="{{ url_for('data.clone_git_project', projectname=project.name) }}"
10
+ method="POST" id="cloneFromGit">
11
+ <div class="mb-3">
12
+ <input type="text" class="form-control" name="github_repo" placeholder="GitHub Repository URL">
13
+ </div>
14
+ <div class="d-flex justify-content-between align-items-center">
15
+ <small class="text-muted">
16
+ <i>Please be aware, that this can take a while (depending on the size of the git
17
+ project)!</i>
18
+ </small>
19
+ </div>
20
+ <button type="submit" class="btn btn-primary mt-3">
21
+ <span class="spinner-border spinner-border-sm me-2 d-none" role="status"
22
+ aria-hidden="true"></span>
23
+ <span>Clone Repository</span>
24
+ </button>
25
+ </form>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
@@ -0,0 +1,48 @@
1
+ <!DOCTYPE html>
2
+ <!-- Nextcloud Upload Modal -->
3
+ <div class="modal-dialog modal-sm">
4
+ <div class="modal-content">
5
+ <form class="js-modal-submit" action="{{ url_for('data.modal_nextcloud', projectname=projectname) }}"
6
+ method="POST" id="nextcloudUploadForm">
7
+ <div class="modal-header">
8
+ <h5 class="modal-title">Login to Nextcloud</h5>
9
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
10
+ </div>
11
+ <div class="modal-body">
12
+ <div class="mb-3">
13
+ <label for="nextcloudUrl" class="form-label">Endpoint/URL *</label>
14
+ <input type="url" class="form-control" id="nextcloudUrl" name="nextcloud_url"
15
+ placeholder="https://cloud.example.com" required>
16
+ </div>
17
+ <div class="mb-3">
18
+ <label for="nextcloudUser" class="form-label">Username *</label>
19
+ <input type="text" class="form-control" id="nextcloudUser" name="nextcloud_user" required>
20
+ </div>
21
+ <div class="mb-3">
22
+ <label for="nextcloudPassword" class="form-label">Password *</label>
23
+ <input type="password" class="form-control" id="nextcloudPassword" name="nextcloud_password"
24
+ required>
25
+ </div>
26
+ <div class="mb-3">
27
+ <label for="nextcloudFolder" class="form-label">Folder</label>
28
+ <input type="text" class="form-control" id="nextcloudFolder" name="nextcloud_folder"
29
+ placeholder="/path/to/folder">
30
+ </div>
31
+ <div class="alert alert-info" role="alert">
32
+ <small>* Required fields</small>
33
+ </div>
34
+ {% if message %}
35
+ <div class="alert text-center alert-warning" role="alert">
36
+ {{ message }}
37
+ </div>
38
+ {% endif %}
39
+ </div>
40
+ <div class="modal-footer d-flex justify-content-center">
41
+ <button type="submit" class="btn btn-primary">
42
+ <span class="spinner-border spinner-border-sm me-2 d-none" role="status" aria-hidden="true"></span>
43
+ <span>Login</span>
44
+ </button>
45
+ </div>
46
+ </form>
47
+ </div>
48
+ </div>