datacontract-cli 0.9.8__py3-none-any.whl → 0.10.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.
@@ -0,0 +1,502 @@
1
+ <!doctype html>
2
+ <html class="h-full bg-gray-100" lang="en">
3
+ <head>
4
+ <title>Data Contract</title>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ {# <script src="https://cdn.tailwindcss.com"></script> #}
8
+ <style>
9
+ {{style | safe }}
10
+ </style>
11
+ </head>
12
+ <body class="h-full">
13
+
14
+ <div class="min-h-full flex flex-col">
15
+
16
+ <nav class="bg-white shadow-sm">
17
+ <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
18
+ <div class="flex h-16 justify-between">
19
+ <div class="flex">
20
+ <div class="flex flex-shrink-0 items-center mr-6">
21
+ <a class="text-xl text-gray-900 font-semibold" href="/">
22
+ Data Contract
23
+ </a>
24
+ </div>
25
+ </div>
26
+ <div class="hidden sm:ml-6 sm:flex sm:items-center">
27
+ <a href="https://datacontract.com" class="text-sky-500 hover:text-gray-700 text-sm font-semibold" target="_blank">datacontract.com</a>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </nav>
32
+
33
+ <main class="pb-7">
34
+
35
+ <div class="pt-5 mx-auto max-w-7xl sm:px-6 lg:px-8">
36
+ <div>
37
+ <div class="lg:flex lg:items-center lg:justify-between px-4 sm:px-0">
38
+ <div class="min-w-0 flex-1">
39
+ <h2 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">
40
+ Data Contract</h2>
41
+ <div class="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-6">
42
+ {{ datacontract.id }}
43
+ </div>
44
+ </div>
45
+ <div class="mt-5 flex lg:mt-0 lg:ml-4 gap-3 items-center">
46
+ <button
47
+ type="button"
48
+ onclick="document.getElementById('dialog-datacontract-yaml').showModal()"
49
+ 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">
50
+ <svg class="-ml-0.5 mr-1.5 h-5 w-5 text-gray-600" viewBox="-0.5 -0.5 24 24" xmlns="http://www.w3.org/2000/svg">
51
+ <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>
52
+ </svg>
53
+ Show YAML
54
+ </button>
55
+ </div>
56
+ </div>
57
+
58
+
59
+ </div>
60
+
61
+ <div>
62
+
63
+ <div class="space-y-6 mt-6">
64
+
65
+
66
+ <section>
67
+ <div class=" px-4 sm:px-0">
68
+ <h1 class="text-base font-semibold leading-6 text-gray-900" id="info">Info</h1>
69
+ <p class="text-sm text-gray-500">Information about the data contract</p>
70
+ </div>
71
+ <div class="mt-2 overflow-hidden shadow sm:rounded-lg bg-white">
72
+
73
+ <div class="px-4 py-5 sm:px-6">
74
+
75
+ <dl class="grid grid-cols-1 gap-x-4 gap-y-6 sm:grid-cols-2">
76
+ <div class="sm:col-span-1">
77
+ <dt class="text-sm font-medium text-gray-500">Title</dt>
78
+ <dd class="mt-1 text-sm text-gray-900">{{ datacontract.info.title }}</dd>
79
+ </div>
80
+
81
+ <div class="sm:col-span-1">
82
+ <dt class="text-sm font-medium text-gray-500">Version</dt>
83
+ <dd class="mt-1 text-sm text-gray-900">{{ datacontract.info.version }}</dd>
84
+ </div>
85
+
86
+ {% if datacontract.info.description %}
87
+ <div class="sm:col-span-2">
88
+ <dt class="text-sm font-medium text-gray-500">Description</dt>
89
+ <dd class="mt-1 text-sm text-gray-900" >
90
+ <span class="whitespace-pre-wrap">{{ datacontract.info.description }}</span>
91
+ </dd>
92
+ </div>
93
+ {% endif %}
94
+
95
+ {% if datacontract.info.owner %}
96
+ <div class="sm:col-span-1">
97
+ <dt class="text-sm font-medium text-gray-500">Owner</dt>
98
+ <dd class="mt-1 text-sm text-gray-900">
99
+ <span>{{ datacontract.info.owner }}</span>
100
+ </dd>
101
+ </div>
102
+ {% endif %}
103
+
104
+ {% if datacontract.info.contact %}
105
+ <div class="sm:col-span-1">
106
+ <dt class="text-sm font-medium text-gray-500">Contact</dt>
107
+ <dd class="mt-1 text-sm text-gray-900">
108
+ {% if datacontract.info.contact.name %}
109
+ {{ datacontract.info.contact.name }}
110
+ {% endif %}
111
+ {% if datacontract.info.contact.email %}
112
+ <a href="mailto:{{ datacontract.info.contact.email }}" class="text-sky-500 hover:text-gray-700">{{ datacontract.info.contact.email }}</a>
113
+ {% endif %}
114
+ {% if datacontract.info.contact.url %}
115
+ <div>
116
+ <a href="{{ datacontract.info.contact.url }}" class="text-sky-500 hover:text-gray-700">{{ datacontract.info.contact.url }}</a>
117
+ </div>
118
+ {% endif %}
119
+ </dd>
120
+ </div>
121
+ {% endif %}
122
+
123
+ </dl>
124
+ </div>
125
+ </div>
126
+ </section>
127
+
128
+
129
+ {% if datacontract.servers %}
130
+ <section>
131
+ <div class="px-4 sm:px-0">
132
+ <h1 class="text-base font-semibold leading-6 text-gray-900" id="servers">Servers</h1>
133
+ <p class="text-sm text-gray-500">Servers of the data contract</p>
134
+ </div>
135
+
136
+ <ul role="list" class="mt-2 divide-y divide-gray-100 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-lg">
137
+
138
+ {% for server_name, server in datacontract.servers.items() %}
139
+ <li class="relative flex gap-x-6 px-4 py-5 sm:px-6">
140
+ <div class="flex items-center gap-x-4">
141
+ <div class="hidden sm:flex sm:flex-col">
142
+ <dt class="text-sm font-medium text-gray-500">Server</dt>
143
+ <dd class="mt-1 text-sm text-gray-900">{{server_name}}</dd>
144
+ </div>
145
+ </div>
146
+
147
+ {% if server.type %}
148
+ <div class="flex items-center gap-x-4">
149
+ <div class="hidden sm:flex sm:flex-col">
150
+ <dt class="text-sm font-medium text-gray-500">Type</dt>
151
+ <dd class="mt-1 text-sm text-gray-900">{{server.type}}</dd>
152
+ </div>
153
+ </div>
154
+ {% endif %}
155
+
156
+ {% if server.project %}
157
+ <div class="flex items-center gap-x-4">
158
+ <div class="hidden sm:flex sm:flex-col">
159
+ <dt class="text-sm font-medium text-gray-500">Project</dt>
160
+ <dd class="mt-1 text-sm text-gray-900">{{server.project}}</dd>
161
+ </div>
162
+ </div>
163
+ {% endif %}
164
+
165
+ {% if server.dataset %}
166
+ <div class="flex items-center gap-x-4">
167
+ <div class="hidden sm:flex sm:flex-col">
168
+ <dt class="text-sm font-medium text-gray-500">Dataset</dt>
169
+ <dd class="mt-1 text-sm text-gray-900">{{server.dataset}}</dd>
170
+ </div>
171
+ </div>
172
+ {% endif %}
173
+
174
+ {% if server.location %}
175
+ <div class="flex items-center gap-x-4">
176
+ <div class="hidden sm:flex sm:flex-col">
177
+ <dt class="text-sm font-medium text-gray-500">Location</dt>
178
+ <dd class="mt-1 text-sm text-gray-900">{{server.location}}</dd>
179
+ </div>
180
+ </div>
181
+ {% endif %}
182
+
183
+ {% if server.endpointUrl %}
184
+ <div class="flex items-center gap-x-4">
185
+ <div class="hidden sm:flex sm:flex-col">
186
+ <dt class="text-sm font-medium text-gray-500">Endpoint URL</dt>
187
+ <dd class="mt-1 text-sm text-gray-900">{{server.endpointUrl}}</dd>
188
+ </div>
189
+ </div>
190
+ {% endif %}
191
+
192
+ {% if server.account %}
193
+ <div class="flex items-center gap-x-4">
194
+ <div class="hidden sm:flex sm:flex-col">
195
+ <dt class="text-sm font-medium text-gray-500">Account</dt>
196
+ <dd class="mt-1 text-sm text-gray-900">{{server.account}}</dd>
197
+ </div>
198
+ </div>
199
+ {% endif %}
200
+
201
+ {% if server.host %}
202
+ <div class="flex items-center gap-x-4">
203
+ <div class="hidden sm:flex sm:flex-col">
204
+ <dt class="text-sm font-medium text-gray-500">Host</dt>
205
+ <dd class="mt-1 text-sm text-gray-900">{{server.host}}</dd>
206
+ </div>
207
+ </div>
208
+ {% endif %}
209
+
210
+ {% if server.port %}
211
+ <div class="flex items-center gap-x-4">
212
+ <div class="hidden sm:flex sm:flex-col">
213
+ <dt class="text-sm font-medium text-gray-500">Port</dt>
214
+ <dd class="mt-1 text-sm text-gray-900">{{server.port}}</dd>
215
+ </div>
216
+ </div>
217
+ {% endif %}
218
+
219
+ {% if server.catalog %}
220
+ <div class="flex items-center gap-x-4">
221
+ <div class="hidden sm:flex sm:flex-col">
222
+ <dt class="text-sm font-medium text-gray-500">Catalog</dt>
223
+ <dd class="mt-1 text-sm text-gray-900">{{server.catalog}}</dd>
224
+ </div>
225
+ </div>
226
+ {% endif %}
227
+
228
+ {% if server.database %}
229
+ <div class="flex items-center gap-x-4">
230
+ <div class="hidden sm:flex sm:flex-col">
231
+ <dt class="text-sm font-medium text-gray-500">Database</dt>
232
+ <dd class="mt-1 text-sm text-gray-900">{{server.database}}</dd>
233
+ </div>
234
+ </div>
235
+ {% endif %}
236
+
237
+ {% if server.schema_ %}
238
+ <div class="flex items-center gap-x-4">
239
+ <div class="hidden sm:flex sm:flex-col">
240
+ <dt class="text-sm font-medium text-gray-500">Schema</dt>
241
+ <dd class="mt-1 text-sm text-gray-900">{{server.schema_}}</dd>
242
+ </div>
243
+ </div>
244
+ {% endif %}
245
+
246
+ {% if server.topic %}
247
+ <div class="flex items-center gap-x-4">
248
+ <div class="hidden sm:flex sm:flex-col">
249
+ <dt class="text-sm font-medium text-gray-500">Topic</dt>
250
+ <dd class="mt-1 text-sm text-gray-900">{{server.topic}}</dd>
251
+ </div>
252
+ </div>
253
+ {% endif %}
254
+
255
+ {% if server.path %}
256
+ <div class="flex items-center gap-x-4">
257
+ <div class="hidden sm:flex sm:flex-col">
258
+ <dt class="text-sm font-medium text-gray-500">Path</dt>
259
+ <dd class="mt-1 text-sm text-gray-900">{{server.path}}</dd>
260
+ </div>
261
+ </div>
262
+ {% endif %}
263
+
264
+ {% if server.format %}
265
+ <div class="flex items-center gap-x-4">
266
+ <div class="hidden sm:flex sm:flex-col">
267
+ <dt class="text-sm font-medium text-gray-500">Format</dt>
268
+ <dd class="mt-1 text-sm text-gray-900">{{server.format}}</dd>
269
+ </div>
270
+ </div>
271
+ {% endif %}
272
+
273
+ {% if server.delimiter %}
274
+ <div class="flex items-center gap-x-4">
275
+ <div class="hidden sm:flex sm:flex-col">
276
+ <dt class="text-sm font-medium text-gray-500">Delimiter</dt>
277
+ <dd class="mt-1 text-sm text-gray-900">{{server.delimiter}}</dd>
278
+ </div>
279
+ </div>
280
+ {% endif %}
281
+
282
+ </li>
283
+ {% endfor %}
284
+
285
+ </ul>
286
+
287
+ </section>
288
+ {% endif %}
289
+
290
+
291
+ {% if datacontract.terms %}
292
+ <section>
293
+ <div class="px-4 sm:px-0">
294
+ <h1 class="text-base font-semibold leading-6 text-gray-900" id="terms">Terms</h1>
295
+ <p class="text-sm text-gray-500">Terms and conditions of the data contract</p>
296
+ </div>
297
+ <div class="mt-2 overflow-hidden shadow sm:rounded-lg bg-white">
298
+
299
+ <div class="px-4 py-5 sm:px-6">
300
+
301
+ <dl class="grid grid-cols-1 gap-x-4 gap-y-6 sm:grid-cols-2">
302
+ <div class="sm:col-span-1">
303
+ <dt class="text-sm font-medium text-gray-500">Usage</dt>
304
+ <dd class="mt-1 text-sm text-gray-900" >
305
+ <span class="whitespace-pre-wrap">{{ datacontract.terms.usage }}</span>
306
+ </dd>
307
+ </div>
308
+
309
+ <div class="sm:col-span-1">
310
+ <dt class="text-sm font-medium text-gray-500">Limitations</dt>
311
+ <dd class="mt-1 text-sm text-gray-900" >
312
+ <span class="whitespace-pre-wrap">{{ datacontract.terms.limitations }}</span>
313
+ </dd>
314
+ </div>
315
+
316
+ {% if datacontract.terms.billing %}
317
+ <div class="sm:col-span-1">
318
+ <dt class="text-sm font-medium text-gray-500">Billing</dt>
319
+ <dd class="mt-1 text-sm text-gray-900" >
320
+ <span class="whitespace-pre-wrap">{{ datacontract.terms.billing }}</span>
321
+ </dd>
322
+ </div>
323
+ {% endif %}
324
+
325
+ {% if datacontract.terms.noticePeriod %}
326
+ <div class="sm:col-span-1">
327
+ <dt class="text-sm font-medium text-gray-500">Notice Period</dt>
328
+ <dd class="mt-1 text-sm text-gray-900 flex" >
329
+ <span class="whitespace-pre-wrap">{{ datacontract.terms.noticePeriod }}</span>
330
+ </dd>
331
+ </div>
332
+ {% endif %}
333
+
334
+ </dl>
335
+ </div>
336
+ </div>
337
+ </section>
338
+ {% endif %}
339
+
340
+
341
+ <section id="models">
342
+ <div class="flex justify-between">
343
+ <div class="px-4 sm:px-0">
344
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
345
+ Data Model
346
+ </h1>
347
+ <p class="text-sm text-gray-500">The logical data model</p>
348
+ </div>
349
+ </div>
350
+
351
+ {% for model_name, model in datacontract.models.items() %}
352
+
353
+ <div class="mt-3 flow-root">
354
+ <div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
355
+ <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
356
+ <div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
357
+
358
+ <table class="min-w-full divide-y divide-gray-300">
359
+ <thead class="bg-gray-50">
360
+ <tr>
361
+ <th scope="colgroup" colspan="4" class="py-2 pl-4 pr-3 text-left font-semibold text-gray-900 sm:pl-6">
362
+ <span>{{ model_name }}</span>
363
+ <span 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">{{ model.type }}</span>
364
+ <div class="text-sm font-medium text-gray-500">{{ model.description }}</div>
365
+ </th>
366
+
367
+ </tr>
368
+ </thead>
369
+ <tbody class="divide-y divide-gray-200 bg-white">
370
+
371
+ {% for field_name, field in model.fields.items() %}
372
+
373
+ <tr>
374
+ <td class="whitespace-nowrap py-2 pl-4 pr-2 text-sm font-medium text-gray-900 sm:pl-6 w-3/12">
375
+ <div class="py-2 text-sm">
376
+ {{ field_name }}
377
+ {# TODO nested fields #}
378
+ </div>
379
+ </td>
380
+ <td class="whitespace-nowrap px-1 py-2 text-sm text-gray-500 w-16">
381
+ {% if field.required %}
382
+ <span class="inline-flex items-center rounded-md bg-gray-50 px-1 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" title="required">R</span>
383
+ {% endif %}
384
+ {% if field.unique %}
385
+ <span class="inline-flex items-center rounded-md bg-gray-50 px-1 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" title="unique">U</span>
386
+ {% endif %}
387
+ </td>
388
+ <td class="whitespace-nowrap px-1 py-2 text-sm text-gray-500 w-1/12">
389
+ {% if field.type %}
390
+ {{ field.type }}
391
+ {% endif %}
392
+ </td>
393
+ <td class="px-3 py-2 text-sm text-gray-500 w-7/12">
394
+ <div class="text-gray-400">{{ field.description or "No description" }}</div>
395
+ {# TODO add format information #}
396
+ </td>
397
+
398
+ </tr>
399
+ {% endfor %}
400
+
401
+ </tbody>
402
+ </table>
403
+ </div>
404
+ </div>
405
+ </div>
406
+ </div>
407
+ {% endfor %}
408
+
409
+ </section>
410
+
411
+ {# TODO add definitions #}
412
+
413
+ {# TODO add service levels #}
414
+
415
+ {% if quality_specification %}
416
+ <section id="quality">
417
+ <div class="px-4 sm:px-0">
418
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
419
+ Quality
420
+ </h1>
421
+ <p class="text-sm text-gray-500">
422
+ <span>{{ datacontract.quality.type }}</span>
423
+ </p>
424
+
425
+
426
+ </div>
427
+ <div class="mt-2 overflow-hidden shadow sm:rounded-lg bg-white">
428
+ <div class="px-4 py-5 sm:px-6">
429
+ <div id="schema-specification" >
430
+ <pre><code class="text-sm">{{ quality_specification }}</code></pre>
431
+ </div>
432
+ </div>
433
+ </div>
434
+ </section>
435
+ {% endif %}
436
+
437
+ </div>
438
+
439
+ </div>
440
+
441
+ <div class="mt-6 text-sm text-gray-400">
442
+ 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}}
443
+ </div>
444
+
445
+ </div>
446
+ </main>
447
+
448
+ <dialog id="dialog-datacontract-yaml" class="relative z-10" aria-labelledby="modal-title" aria-modal="true">
449
+ <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
450
+
451
+ <div class="fixed inset-0 z-10 w-screen overflow-y-auto">
452
+ <div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
453
+ <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">
454
+ <div class="absolute right-0 top-0 pr-4 pt-4">
455
+ <button type="button" onclick="document.getElementById('dialog-datacontract-yaml').close()" class="rounded-md bg-white text-gray-400 hover:text-gray-500">
456
+ <span class="sr-only">Close</span>
457
+ <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
458
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
459
+ </svg>
460
+ </button>
461
+ </div>
462
+ <div>
463
+ <div class="mt-3 mb-3 text-center sm:mt-5">
464
+
465
+ <h3 class="text-base font-semibold leading-6 text-gray-900" id="modal-title">Data Contract YAML</h3>
466
+ </div>
467
+ <pre class="overflow-x-auto text-sm bg-gray-50 p-4"><code>{{datacontract_yaml}}</code></pre>
468
+ </div>
469
+ <div class="mt-5 sm:mt-6">
470
+ <button type="button" onclick="document.getElementById('dialog-datacontract-yaml').close()"
471
+ 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>
472
+ </div>
473
+ </div>
474
+ </div>
475
+ </div>
476
+ </dialog>
477
+
478
+
479
+ <footer class="bg-white mt-auto text-sm text-gray-400">
480
+ <div class="mx-auto max-w-7xl py-5 px-6 md:flex md:items-center md:justify-between lg:px-8">
481
+ <div class="flex justify-center space-x-6 md:order-2">
482
+ <div>
483
+ <a href="https://cli.datacontract.com" class="text-gray-400 hover:text-gray-500 px-2">Data Contract CLI</a>
484
+
485
+ <a href="https://datacontract.com" class="text-gray-400 hover:text-gray-500 px-2">Data Contract Specification</a>
486
+ </div>
487
+
488
+
489
+ </div>
490
+ <div class="mt-8 md:order-1 md:mt-0">
491
+ <p class="text-center leading-5 text-gray-400">
492
+ Supported with ❤️ by <a href="https://datamesh-manager.com" class="text-gray-400 hover:text-gray-500">Data Mesh Manager</a>
493
+ </p>
494
+ </div>
495
+ </div>
496
+
497
+ </footer>
498
+
499
+ </div>
500
+
501
+ </body>
502
+ </html>