From 949c7d1ef2cb171ff697434144b6f379b3e505fb Mon Sep 17 00:00:00 2001 From: Joachim Praetorius Date: Thu, 16 May 2024 17:01:43 +0200 Subject: [PATCH] Issues/193 fix all todos in html export (#203) * Make Examples in Fields work - we have to have them declared in the model to make them show up at all :) * Add Definitions in HTML Export - add examples to the model, so we can render them - create new tables akin to what we do for the models * Add examples * Handle nested fields in HTML Export We just go one level deep but add an additional set of rows for fields contained in a models field. * Update CHANGELOG * Update Tests for breaking and changelog Now that we include the `example` property in the field there's more things being pointed out, so adjust the tests accordingly * Handle Model Fields and their nesting through partials - added jinja partials as dependency - extracted the model and the nesting handling out to its own partial * Update definitions - move them to their opwn partial - move enum into the content column - try to highlight the different optional aspects a tad * Move some more blocks into partials * Add partials to manifest * Removew the nested headline --------- Co-authored-by: jochen --- CHANGELOG.md | 1 + MANIFEST.in | 5 +- datacontract/breaking/breaking_rules.py | 4 + datacontract/export/html_export.py | 3 + .../model/data_contract_specification.py | 2 + datacontract/templates/datacontract.html | 631 +----------------- .../partials/datacontract_information.html | 66 ++ .../partials/datacontract_servicelevels.html | 253 +++++++ .../partials/datacontract_terms.html | 44 ++ .../templates/partials/definition.html | 99 +++ datacontract/templates/partials/example.html | 27 + .../templates/partials/model_field.html | 97 +++ datacontract/templates/partials/server.html | 144 ++++ datacontract/templates/style/output.css | 17 +- .../templates/style/tailwind.config.js | 2 +- pyproject.toml | 3 +- tests/test_changelog.py | 27 +- 17 files changed, 810 insertions(+), 615 deletions(-) create mode 100644 datacontract/templates/partials/datacontract_information.html create mode 100644 datacontract/templates/partials/datacontract_servicelevels.html create mode 100644 datacontract/templates/partials/datacontract_terms.html create mode 100644 datacontract/templates/partials/definition.html create mode 100644 datacontract/templates/partials/example.html create mode 100644 datacontract/templates/partials/model_field.html create mode 100644 datacontract/templates/partials/server.html diff --git a/CHANGELOG.md b/CHANGELOG.md index b2cbe4dc..ff6464bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `datacontract import --format jsonschema`: Import from JSON schema (#91) - `datacontract export --format jsonschema`: Improved export by exporting more additional information - `datacontract publish`: Publish the data contract to the Data Mesh Manager +- HTML Export: Added support for Service Levels, Definitions, Examples and nested Fields (one level deep) ## [0.10.3] - 2024-05-05 diff --git a/MANIFEST.in b/MANIFEST.in index 9ee92182..7071c789 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,2 @@ -include datacontract/templates/index.html -include datacontract/templates/datacontract.html -include datacontract/templates/style/output.css \ No newline at end of file +include datacontract/templates/style/output.css +recursive-include datacontract/templates/ **/*.html \ No newline at end of file diff --git a/datacontract/breaking/breaking_rules.py b/datacontract/breaking/breaking_rules.py index ca36f1c5..2ed3d812 100644 --- a/datacontract/breaking/breaking_rules.py +++ b/datacontract/breaking/breaking_rules.py @@ -90,6 +90,10 @@ class BreakingRules: field_tags_removed = Severity.INFO field_tags_updated = Severity.INFO + field_example_added = Severity.INFO + field_example_updated = Severity.INFO + field_example_removed = Severity.INFO + # quality Rules quality_added = Severity.INFO quality_removed = Severity.WARNING diff --git a/datacontract/export/html_export.py b/datacontract/export/html_export.py index 56a8e775..dbf3a843 100644 --- a/datacontract/export/html_export.py +++ b/datacontract/export/html_export.py @@ -4,6 +4,7 @@ import pytz import yaml +import jinja_partials from jinja2 import Environment, PackageLoader, select_autoescape from datacontract.model.data_contract_specification import \ @@ -20,6 +21,8 @@ def to_html(data_contract_spec: DataContractSpecification) -> str: default_for_string=True, ), ) + # Set up for partials + jinja_partials.register_environment(env) # Load the required template # needs to be included in /MANIFEST.in diff --git a/datacontract/model/data_contract_specification.py b/datacontract/model/data_contract_specification.py index 32ca400b..915c3aab 100644 --- a/datacontract/model/data_contract_specification.py +++ b/datacontract/model/data_contract_specification.py @@ -58,6 +58,7 @@ class Definition(pyd.BaseModel): pii: bool = None classification: str = None tags: List[str] = [] + example: str = None class Field(pyd.BaseModel): @@ -86,6 +87,7 @@ class Field(pyd.BaseModel): items: "Field" = None precision: int = None scale: int = None + example: str = None config: Dict[str, Any] = None diff --git a/datacontract/templates/datacontract.html b/datacontract/templates/datacontract.html index ec45ee3c..e7c50a20 100644 --- a/datacontract/templates/datacontract.html +++ b/datacontract/templates/datacontract.html @@ -6,7 +6,7 @@ {# #} @@ -58,78 +58,13 @@

-
-
-

Info

-

Information about the data contract

-
-
- -
- -
-
-
Title
-
{{ datacontract.info.title }}
-
- -
-
Version
-
{{ datacontract.info.version }}
-
- - {% if datacontract.info.status %} -
-
Status
-
{{ datacontract.info.status }}
-
- {% endif %} - - {% if datacontract.info.description %} -
-
Description
-
- {{ datacontract.info.description }} -
-
- {% endif %} - - {% if datacontract.info.owner %} -
-
Owner
-
- {{ datacontract.info.owner }} -
-
- {% endif %} - - {% if datacontract.info.contact %} -
-
Contact
-
- {% if datacontract.info.contact.name %} - {{ datacontract.info.contact.name }} - {% endif %} - {% if datacontract.info.contact.email %} - {{ datacontract.info.contact.email }} - {% endif %} - {% if datacontract.info.contact.url %} - - {% endif %} -
-
- {% endif %} - -
-
-
+
+ {{ render_partial('partials/datacontract_information.html', datacontract = datacontract) }}
{% if datacontract.servers %} -
+

Servers

Servers of the data contract

@@ -138,150 +73,7 @@

Servers
    {% for server_name, server in datacontract.servers.items() %} -
  • -
    - -
    - - {% if server.type %} -
    - -
    - {% endif %} - - {% if server.project %} -
    - -
    - {% endif %} - - {% if server.dataset %} -
    - -
    - {% endif %} - - {% if server.location %} -
    - -
    - {% endif %} - - {% if server.endpointUrl %} -
    - -
    - {% endif %} - - {% if server.account %} -
    - -
    - {% endif %} - - {% if server.host %} -
    - -
    - {% endif %} - - {% if server.port %} -
    - -
    - {% endif %} - - {% if server.catalog %} -
    - -
    - {% endif %} - - {% if server.database %} -
    - -
    - {% endif %} - - {% if server.schema_ %} -
    - -
    - {% endif %} - - {% if server.topic %} -
    - -
    - {% endif %} - - {% if server.path %} -
    - -
    - {% endif %} - - {% if server.format %} -
    - -
    - {% endif %} - - {% if server.delimiter %} -
    - -
    - {% endif %} - -
  • + {{ render_partial('partials/server.html', server_name = server_name, server = server) }} {% endfor %}
@@ -291,51 +83,8 @@

Servers {% if datacontract.terms %} -
-
-

Terms

-

Terms and conditions of the data contract

-
-
- -
- -
-
-
Usage
-
- {{ datacontract.terms.usage }} -
-
- -
-
Limitations
-
- {{ datacontract.terms.limitations }} -
-
- - {% if datacontract.terms.billing %} -
-
Billing
-
- {{ datacontract.terms.billing }} -
-
- {% endif %} - - {% if datacontract.terms.noticePeriod %} -
-
Notice Period
-
- {{ datacontract.terms.noticePeriod }} -
-
- {% endif %} - -
-
-
+
+ {{ render_partial('partials/datacontract_terms.html', datacontract = datacontract) }}
{% endif %} @@ -369,90 +118,9 @@

- {% for field_name, field in model.fields.items() %} - - - -
- {% if field.title %} -
{{ field.title }}
- {% endif %} -
{{ field_name }}
- {# TODO nested fields #} -
- - - {% if field.type %} - {{ field.type }} - {% endif %} - - - {% if field.description %} -
{{ field.description }}
- {% else %} -
No description
- {% endif %} - - {% if field.example %} -
- Example: {{ field.example }} -
- {% endif %} - -
- {% if field.primary %} - primary - {% endif %} - {% if field.required %} - required - {% endif %} - {% if field.unique %} - unique - {% endif %} - {% if field.format %} - format:{{ field.format }} - {% endif %} - {% if field.minLength %} - minLength:{{ field.minLength }} - {% endif %} - {% if field.maxLength %} - maxLength:{{ field.maxLength }} - {% endif %} - {% if field.pattern %} - pattern:{{ field.pattern }} - {% endif %} - {% if field.precision %} - precision:{{ field.precision }} - {% endif %} - {% if field.scale %} - scale:{{ field.scale }} - {% endif %} - {% if field.minimum %} - minimum:{{ field.minimum }} - {% endif %} - {% if field.exclusiveMinimum %} - exclusiveMinimum:{{ field.exclusiveMinimum }} - {% endif %} - {% if field.maximum %} - maximum:{{ field.maximum }} - {% endif %} - {% if field.exclusiveMaximum %} - exclusiveMaximum:{{ field.exclusiveMaximum }} - {% endif %} - {% if field.classification %} - {{ field.classification }} - {% endif %} - {% if field.pii %} - PII - {% endif %} -
- - - - + {{ render_partial('partials/model_field.html', nested = False, field_name=field_name, field = field, level = 0) }} {% endfor %} -

@@ -460,266 +128,36 @@

{% endfor %} -

+ + {% if datacontract.definitions %} +
+
+

Definitions

+

Domain specific definitions in the data contract

+
+ + {% for definition_name, definition in datacontract.definitions.items() %} + {{ render_partial('partials/definition.html', definition_name = definition_name, definition = definition)}} + {% endfor %} +
+ {% endif %} - {# TODO add definitions #} + {% if datacontract.examples %} +
+
+

Examples

+

Examples for models in the data contract

+
+ {% for example in datacontract.examples %} + {{ render_partial('partials/example.html', example = example) }} + {% endfor %} +
+ {% endif %} {% if datacontract.servicelevels %}
-
-

Service Levels

-

Service levels of the data contract

-
-
-
-
- {% if datacontract.servicelevels.availability %} -
-

- Availability -

- {% if datacontract.servicelevels.availability.description %} -
-
Description
-
- {{ datacontract.servicelevels.availability.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.availability.percentage %} -
-
Percentage
-
- {{ datacontract.servicelevels.availability.percentage }} -
-
- {% endif %} -
- {% endif %} - {% if datacontract.servicelevels.retention %} -
-

- Retention -

- {% if datacontract.servicelevels.retention.description %} -
-
Description
-
- {{ datacontract.servicelevels.retention.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.retention.period %} -
-
Period
-
- {{ datacontract.servicelevels.retention.period }} -
-
- {% endif %} - {% if datacontract.servicelevels.retention.unlimited %} -
-
Unlimited
-
- {{ datacontract.servicelevels.retention.unlimited }} -
-
- {% endif %} -
- {% endif %} - {% if datacontract.servicelevels.latency %} -
-

- Latency -

- {% if datacontract.servicelevels.latency.description %} -
-
Description
-
- {{ datacontract.servicelevels.latency.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.latency.threshold %} -
-
Threshold
-
- {{ datacontract.servicelevels.latency.threshold }} -
-
- {% endif %} - {% if datacontract.servicelevels.latency.sourceTimestampField %} -
-
Source Timestamp field
-
- {{ datacontract.servicelevels.latency.sourceTimestampField - }} -
-
- {% endif %} - {% if datacontract.servicelevels.latency.processedTimestampField %} -
-
Processed Timestamp field
-
- {{ datacontract.servicelevels.latency.processedTimestampField - }} -
-
- {% endif %} -
- {% endif %} - {% if datacontract.servicelevels.freshness %} -
-

- Freshness -

- {% if datacontract.servicelevels.freshness.description %} -
-
Description
-
- {{ datacontract.servicelevels.freshness.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.freshness.threshold %} -
-
Threshold
-
- {{ datacontract.servicelevels.freshness.threshold }} -
-
- {% endif %} - {% if datacontract.servicelevels.freshness.timestampField %} -
-
Timestamp field
-
- {{ datacontract.servicelevels.freshness.timestampField }} -
-
- {% endif %} -
- {% endif %} - {% if datacontract.servicelevels.frequency %} -
-

- Frequency -

- {% if datacontract.servicelevels.frequency.description %} -
-
Description
-
- {{ datacontract.servicelevels.frequency.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.frequency.type %} -
-
Type
-
- {{ datacontract.servicelevels.frequency.type }} -
-
- {% endif %} - {% if datacontract.servicelevels.frequency.interval %} -
-
Interval
-
- {{ datacontract.servicelevels.frequency.interval }} -
-
- {% endif %} - {% if datacontract.servicelevels.frequency.cron %} -
-
Cron
-
- {{ datacontract.servicelevels.frequency.cron }} -
-
- {% endif %} -
- {% endif %} - {% if datacontract.servicelevels.support %} -
-

- Support -

- {% if datacontract.servicelevels.support.description %} -
-
Description
-
- {{ datacontract.servicelevels.support.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.support.time %} -
-
Time
-
- {{ datacontract.servicelevels.support.time }} -
-
- {% endif %} - {% if datacontract.servicelevels.support.responseTime %} -
-
Response Time
-
- {{ datacontract.servicelevels.support.responseTime }} -
-
- {% endif %} -
- {% endif %} - {% if datacontract.servicelevels.backup %} -
-

- Backup -

- {% if datacontract.servicelevels.backup.description %} -
-
Description
-
- {{ datacontract.servicelevels.backup.description }} -
-
- {% endif %} - {% if datacontract.servicelevels.backup.internal %} -
-
Interval
-
- {{ datacontract.servicelevels.backup.interval }} -
-
- {% endif %} - {% if datacontract.servicelevels.backup.cron %} -
-
Cron
-
- {{ datacontract.servicelevels.backup.cron }} -
-
- {% endif %} - {% if datacontract.servicelevels.backup.recoveryTime %} -
-
Recovery Time
-
- {{ datacontract.servicelevels.backup.recoveryTime }} -
-
- {% endif %} - {% if datacontract.servicelevels.backup.recoveryPoint %} -
-
Recovery Point
-
- {{ datacontract.servicelevels.backup.recoveryPoint }} -
-
- {% endif %} -
- {% endif %} -
-
-
+ {{ render_partial('partials/datacontract_servicelevels.html', datacontract = datacontract ) }}
{% endif %} @@ -732,8 +170,6 @@

{{ datacontract.quality.type }}

- -
@@ -746,7 +182,6 @@

{% endif %}

-
diff --git a/datacontract/templates/partials/datacontract_information.html b/datacontract/templates/partials/datacontract_information.html new file mode 100644 index 00000000..7134a94e --- /dev/null +++ b/datacontract/templates/partials/datacontract_information.html @@ -0,0 +1,66 @@ +
+

Info

+

Information about the data contract

+
+
+ +
+ +
+
+
Title
+
{{ datacontract.info.title }}
+
+ +
+
Version
+
{{ datacontract.info.version }}
+
+ + {% if datacontract.info.status %} +
+
Status
+
{{ datacontract.info.status }}
+
+ {% endif %} + + {% if datacontract.info.description %} +
+
Description
+
+ {{ datacontract.info.description }} +
+
+ {% endif %} + + {% if datacontract.info.owner %} +
+
Owner
+
+ {{ datacontract.info.owner }} +
+
+ {% endif %} + + {% if datacontract.info.contact %} +
+
Contact
+
+ {% if datacontract.info.contact.name %} + {{ datacontract.info.contact.name }} + {% endif %} + {% if datacontract.info.contact.email %} + {{ datacontract.info.contact.email }} + {% endif %} + {% if datacontract.info.contact.url %} + + {% endif %} +
+
+ {% endif %} + +
+
+
\ No newline at end of file diff --git a/datacontract/templates/partials/datacontract_servicelevels.html b/datacontract/templates/partials/datacontract_servicelevels.html new file mode 100644 index 00000000..fab0579a --- /dev/null +++ b/datacontract/templates/partials/datacontract_servicelevels.html @@ -0,0 +1,253 @@ +
+

Service Levels

+

Service levels of the data contract

+
+
+
+
+ {% if datacontract.servicelevels.availability %} +
+

+ Availability +

+ {% if datacontract.servicelevels.availability.description %} +
+
Description
+
+ {{ datacontract.servicelevels.availability.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.availability.percentage %} +
+
Percentage
+
+ {{ datacontract.servicelevels.availability.percentage }} +
+
+ {% endif %} +
+ {% endif %} + {% if datacontract.servicelevels.retention %} +
+

+ Retention +

+ {% if datacontract.servicelevels.retention.description %} +
+
Description
+
+ {{ datacontract.servicelevels.retention.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.retention.period %} +
+
Period
+
+ {{ datacontract.servicelevels.retention.period }} +
+
+ {% endif %} + {% if datacontract.servicelevels.retention.unlimited %} +
+
Unlimited
+
+ {{ datacontract.servicelevels.retention.unlimited }} +
+
+ {% endif %} +
+ {% endif %} + {% if datacontract.servicelevels.latency %} +
+

+ Latency +

+ {% if datacontract.servicelevels.latency.description %} +
+
Description
+
+ {{ datacontract.servicelevels.latency.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.latency.threshold %} +
+
Threshold
+
+ {{ datacontract.servicelevels.latency.threshold }} +
+
+ {% endif %} + {% if datacontract.servicelevels.latency.sourceTimestampField %} +
+
Source Timestamp field
+
+ {{ datacontract.servicelevels.latency.sourceTimestampField + }} +
+
+ {% endif %} + {% if datacontract.servicelevels.latency.processedTimestampField %} +
+
Processed Timestamp field
+
+ {{ datacontract.servicelevels.latency.processedTimestampField + }} +
+
+ {% endif %} +
+ {% endif %} + {% if datacontract.servicelevels.freshness %} +
+

+ Freshness +

+ {% if datacontract.servicelevels.freshness.description %} +
+
Description
+
+ {{ datacontract.servicelevels.freshness.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.freshness.threshold %} +
+
Threshold
+
+ {{ datacontract.servicelevels.freshness.threshold }} +
+
+ {% endif %} + {% if datacontract.servicelevels.freshness.timestampField %} +
+
Timestamp field
+
+ {{ datacontract.servicelevels.freshness.timestampField }} +
+
+ {% endif %} +
+ {% endif %} + {% if datacontract.servicelevels.frequency %} +
+

+ Frequency +

+ {% if datacontract.servicelevels.frequency.description %} +
+
Description
+
+ {{ datacontract.servicelevels.frequency.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.frequency.type %} +
+
Type
+
+ {{ datacontract.servicelevels.frequency.type }} +
+
+ {% endif %} + {% if datacontract.servicelevels.frequency.interval %} +
+
Interval
+
+ {{ datacontract.servicelevels.frequency.interval }} +
+
+ {% endif %} + {% if datacontract.servicelevels.frequency.cron %} +
+
Cron
+
+ {{ datacontract.servicelevels.frequency.cron }} +
+
+ {% endif %} +
+ {% endif %} + {% if datacontract.servicelevels.support %} +
+

+ Support +

+ {% if datacontract.servicelevels.support.description %} +
+
Description
+
+ {{ datacontract.servicelevels.support.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.support.time %} +
+
Time
+
+ {{ datacontract.servicelevels.support.time }} +
+
+ {% endif %} + {% if datacontract.servicelevels.support.responseTime %} +
+
Response Time
+
+ {{ datacontract.servicelevels.support.responseTime }} +
+
+ {% endif %} +
+ {% endif %} + {% if datacontract.servicelevels.backup %} +
+

+ Backup +

+ {% if datacontract.servicelevels.backup.description %} +
+
Description
+
+ {{ datacontract.servicelevels.backup.description }} +
+
+ {% endif %} + {% if datacontract.servicelevels.backup.internal %} +
+
Interval
+
+ {{ datacontract.servicelevels.backup.interval }} +
+
+ {% endif %} + {% if datacontract.servicelevels.backup.cron %} +
+
Cron
+
+ {{ datacontract.servicelevels.backup.cron }} +
+
+ {% endif %} + {% if datacontract.servicelevels.backup.recoveryTime %} +
+
Recovery Time
+
+ {{ datacontract.servicelevels.backup.recoveryTime }} +
+
+ {% endif %} + {% if datacontract.servicelevels.backup.recoveryPoint %} +
+
Recovery Point
+
+ {{ datacontract.servicelevels.backup.recoveryPoint }} +
+
+ {% endif %} +
+ {% endif %} +
+
+
\ No newline at end of file diff --git a/datacontract/templates/partials/datacontract_terms.html b/datacontract/templates/partials/datacontract_terms.html new file mode 100644 index 00000000..2186df38 --- /dev/null +++ b/datacontract/templates/partials/datacontract_terms.html @@ -0,0 +1,44 @@ +
+

Terms

+

Terms and conditions of the data contract

+
+
+ +
+ +
+
+
Usage
+
+ {{ datacontract.terms.usage }} +
+
+ +
+
Limitations
+
+ {{ datacontract.terms.limitations }} +
+
+ + {% if datacontract.terms.billing %} +
+
Billing
+
+ {{ datacontract.terms.billing }} +
+
+ {% endif %} + + {% if datacontract.terms.noticePeriod %} +
+
Notice Period
+
+ {{ datacontract.terms.noticePeriod }} +
+
+ {% endif %} + +
+
+
\ No newline at end of file diff --git a/datacontract/templates/partials/definition.html b/datacontract/templates/partials/definition.html new file mode 100644 index 00000000..80ecae87 --- /dev/null +++ b/datacontract/templates/partials/definition.html @@ -0,0 +1,99 @@ +
+
+
+
+ + + + + + + + + + + + + + + +
+ {{ definition_name }} + {{ definition.domain }} +
{{ definition.description }}
+
+
+ {% if definition.title %} +
{{ definition.title }}
+ {% endif %} +
{{ definition.name }}
+
+
+
+ {{ definition.type }} + {% if definition.format %} + {{ definition.format }} + {% endif %} +
+
+ {% if definition.example %} +
+ Example: {{ definition.example }} +
+ {% endif %} + {% if definition.tags %} +
+ Tags: + {% for tag in definition.tags %} + {{ tag }} + {% endfor %} +
+ {% endif %} + {% if definition.enum %} +
+ Enum: + {% for value in definition.enum %} + {{ value }} + {% endfor %} +
+ {% endif %} +
+ {% if definition.minLength %} + minLength:{{ definition.minLength }} + {% endif %} + {% if definition.maxLength %} + maxLength:{{ definition.maxLength }} + {% endif %} + {% if definition.pattern %} + pattern:{{ definition.pattern }} + {% endif %} + {% if definition.precision %} + precision:{{ definition.precision }} + {% endif %} + {% if definition.scale %} + scale:{{ definition.scale }} + {% endif %} + {% if definition.minimum %} + minimum:{{ definition.minimum }} + {% endif %} + {% if definition.exclusiveMinimum %} + exclusiveMinimum:{{ definition.exclusiveMinimum }} + {% endif %} + {% if definition.maximum %} + maximum:{{ definition.maximum }} + {% endif %} + {% if definition.exclusiveMaximum %} + exclusiveMaximum:{{ definition.exclusiveMaximum }} + {% endif %} + {% if definition.classification %} + {{ definition.classification }} + {% endif %} + {% if definition.pii %} + PII + {% endif %} +
+
+
+
+
+
\ No newline at end of file diff --git a/datacontract/templates/partials/example.html b/datacontract/templates/partials/example.html new file mode 100644 index 00000000..ce423f5a --- /dev/null +++ b/datacontract/templates/partials/example.html @@ -0,0 +1,27 @@ +
+
+
+
+ + + + + + + + + + + + +
+ {{ example.model }} + {{ example.type }} +
{{ example.description }}
+
+
{{ example.data }}
+
+
+
+
+
\ No newline at end of file diff --git a/datacontract/templates/partials/model_field.html b/datacontract/templates/partials/model_field.html new file mode 100644 index 00000000..02186383 --- /dev/null +++ b/datacontract/templates/partials/model_field.html @@ -0,0 +1,97 @@ +{% if nested %} + + + {# poor mans approach to indenting things a bit #} + {% for i in range(0,level)%} +
 
+ {% endfor %} +
+ ↳ +
+{% else %} + + +{% endif %} +
+ {% if field.title %} +
{{ field.title }}
+ {% endif %} +
{{ field_name }}
+
+ + + {% if field.type %} + {{ field.type }} + {% endif %} + + + {% if field.description %} +
{{ field.description }}
+ {% else %} +
No description
+ {% endif %} + + {% if field.example %} +
+ Example: {{ field.example }} +
+ {% endif %} + +
+ {% if field.primary %} + primary + {% endif %} + {% if field.required %} + required + {% endif %} + {% if field.unique %} + unique + {% endif %} + {% if field.format %} + format:{{ field.format }} + {% endif %} + {% if field.minLength %} + minLength:{{ field.minLength }} + {% endif %} + {% if field.maxLength %} + maxLength:{{ field.maxLength }} + {% endif %} + {% if field.pattern %} + pattern:{{ field.pattern }} + {% endif %} + {% if field.precision %} + precision:{{ field.precision }} + {% endif %} + {% if field.scale %} + scale:{{ field.scale }} + {% endif %} + {% if field.minimum %} + minimum:{{ field.minimum }} + {% endif %} + {% if field.exclusiveMinimum %} + exclusiveMinimum:{{ field.exclusiveMinimum }} + {% endif %} + {% if field.maximum %} + maximum:{{ field.maximum }} + {% endif %} + {% if field.exclusiveMaximum %} + exclusiveMaximum:{{ field.exclusiveMaximum }} + {% endif %} + {% if field.classification %} + {{ field.classification }} + {% endif %} + {% if field.pii %} + PII + {% endif %} +
+ + + +{% if field.fields %} +{% for field_name, field in field.fields.items() %} + {{ render_partial('partials/model_field.html', nested = True, field_name=field_name, field = field, level = level + 1) }} +{% endfor %} + + + +{% endif %} \ No newline at end of file diff --git a/datacontract/templates/partials/server.html b/datacontract/templates/partials/server.html new file mode 100644 index 00000000..aab8fa10 --- /dev/null +++ b/datacontract/templates/partials/server.html @@ -0,0 +1,144 @@ +
  • +
    + +
    + + {% if server.type %} +
    + +
    + {% endif %} + + {% if server.project %} +
    + +
    + {% endif %} + + {% if server.dataset %} +
    + +
    + {% endif %} + + {% if server.location %} +
    + +
    + {% endif %} + + {% if server.endpointUrl %} +
    + +
    + {% endif %} + + {% if server.account %} +
    + +
    + {% endif %} + + {% if server.host %} +
    + +
    + {% endif %} + + {% if server.port %} +
    + +
    + {% endif %} + + {% if server.catalog %} +
    + +
    + {% endif %} + + {% if server.database %} +
    + +
    + {% endif %} + + {% if server.schema_ %} +
    + +
    + {% endif %} + + {% if server.topic %} +
    + +
    + {% endif %} + + {% if server.path %} +
    + +
    + {% endif %} + + {% if server.format %} +
    + +
    + {% endif %} + + {% if server.delimiter %} +
    + +
    + {% endif %} + +
  • \ No newline at end of file diff --git a/datacontract/templates/style/output.css b/datacontract/templates/style/output.css index 5ffc44d1..56c62617 100644 --- a/datacontract/templates/style/output.css +++ b/datacontract/templates/style/output.css @@ -757,6 +757,10 @@ video { width: 2.5rem; } +.w-2 { + width: 0.5rem; +} + .w-2\/12 { width: 16.666667%; } @@ -781,6 +785,10 @@ video { width: 18rem; } +.w-9\/12 { + width: 75%; +} + .w-full { width: 100%; } @@ -858,11 +866,6 @@ video { column-gap: 1rem; } -.gap-x-6 { - -moz-column-gap: 1.5rem; - column-gap: 1.5rem; -} - .gap-y-6 { row-gap: 1.5rem; } @@ -1381,10 +1384,6 @@ video { flex-direction: row; } - .sm\:flex-col { - flex-direction: column; - } - .sm\:flex-wrap { flex-wrap: wrap; } diff --git a/datacontract/templates/style/tailwind.config.js b/datacontract/templates/style/tailwind.config.js index 1aa627c6..baf2346c 100644 --- a/datacontract/templates/style/tailwind.config.js +++ b/datacontract/templates/style/tailwind.config.js @@ -1,5 +1,5 @@ module.exports = { - content: ["../datacontract.html", "../index.html"], + content: ["../datacontract.html", "../index.html", "../partials/model_field.html", "../partials/definition.html", "../partials/datacontract_information.html", "../partials/datacontract_servicelevels.html", "../partials/datacontract_terms.html", "../partials/example.html"], theme: { }, plugins: [], } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 630ede12..59dffb99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,8 @@ dependencies = [ "deltalake~=0.17.0", "boto3>=1.34.41,<1.34.99", "botocore>=1.34.41,<1.34.99", - "jsonschema>=4.22" + "jsonschema>=4.22", + "jinja_partials >= 0.2.1" ] [project.optional-dependencies] diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 90a8bf32..fce7dccd 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -599,7 +599,7 @@ def test_definition_added(): output = result.stdout assert result.exit_code == 0 - assert "16 changes: 0 error, 13 warning, 3 info\n" in output + assert "17 changes: 0 error, 13 warning, 4 info\n" in output assert ( r"""warning [field_ref_added] at ./fixtures/breaking/datacontract-definitions-v2.yaml @@ -705,6 +705,13 @@ def test_definition_added(): added with value: `['my_enum']`""" in output ) + assert ( + """info [field_example_added] at +./fixtures/breaking/datacontract-definitions-v2.yaml + in models.my_table.fields.my_field.example + added with value: `my_example`""" + in output + ) def test_definition_removed(): @@ -719,7 +726,7 @@ def test_definition_removed(): output = result.stdout assert result.exit_code == 0 - assert "16 changes: 3 error, 9 warning, 4 info\n" in output + assert "17 changes: 3 error, 9 warning, 5 info\n" in output assert ( r"""warning [field_ref_removed] at ./fixtures/breaking/datacontract-definitions-v1.yaml @@ -825,6 +832,13 @@ def test_definition_removed(): removed field property""" in output ) + assert ( + """info [field_example_removed] at +./fixtures/breaking/datacontract-definitions-v1.yaml + in models.my_table.fields.my_field.example + removed field property""" + in output + ) def test_definition_updated(): @@ -839,7 +853,7 @@ def test_definition_updated(): output = result.stdout assert result.exit_code == 0 - assert "16 changes: 12 error, 1 warning, 3 info\n" in output + assert "17 changes: 12 error, 1 warning, 4 info\n" in output assert ( r"""warning [field_ref_updated] at ./fixtures/breaking/datacontract-definitions-v3.yaml @@ -946,3 +960,10 @@ def test_definition_updated(): changed from `['my_enum']` to `['my_enum_2']`""" in output ) + assert ( + """info [field_example_updated] at +./fixtures/breaking/datacontract-definitions-v3.yaml + in models.my_table.fields.my_field.example + changed from `my_example` to `my_example_2`""" + in output + )