datacontract-cli 0.10.23__py3-none-any.whl → 0.10.37__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.
- datacontract/__init__.py +13 -0
- datacontract/api.py +12 -5
- datacontract/catalog/catalog.py +5 -3
- datacontract/cli.py +116 -10
- datacontract/data_contract.py +143 -65
- datacontract/engines/data_contract_checks.py +366 -60
- datacontract/engines/data_contract_test.py +50 -4
- datacontract/engines/fastjsonschema/check_jsonschema.py +37 -19
- datacontract/engines/fastjsonschema/s3/s3_read_files.py +3 -2
- datacontract/engines/soda/check_soda_execute.py +22 -3
- datacontract/engines/soda/connections/athena.py +79 -0
- datacontract/engines/soda/connections/duckdb_connection.py +65 -6
- datacontract/engines/soda/connections/kafka.py +4 -2
- datacontract/export/avro_converter.py +20 -3
- datacontract/export/bigquery_converter.py +1 -1
- datacontract/export/dbt_converter.py +36 -7
- datacontract/export/dqx_converter.py +126 -0
- datacontract/export/duckdb_type_converter.py +57 -0
- datacontract/export/excel_exporter.py +923 -0
- datacontract/export/exporter.py +3 -0
- datacontract/export/exporter_factory.py +17 -1
- datacontract/export/great_expectations_converter.py +55 -5
- datacontract/export/{html_export.py → html_exporter.py} +31 -20
- datacontract/export/markdown_converter.py +134 -5
- datacontract/export/mermaid_exporter.py +110 -0
- datacontract/export/odcs_v3_exporter.py +187 -145
- datacontract/export/protobuf_converter.py +163 -69
- datacontract/export/rdf_converter.py +2 -2
- datacontract/export/sodacl_converter.py +9 -1
- datacontract/export/spark_converter.py +31 -4
- datacontract/export/sql_converter.py +6 -2
- datacontract/export/sql_type_converter.py +20 -8
- datacontract/imports/avro_importer.py +63 -12
- datacontract/imports/csv_importer.py +111 -57
- datacontract/imports/excel_importer.py +1111 -0
- datacontract/imports/importer.py +16 -3
- datacontract/imports/importer_factory.py +17 -0
- datacontract/imports/json_importer.py +325 -0
- datacontract/imports/odcs_importer.py +2 -2
- datacontract/imports/odcs_v3_importer.py +351 -151
- datacontract/imports/protobuf_importer.py +264 -0
- datacontract/imports/spark_importer.py +117 -13
- datacontract/imports/sql_importer.py +32 -16
- datacontract/imports/unity_importer.py +84 -38
- datacontract/init/init_template.py +1 -1
- datacontract/integration/datamesh_manager.py +16 -2
- datacontract/lint/resolve.py +112 -23
- datacontract/lint/schema.py +24 -15
- datacontract/model/data_contract_specification/__init__.py +1 -0
- datacontract/model/odcs.py +13 -0
- datacontract/model/run.py +3 -0
- datacontract/output/junit_test_results.py +3 -3
- datacontract/schemas/datacontract-1.1.0.init.yaml +1 -1
- datacontract/schemas/datacontract-1.2.0.init.yaml +91 -0
- datacontract/schemas/datacontract-1.2.0.schema.json +2029 -0
- datacontract/schemas/datacontract-1.2.1.init.yaml +91 -0
- datacontract/schemas/datacontract-1.2.1.schema.json +2058 -0
- datacontract/schemas/odcs-3.0.2.schema.json +2382 -0
- datacontract/templates/datacontract.html +54 -3
- datacontract/templates/datacontract_odcs.html +685 -0
- datacontract/templates/index.html +5 -2
- datacontract/templates/partials/server.html +2 -0
- datacontract/templates/style/output.css +319 -145
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/METADATA +656 -431
- datacontract_cli-0.10.37.dist-info/RECORD +119 -0
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/WHEEL +1 -1
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info/licenses}/LICENSE +1 -1
- datacontract/export/csv_type_converter.py +0 -36
- datacontract/lint/lint.py +0 -142
- datacontract/lint/linters/description_linter.py +0 -35
- datacontract/lint/linters/field_pattern_linter.py +0 -34
- datacontract/lint/linters/field_reference_linter.py +0 -48
- datacontract/lint/linters/notice_period_linter.py +0 -55
- datacontract/lint/linters/quality_schema_linter.py +0 -52
- datacontract/lint/linters/valid_constraints_linter.py +0 -100
- datacontract/model/data_contract_specification.py +0 -327
- datacontract_cli-0.10.23.dist-info/RECORD +0 -113
- /datacontract/{lint/linters → output}/__init__.py +0 -0
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/entry_points.txt +0 -0
- {datacontract_cli-0.10.23.dist-info → datacontract_cli-0.10.37.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
{% macro render_nested_properties(properties, level) %}
|
|
2
|
+
<tr>
|
|
3
|
+
{% for property in properties %}
|
|
4
|
+
<td class="px-4 py-4 whitespace-nowrap">
|
|
5
|
+
|
|
6
|
+
<div class="text-sm font-medium text-gray-900">
|
|
7
|
+
{% for i in range(0,level)%}
|
|
8
|
+
|
|
9
|
+
{% endfor %}
|
|
10
|
+
{% if level > 0 %}
|
|
11
|
+
↳
|
|
12
|
+
{% endif %}
|
|
13
|
+
{{ property.name or "items" }}</div>
|
|
14
|
+
{% if property.primaryKey %}
|
|
15
|
+
<span
|
|
16
|
+
class="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-800 ring-1 ring-inset ring-yellow-600/20">Primary Key</span>
|
|
17
|
+
{% endif %}
|
|
18
|
+
{% if property.partitioned %}
|
|
19
|
+
<span
|
|
20
|
+
class="inline-flex items-center rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-800 ring-1 ring-inset ring-blue-600/20">Partitioned</span>
|
|
21
|
+
{% endif %}
|
|
22
|
+
{% if property.criticalDataElement %}
|
|
23
|
+
<span
|
|
24
|
+
class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-800 ring-1 ring-inset ring-red-600/20">Critical</span>
|
|
25
|
+
{% endif %}
|
|
26
|
+
</td>
|
|
27
|
+
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">{{
|
|
28
|
+
property.businessName or "-" }}
|
|
29
|
+
</td>
|
|
30
|
+
<td class="px-4 py-4 whitespace-nowrap">
|
|
31
|
+
<div class="text-sm text-gray-900">{{ property.logicalType }}</div>
|
|
32
|
+
{% if property.physicalType and property.physicalType !=
|
|
33
|
+
property.logicalType %}
|
|
34
|
+
<div class="text-xs text-gray-500">{{ property.physicalType }}</div>
|
|
35
|
+
{% endif %}
|
|
36
|
+
</td>
|
|
37
|
+
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
38
|
+
{% if property.required %}
|
|
39
|
+
<span class="text-green-600">Yes</span>
|
|
40
|
+
{% else %}
|
|
41
|
+
<span class="text-gray-400">No</span>
|
|
42
|
+
{% endif %}
|
|
43
|
+
</td>
|
|
44
|
+
<td class="px-4 py-4 text-sm text-gray-500">{{ property.description or "-"
|
|
45
|
+
}}
|
|
46
|
+
</td>
|
|
47
|
+
</tr>
|
|
48
|
+
{% if property.properties %}
|
|
49
|
+
{{render_nested_properties(property.properties, level+1)}}
|
|
50
|
+
{% endif %}
|
|
51
|
+
{% if property.items %}
|
|
52
|
+
{{render_nested_properties([property.items], level+1)}}
|
|
53
|
+
{% endif %}
|
|
54
|
+
{% endfor %}
|
|
55
|
+
<!-- Mark the end of the contained fields -->
|
|
56
|
+
<tr style="--tw-divide-y-reverse: 2"></tr>
|
|
57
|
+
{% endmacro %}
|
|
58
|
+
|
|
59
|
+
<!doctype html>
|
|
60
|
+
<html class="h-full bg-gray-100" lang="en">
|
|
61
|
+
<head>
|
|
62
|
+
<title>Data Contract</title>
|
|
63
|
+
<meta charset="UTF-8">
|
|
64
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
65
|
+
{# <script src="https://cdn.tailwindcss.com"></script> #}
|
|
66
|
+
<script src="https://unpkg.com/@panzoom/panzoom@4.6.0/dist/panzoom.min.js"></script>
|
|
67
|
+
|
|
68
|
+
<style>
|
|
69
|
+
{{ style | safe }}
|
|
70
|
+
</style>
|
|
71
|
+
</head>
|
|
72
|
+
<body class="h-full">
|
|
73
|
+
<div class="min-h-full flex flex-col">
|
|
74
|
+
|
|
75
|
+
<nav class="bg-white shadow-sm">
|
|
76
|
+
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
77
|
+
<div class="flex h-16 justify-between">
|
|
78
|
+
<div class="flex">
|
|
79
|
+
<div class="flex flex-shrink-0 items-center mr-6">
|
|
80
|
+
<a class="text-xl text-gray-900 font-semibold" href="/">
|
|
81
|
+
Data Contracts
|
|
82
|
+
</a>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="hidden sm:ml-6 sm:flex sm:items-center">
|
|
86
|
+
<a href="https://datacontract.com" class="text-sky-500 hover:text-gray-700 text-sm font-semibold" target="_blank">datacontract.com</a>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</nav>
|
|
91
|
+
<main class="pb-7">
|
|
92
|
+
|
|
93
|
+
<div class="pt-5 mx-auto max-w-7xl sm:px-6 lg:px-8">
|
|
94
|
+
<div>
|
|
95
|
+
<div class="md:flex md:items-center md:justify-between px-4 sm:px-0">
|
|
96
|
+
<div class="min-w-0 flex-1">
|
|
97
|
+
<h2 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">
|
|
98
|
+
Data Contract</h2>
|
|
99
|
+
<div class="mt-1 flex flex-col sm:mt-1 sm:flex-row sm:flex-wrap sm:space-x-6">
|
|
100
|
+
{{ datacontract.id }}
|
|
101
|
+
</div>
|
|
102
|
+
<div class="mt-1 flex flex-col sm:mt-1 sm:flex-row sm:flex-wrap sm:space-x-4">
|
|
103
|
+
<span
|
|
104
|
+
class="inline-flex items-center rounded-full bg-indigo-100 px-2.5 py-0.5 text-xs font-medium text-gray-800 ">
|
|
105
|
+
<span>Open Data Contract Standard {{ datacontract.apiVersion }}</span>
|
|
106
|
+
</span>
|
|
107
|
+
|
|
108
|
+
{% if datacontract.tags %}
|
|
109
|
+
<div class="flex items-center text-sm text-gray-500 whitespace-nowrap">
|
|
110
|
+
{% for tag in datacontract.tags %}
|
|
111
|
+
<span class="inline-flex items-center rounded-full bg-indigo-100 px-2.5 py-0.5 text-xs font-medium text-gray-800 mr-1">
|
|
112
|
+
<span>{{ tag }}</span>
|
|
113
|
+
</span>
|
|
114
|
+
{% endfor %}
|
|
115
|
+
</div>
|
|
116
|
+
{% endif %}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="mt-5 flex lg:mt-0 lg:ml-4 gap-3 items-center">
|
|
120
|
+
<button
|
|
121
|
+
type="button"
|
|
122
|
+
onclick="document.getElementById('dialog-datacontract-yaml').showModal()"
|
|
123
|
+
class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">
|
|
124
|
+
<svg class="-ml-0.5 mr-1.5 h-5 w-5 text-gray-600" viewBox="-0.5 -0.5 24 24">
|
|
125
|
+
<path d="m4.3125 8.145833333333334 9.104166666666668 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m4.3125 11.020833333333334 9.104166666666668 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m4.3125 5.270833333333334 6.708333333333334 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m4.3125 13.895833333333334 7.1875 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m4.3125 16.770833333333336 3.8333333333333335 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="M8.145833333333334 22.520833333333336h-6.708333333333334a0.9583333333333334 0.9583333333333334 0 0 1 -0.9583333333333334 -0.9583333333333334v-20.125a0.9583333333333334 0.9583333333333334 0 0 1 0.9583333333333334 -0.9583333333333334h12.739125a0.9583333333333334 0.9583333333333334 0 0 1 0.6775416666666667 0.28079166666666666L18.406708333333334 4.3125a0.9583333333333334 0.9583333333333334 0 0 1 0.28079166666666666 0.6775416666666667V8.145833333333334" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m15.045833333333333 21.370833333333334 -4.025 1.15 1.15 -4.025 6.879875 -6.879875a2.032625 2.032625 0 0 1 2.875 2.875Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m18.188208333333332 12.478458333333334 2.875 2.875" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path><path d="m12.170833333333333 18.495833333333334 2.875 2.875" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"></path>
|
|
126
|
+
</svg>
|
|
127
|
+
Show YAML
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div>
|
|
134
|
+
<div class="space-y-6 mt-6">
|
|
135
|
+
<section id="information">
|
|
136
|
+
<div class="px-4 sm:px-0">
|
|
137
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Fundamentals</h1>
|
|
138
|
+
<p class="text-sm text-gray-500">Basic information about the data contract</p>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div class="mt-2 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
142
|
+
<div class="px-6 py-4 space-y-4">
|
|
143
|
+
<dl class="grid grid-cols-1 gap-x-4 gap-y-6 sm:grid-cols-2">
|
|
144
|
+
|
|
145
|
+
{% if datacontract.name %}
|
|
146
|
+
<div>
|
|
147
|
+
<dt class="text-sm font-medium text-gray-900">Name</dt>
|
|
148
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.name }}</dd>
|
|
149
|
+
</div>
|
|
150
|
+
{% endif %}
|
|
151
|
+
|
|
152
|
+
{% if datacontract.version %}
|
|
153
|
+
<div>
|
|
154
|
+
<dt class="text-sm font-medium text-gray-900">Version</dt>
|
|
155
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.version }}</dd>
|
|
156
|
+
</div>
|
|
157
|
+
{% endif %}
|
|
158
|
+
|
|
159
|
+
{% if datacontract.status %}
|
|
160
|
+
<div>
|
|
161
|
+
<dt class="text-sm font-medium text-gray-900">Status</dt>
|
|
162
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.status }}</dd>
|
|
163
|
+
</div>
|
|
164
|
+
{% endif %}
|
|
165
|
+
|
|
166
|
+
{% if datacontract.dataProduct %}
|
|
167
|
+
<div>
|
|
168
|
+
<dt class="text-sm font-medium text-gray-900">Data Product</dt>
|
|
169
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.dataProduct }}</dd>
|
|
170
|
+
</div>
|
|
171
|
+
{% endif %}
|
|
172
|
+
|
|
173
|
+
{% if datacontract.tenant %}
|
|
174
|
+
<div>
|
|
175
|
+
<dt class="text-sm font-medium text-gray-900">Tenant</dt>
|
|
176
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.tenant }}</dd>
|
|
177
|
+
</div>
|
|
178
|
+
{% endif %}
|
|
179
|
+
|
|
180
|
+
{% if datacontract.description %}
|
|
181
|
+
{% if datacontract.description.purpose %}
|
|
182
|
+
<div>
|
|
183
|
+
<dt class="text-sm font-medium text-gray-900">Purpose</dt>
|
|
184
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.description.purpose }}</dd>
|
|
185
|
+
</div>
|
|
186
|
+
{% endif %}
|
|
187
|
+
|
|
188
|
+
{% if datacontract.description.usage %}
|
|
189
|
+
<div>
|
|
190
|
+
<dt class="text-sm font-medium text-gray-900">Usage</dt>
|
|
191
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.description.usage }}</dd>
|
|
192
|
+
</div>
|
|
193
|
+
{% endif %}
|
|
194
|
+
|
|
195
|
+
{% if datacontract.description.limitations %}
|
|
196
|
+
<div>
|
|
197
|
+
<dt class="text-sm font-medium text-gray-900">Limitations</dt>
|
|
198
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.description.limitations }}</dd>
|
|
199
|
+
</div>
|
|
200
|
+
{% endif %}
|
|
201
|
+
{% endif %}
|
|
202
|
+
|
|
203
|
+
{% if datacontract.contractCreatedTs %}
|
|
204
|
+
<div>
|
|
205
|
+
<dt class="text-sm font-medium text-gray-900">Contract Created</dt>
|
|
206
|
+
<dd class="mt-1 text-sm text-gray-700">{{ datacontract.contractCreatedTs }}</dd>
|
|
207
|
+
</div>
|
|
208
|
+
{% endif %}
|
|
209
|
+
</dl>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</section>
|
|
213
|
+
|
|
214
|
+
<section id="diagram" class="mt-6">
|
|
215
|
+
<div class="px-4 sm:px-0">
|
|
216
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Entity Relationship
|
|
217
|
+
Diagram</h1>
|
|
218
|
+
<p class="text-sm text-gray-500">Visual representation of data model relationships</p>
|
|
219
|
+
</div>
|
|
220
|
+
<div class="mt-3">
|
|
221
|
+
<div class="overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
222
|
+
<div class="diagram-container p-4 w-full" id="diagram-container">
|
|
223
|
+
<pre class="mermaid">
|
|
224
|
+
{{ mermaid_diagram }}
|
|
225
|
+
</pre>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
<script type="module">
|
|
230
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
|
|
231
|
+
|
|
232
|
+
mermaid.initialize({
|
|
233
|
+
startOnLoad: false,
|
|
234
|
+
theme: 'neutral'
|
|
235
|
+
});
|
|
236
|
+
await mermaid.run({
|
|
237
|
+
querySelector: '.mermaid',
|
|
238
|
+
postRenderCallback: (id) => {
|
|
239
|
+
const container = document.getElementById("diagram-container");
|
|
240
|
+
const svgElement = container.querySelector("svg");
|
|
241
|
+
|
|
242
|
+
if (svgElement) {
|
|
243
|
+
// Initialize Panzoom
|
|
244
|
+
const panzoomInstance = Panzoom(svgElement, {
|
|
245
|
+
maxScale: 5,
|
|
246
|
+
minScale: 0.5,
|
|
247
|
+
step: 0.1,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Mouse wheel zoom
|
|
251
|
+
container.addEventListener("wheel", (event) => {
|
|
252
|
+
event.preventDefault();
|
|
253
|
+
panzoomInstance.zoomWithWheel(event);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
</script>
|
|
259
|
+
</section>
|
|
260
|
+
|
|
261
|
+
<section id="schema">
|
|
262
|
+
<div class="flex justify-between">
|
|
263
|
+
<div class="px-4 sm:px-0">
|
|
264
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">
|
|
265
|
+
Schema
|
|
266
|
+
</h1>
|
|
267
|
+
<p class="text-sm text-gray-500">The data schema and structure</p>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
{% for schema in datacontract.schema_ %}
|
|
272
|
+
|
|
273
|
+
<div class="mt-3 flow-root">
|
|
274
|
+
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
|
275
|
+
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
|
276
|
+
<div
|
|
277
|
+
class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
|
|
278
|
+
|
|
279
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
280
|
+
<thead class="bg-gray-50">
|
|
281
|
+
<tr>
|
|
282
|
+
<th scope="colgroup" colspan="5"
|
|
283
|
+
class="py-2 pl-4 pr-3 text-left font-semibold text-gray-900 sm:pl-6">
|
|
284
|
+
{% if schema.name %}
|
|
285
|
+
<span class="font-semibold">{{ schema.name }}</span>
|
|
286
|
+
{% endif %}
|
|
287
|
+
{% if schema.physicalName and schema.physicalName != schema.name %}
|
|
288
|
+
<span class="font-mono font-medium text-gray-600">({{ schema.physicalName }})</span>
|
|
289
|
+
{% endif %}
|
|
290
|
+
<span
|
|
291
|
+
class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">{{ schema.physicalType or schema.logicalType }}</span>
|
|
292
|
+
<div class="text-sm font-medium text-gray-500">{{ schema.description }}
|
|
293
|
+
</div>
|
|
294
|
+
{% if schema.dataGranularityDescription %}
|
|
295
|
+
<div class="text-xs text-gray-400">Granularity: {{
|
|
296
|
+
schema.dataGranularityDescription }}
|
|
297
|
+
</div>
|
|
298
|
+
{% endif %}
|
|
299
|
+
</th>
|
|
300
|
+
</tr>
|
|
301
|
+
<tr>
|
|
302
|
+
<th
|
|
303
|
+
class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
304
|
+
Property
|
|
305
|
+
</th>
|
|
306
|
+
<th
|
|
307
|
+
class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
308
|
+
Business Name
|
|
309
|
+
</th>
|
|
310
|
+
<th
|
|
311
|
+
class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
312
|
+
Type
|
|
313
|
+
</th>
|
|
314
|
+
<th
|
|
315
|
+
class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
316
|
+
Required
|
|
317
|
+
</th>
|
|
318
|
+
<th
|
|
319
|
+
class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
320
|
+
Description
|
|
321
|
+
</th>
|
|
322
|
+
</tr>
|
|
323
|
+
</thead>
|
|
324
|
+
<tbody class="divide-y divide-gray-200 bg-white">
|
|
325
|
+
{{ render_nested_properties(schema.properties, 0) }}
|
|
326
|
+
</tbody>
|
|
327
|
+
{% if schema.quality %}
|
|
328
|
+
<tfoot class="divide-y divide-gray-200 bg-white">
|
|
329
|
+
{% for quality in schema.quality %}
|
|
330
|
+
<tr>
|
|
331
|
+
<th scope="colgroup" colspan="5"
|
|
332
|
+
class="py-2 pl-4 pr-3 text-left text-sm font-normal sm:pl-6 bg-white">
|
|
333
|
+
<div class="flex flex-col space-y-1">
|
|
334
|
+
<div class="font-medium">{{ quality.rule }}</div>
|
|
335
|
+
<div class="text-xs text-gray-500">{{ quality.description }}</div>
|
|
336
|
+
{% if quality.dimension %}
|
|
337
|
+
<span
|
|
338
|
+
class="inline-flex items-center rounded-md bg-purple-50 px-2 py-1 text-xs font-medium text-purple-800 ring-1 ring-inset ring-purple-600/20 w-fit">{{ quality.dimension }}</span>
|
|
339
|
+
{% endif %}
|
|
340
|
+
</div>
|
|
341
|
+
</th>
|
|
342
|
+
</tr>
|
|
343
|
+
{% endfor %}
|
|
344
|
+
</tfoot>
|
|
345
|
+
{% endif %}
|
|
346
|
+
</table>
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
</div>
|
|
351
|
+
{% endfor %}
|
|
352
|
+
</section>
|
|
353
|
+
|
|
354
|
+
{% if datacontract.support %}
|
|
355
|
+
<section id="support">
|
|
356
|
+
<div class="px-4 sm:px-0">
|
|
357
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Support</h1>
|
|
358
|
+
<p class="text-sm text-gray-500">Support channels and resources</p>
|
|
359
|
+
</div>
|
|
360
|
+
|
|
361
|
+
<ul role="list"
|
|
362
|
+
class="mt-2 divide-y divide-gray-100 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
363
|
+
{% for support in datacontract.support %}
|
|
364
|
+
<li class="px-6 py-4">
|
|
365
|
+
<div class="flex items-center justify-between">
|
|
366
|
+
<div class="flex items-center">
|
|
367
|
+
<div class="ml-3">
|
|
368
|
+
<p class="text-sm font-medium text-gray-900">{{ support.channel }}</p>
|
|
369
|
+
{% if support.description %}
|
|
370
|
+
<p class="text-sm text-gray-500">{{ support.description }}</p>
|
|
371
|
+
{% endif %}
|
|
372
|
+
{% if support.tool %}
|
|
373
|
+
<span
|
|
374
|
+
class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">{{ support.tool }}</span>
|
|
375
|
+
{% endif %}
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
378
|
+
{% if support.url %}
|
|
379
|
+
<div class="ml-3">
|
|
380
|
+
<a href="{{ support.url }}" target="_blank"
|
|
381
|
+
class="text-sky-500 hover:text-sky-700 text-sm font-medium">{{ support.url
|
|
382
|
+
}}</a>
|
|
383
|
+
</div>
|
|
384
|
+
{% endif %}
|
|
385
|
+
</div>
|
|
386
|
+
</li>
|
|
387
|
+
{% endfor %}
|
|
388
|
+
</ul>
|
|
389
|
+
</section>
|
|
390
|
+
{% endif %}
|
|
391
|
+
|
|
392
|
+
{% if datacontract.price %}
|
|
393
|
+
<section id="pricing">
|
|
394
|
+
<div class="px-4 sm:px-0">
|
|
395
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Pricing</h1>
|
|
396
|
+
<p class="text-sm text-gray-500">Data contract pricing information</p>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
<div
|
|
400
|
+
class="mt-2 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
401
|
+
<div class="px-6 py-4">
|
|
402
|
+
<div class="flex items-center space-x-4">
|
|
403
|
+
<div class="text-2xl font-bold text-gray-900">
|
|
404
|
+
{{ datacontract.price.priceAmount }} {{ datacontract.price.priceCurrency }}
|
|
405
|
+
</div>
|
|
406
|
+
<div class="text-sm text-gray-500">
|
|
407
|
+
per {{ datacontract.price.priceUnit }}
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
</section>
|
|
413
|
+
{% endif %}
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
{% if datacontract.team %}
|
|
417
|
+
<section id="team">
|
|
418
|
+
<div class="px-4 sm:px-0">
|
|
419
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Team</h1>
|
|
420
|
+
<p class="text-sm text-gray-500">Team members and their roles</p>
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<div
|
|
424
|
+
class="mt-2 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
425
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
426
|
+
<thead class="bg-gray-50">
|
|
427
|
+
<tr>
|
|
428
|
+
<th
|
|
429
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
430
|
+
Username
|
|
431
|
+
</th>
|
|
432
|
+
<th
|
|
433
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
434
|
+
Role
|
|
435
|
+
</th>
|
|
436
|
+
<th
|
|
437
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
438
|
+
Date In
|
|
439
|
+
</th>
|
|
440
|
+
<th
|
|
441
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
442
|
+
Date Out
|
|
443
|
+
</th>
|
|
444
|
+
<th
|
|
445
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
446
|
+
Comment
|
|
447
|
+
</th>
|
|
448
|
+
</tr>
|
|
449
|
+
</thead>
|
|
450
|
+
<tbody class="divide-y divide-gray-200 bg-white">
|
|
451
|
+
{% for member in datacontract.team %}
|
|
452
|
+
<tr>
|
|
453
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{
|
|
454
|
+
member.username }}
|
|
455
|
+
</td>
|
|
456
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ member.role }}
|
|
457
|
+
</td>
|
|
458
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ member.dateIn or
|
|
459
|
+
"-" }}
|
|
460
|
+
</td>
|
|
461
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ member.dateOut or
|
|
462
|
+
"-" }}
|
|
463
|
+
</td>
|
|
464
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ member.comment or
|
|
465
|
+
"-" }}
|
|
466
|
+
</td>
|
|
467
|
+
</tr>
|
|
468
|
+
{% endfor %}
|
|
469
|
+
</tbody>
|
|
470
|
+
</table>
|
|
471
|
+
</div>
|
|
472
|
+
</section>
|
|
473
|
+
{% endif %}
|
|
474
|
+
|
|
475
|
+
{% if datacontract.roles %}
|
|
476
|
+
<section id="roles">
|
|
477
|
+
<div class="px-4 sm:px-0">
|
|
478
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Access Roles</h1>
|
|
479
|
+
<p class="text-sm text-gray-500">Access roles and approval workflows</p>
|
|
480
|
+
</div>
|
|
481
|
+
|
|
482
|
+
<div
|
|
483
|
+
class="mt-2 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
484
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
485
|
+
<thead class="bg-gray-50">
|
|
486
|
+
<tr>
|
|
487
|
+
<th
|
|
488
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
489
|
+
Role
|
|
490
|
+
</th>
|
|
491
|
+
<th
|
|
492
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
493
|
+
Access
|
|
494
|
+
</th>
|
|
495
|
+
<th
|
|
496
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
497
|
+
First Level Approver
|
|
498
|
+
</th>
|
|
499
|
+
<th
|
|
500
|
+
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
501
|
+
Second Level Approver
|
|
502
|
+
</th>
|
|
503
|
+
</tr>
|
|
504
|
+
</thead>
|
|
505
|
+
<tbody class="divide-y divide-gray-200 bg-white">
|
|
506
|
+
{% for role in datacontract.roles %}
|
|
507
|
+
<tr>
|
|
508
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{
|
|
509
|
+
role.role }}
|
|
510
|
+
</td>
|
|
511
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
512
|
+
<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset
|
|
513
|
+
{% if role.access == 'read' %}bg-green-50 text-green-700 ring-green-600/20{% elif role.access == 'write' %}bg-blue-50 text-blue-700 ring-blue-600/20{% else %}bg-gray-50 text-gray-700 ring-gray-600/20{% endif %}">
|
|
514
|
+
{{ role.access or "-" }}
|
|
515
|
+
</span>
|
|
516
|
+
</td>
|
|
517
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{
|
|
518
|
+
role.firstLevelApprovers or "-" }}
|
|
519
|
+
</td>
|
|
520
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{
|
|
521
|
+
role.secondLevelApprovers or "-" }}
|
|
522
|
+
</td>
|
|
523
|
+
</tr>
|
|
524
|
+
{% endfor %}
|
|
525
|
+
</tbody>
|
|
526
|
+
</table>
|
|
527
|
+
</div>
|
|
528
|
+
</section>
|
|
529
|
+
{% endif %}
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
{% if datacontract.slaProperties %}
|
|
533
|
+
<section id="sla">
|
|
534
|
+
<div class="px-4 sm:px-0">
|
|
535
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Service Level Agreements</h1>
|
|
536
|
+
<p class="text-sm text-gray-500">SLA properties and commitments</p>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<div class="mt-2 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
540
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
541
|
+
<thead class="bg-gray-50">
|
|
542
|
+
<tr>
|
|
543
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Property</th>
|
|
544
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Value</th>
|
|
545
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Unit</th>
|
|
546
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Element</th>
|
|
547
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Driver</th>
|
|
548
|
+
</tr>
|
|
549
|
+
</thead>
|
|
550
|
+
<tbody class="divide-y divide-gray-200 bg-white">
|
|
551
|
+
{% for sla in datacontract.slaProperties %}
|
|
552
|
+
<tr>
|
|
553
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ sla.property }}</td>
|
|
554
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ sla.value }}</td>
|
|
555
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ sla.unit or "-" }}</td>
|
|
556
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ sla.element or "-" }}</td>
|
|
557
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ sla.driver or "-" }}</td>
|
|
558
|
+
</tr>
|
|
559
|
+
{% endfor %}
|
|
560
|
+
</tbody>
|
|
561
|
+
</table>
|
|
562
|
+
</div>
|
|
563
|
+
</section>
|
|
564
|
+
{% endif %}
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
{% if datacontract.servers %}
|
|
568
|
+
<section id="servers">
|
|
569
|
+
<div class="px-4 sm:px-0">
|
|
570
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900" id="servers">Servers</h1>
|
|
571
|
+
<p class="text-sm text-gray-500">Infrastructure servers of the data contract</p>
|
|
572
|
+
</div>
|
|
573
|
+
|
|
574
|
+
<ul role="list"
|
|
575
|
+
class="mt-2 divide-y divide-gray-100 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
576
|
+
{% for server in datacontract.servers %}
|
|
577
|
+
{{ render_partial('partials/server.html', server_name = server.server, server =
|
|
578
|
+
server) }}
|
|
579
|
+
{% endfor %}
|
|
580
|
+
</ul>
|
|
581
|
+
|
|
582
|
+
</section>
|
|
583
|
+
{% endif %}
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
{% if datacontract.customProperties %}
|
|
587
|
+
<section id="custom-properties">
|
|
588
|
+
<div class="px-4 sm:px-0">
|
|
589
|
+
<h1 class="text-base font-semibold leading-6 text-gray-900">Custom Properties</h1>
|
|
590
|
+
<p class="text-sm text-gray-500">Additional custom properties and metadata</p>
|
|
591
|
+
</div>
|
|
592
|
+
|
|
593
|
+
<div class="mt-2 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
|
|
594
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
595
|
+
<thead class="bg-gray-50">
|
|
596
|
+
<tr>
|
|
597
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Property</th>
|
|
598
|
+
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Value</th>
|
|
599
|
+
</tr>
|
|
600
|
+
</thead>
|
|
601
|
+
<tbody class="divide-y divide-gray-200 bg-white">
|
|
602
|
+
{% for prop in datacontract.customProperties %}
|
|
603
|
+
<tr>
|
|
604
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ prop.property }}</td>
|
|
605
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
606
|
+
{% if prop.value is iterable and prop.value is not string %}
|
|
607
|
+
{% for item in prop.value %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}
|
|
608
|
+
{% else %}
|
|
609
|
+
{{ prop.value }}
|
|
610
|
+
{% endif %}
|
|
611
|
+
</td>
|
|
612
|
+
</tr>
|
|
613
|
+
{% endfor %}
|
|
614
|
+
</tbody>
|
|
615
|
+
</table>
|
|
616
|
+
</div>
|
|
617
|
+
</section>
|
|
618
|
+
{% endif %}
|
|
619
|
+
|
|
620
|
+
</div>
|
|
621
|
+
</div>
|
|
622
|
+
|
|
623
|
+
<div class="mt-6 text-sm text-gray-400">
|
|
624
|
+
Created at {{formatted_date}} with <a href="https://cli.datacontract.com" class="text-gray-400 hover:text-gray-500">Data Contract CLI</a> v{{datacontract_cli_version}}
|
|
625
|
+
</div>
|
|
626
|
+
|
|
627
|
+
</div>
|
|
628
|
+
</main>
|
|
629
|
+
|
|
630
|
+
<dialog id="dialog-datacontract-yaml" class="relative z-10" aria-labelledby="modal-title" aria-modal="true">
|
|
631
|
+
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
|
|
632
|
+
|
|
633
|
+
<div class="fixed inset-0 z-10 w-screen overflow-y-auto">
|
|
634
|
+
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
|
635
|
+
<div class="relative transform rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-4/5 sm:p-6">
|
|
636
|
+
<div class="absolute right-0 top-0 pr-4 pt-4">
|
|
637
|
+
<button type="button" onclick="document.getElementById('dialog-datacontract-yaml').close()" class="rounded-md bg-white text-gray-400 hover:text-gray-500">
|
|
638
|
+
<span class="sr-only">Close</span>
|
|
639
|
+
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
640
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
641
|
+
</svg>
|
|
642
|
+
</button>
|
|
643
|
+
</div>
|
|
644
|
+
<div>
|
|
645
|
+
<div class="mt-3 mb-3 text-center sm:mt-5">
|
|
646
|
+
|
|
647
|
+
<h3 class="text-base font-semibold leading-6 text-gray-900" id="modal-title">Data Contract YAML</h3>
|
|
648
|
+
</div>
|
|
649
|
+
<pre class="overflow-x-auto text-sm bg-gray-50 p-4"><code>{{datacontract_yaml}}</code></pre>
|
|
650
|
+
</div>
|
|
651
|
+
<div class="mt-5 sm:mt-6">
|
|
652
|
+
<button type="button" onclick="document.getElementById('dialog-datacontract-yaml').close()"
|
|
653
|
+
class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Close</button>
|
|
654
|
+
</div>
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
</dialog>
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
<footer class="bg-white mt-auto text-sm text-gray-400">
|
|
662
|
+
<div class="mx-auto max-w-7xl py-5 px-6 md:flex md:items-center md:justify-between lg:px-8">
|
|
663
|
+
<div class="flex justify-center space-x-6 md:order-2">
|
|
664
|
+
<div>
|
|
665
|
+
<a href="https://cli.datacontract.com" class="text-gray-400 hover:text-gray-500 px-2">Data Contract CLI</a>
|
|
666
|
+
|
|
667
|
+
<a href="https://datacontract.com" class="text-gray-400 hover:text-gray-500 px-2">Data Contract Specification</a>
|
|
668
|
+
</div>
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
</div>
|
|
672
|
+
<div class="mt-8 md:order-1 md:mt-0">
|
|
673
|
+
<p class="text-center leading-5 text-gray-400">
|
|
674
|
+
Supported by <a href="https://datacontract-manager.com"
|
|
675
|
+
class="text-gray-400 hover:text-gray-500">Data Contract Manager</a>
|
|
676
|
+
</p>
|
|
677
|
+
</div>
|
|
678
|
+
</div>
|
|
679
|
+
|
|
680
|
+
</footer>
|
|
681
|
+
|
|
682
|
+
</div>
|
|
683
|
+
|
|
684
|
+
</body>
|
|
685
|
+
</html>
|