-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a new JSON editor widget and attached it to the admin pages for…
… Specification Templates and Evaluation Definitions
- Loading branch information
1 parent
b9b9b97
commit 6d1c72e
Showing
20 changed files
with
2,059 additions
and
198 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
...on/services/evaluationservice/dmod/evaluationservice/evaluation_service/forms/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
""" | ||
All custom forms | ||
""" | ||
|
||
from .json import EvaluationDefinitionForm | ||
from .json import SpecificationTemplateForm |
96 changes: 96 additions & 0 deletions
96
python/services/evaluationservice/dmod/evaluationservice/evaluation_service/forms/json.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
""" | ||
Definitions for forms that provide advanced handling for json data | ||
""" | ||
from __future__ import annotations | ||
|
||
import typing | ||
import json | ||
import re | ||
|
||
from pydantic import BaseModel | ||
|
||
from django import forms | ||
|
||
from widgets import JSONArea | ||
|
||
from dmod.evaluations import specification | ||
from dmod.evaluations.specification.base import get_subclasses | ||
|
||
from evaluation_service import models | ||
|
||
BINARY_TYPES = re.compile( | ||
r'((?<!,)\s*\{\s*"type": "string",\s*"format": "binary"\s*},\s*|,\s*\{\s*"type": "string",\s*"format": "binary"\s*}\s*)' | ||
) | ||
""" | ||
A regular expression that finds all type definitions that are strings formatted as bytes | ||
""" | ||
|
||
def get_editor_friendly_model_schema(model: typing.Type[BaseModel]) -> typing.Optional[dict]: | ||
""" | ||
Get the schema for a model and scrub any editor unfriendly type from it | ||
An example of an editor unfriendly type is a string in a binary format | ||
Args: | ||
model: The model whose schema to retrieve | ||
Returns: | ||
A schema for the model if it is available | ||
""" | ||
if hasattr(model, "schema_json"): | ||
json_data = model.schema_json() | ||
|
||
json_data = BINARY_TYPES.sub("", json_data) | ||
|
||
return json.loads(json_data) | ||
return None | ||
|
||
def get_specification_schema_map() -> typing.Dict[str, typing.Any]: | ||
""" | ||
Generate a dictionary mapping specification types to their schemas | ||
Return: | ||
A dictionary mapping the value of a specification type that will be on the template type selector to schema data that is compatible with the client side editor | ||
""" | ||
return { | ||
specification_type.get_specification_type(): get_editor_friendly_model_schema(specification_type) | ||
for specification_type in get_subclasses(specification.TemplatedSpecification) | ||
} | ||
|
||
|
||
class EvaluationDefinitionForm(forms.ModelForm): | ||
""" | ||
A specialized form for EvaluationDefinition that allows its JSON data to be manipulated within a JSONArea | ||
""" | ||
class Meta: | ||
model = models.EvaluationDefinition | ||
fields = "__all__" | ||
|
||
definition = forms.JSONField( | ||
widget=JSONArea( | ||
schema=get_editor_friendly_model_schema(specification.EvaluationSpecification) | ||
) | ||
) | ||
|
||
class SpecificationTemplateForm(forms.ModelForm): | ||
""" | ||
A specialized form for SpecificationTemplate that allows its JSON data to be manipulated within a JSONArea | ||
""" | ||
class Meta: | ||
model = models.SpecificationTemplate | ||
fields = "__all__" | ||
|
||
class Media: | ||
# Include a script to add functionality that will update the json area's | ||
# schema when the template type is changed | ||
js = [ | ||
"evaluation_service/js/template_specification.js" | ||
] | ||
|
||
template_configuration = forms.JSONField( | ||
widget=JSONArea( | ||
extra_data={ | ||
"schemas": get_specification_schema_map() | ||
} | ||
) | ||
) |
18 changes: 18 additions & 0 deletions
18
.../evaluation_service/migrations/0004_alter_specificationtemplate_template_configuration.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Generated by Django 4.1.3 on 2023-07-24 19:28 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('evaluation_service', '0003_specificationtemplate_and_more'), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name='specificationtemplate', | ||
name='template_configuration', | ||
field=models.JSONField(help_text='The configuration that should be applied to a given specification type'), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
...aluationservice/evaluation_service/static/evaluation_service/js/template_specification.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/** | ||
* Supplies custom functions and handling for the SpecificationTemplateForm | ||
*/ | ||
|
||
/** | ||
* Handler for when the template type selector has changed values | ||
*/ | ||
function templateTypeChanged() { | ||
changeConfigurationSchema(this); | ||
} | ||
|
||
/** | ||
* Update the JSON editor with the selected schema | ||
* | ||
* @param {HTMLElement?} selector A select element stating what schema to use | ||
*/ | ||
function changeConfigurationSchema(selector) { | ||
let newSchema = null; | ||
const editorData = getEditorData("template_configuration"); | ||
|
||
if (selector === null || selector === undefined) { | ||
selector = django.jQuery("select[name=template_specification_type]")[0]; | ||
} else if (selector instanceof django.jQuery) { | ||
selector = selector[0]; | ||
} | ||
|
||
if (!(selector.hasOwnProperty("value") || "value" in selector)) { | ||
return; | ||
} | ||
|
||
if (editorData !== null && "schemas" in editorData && selector.value in editorData.schemas) { | ||
newSchema = editorData.schemas[selector.value]; | ||
} | ||
|
||
if (newSchema === null || newSchema === undefined) { | ||
return; | ||
} | ||
|
||
const editor = getEditor("template_configuration"); | ||
|
||
if (editor) { | ||
editor.setSchema(newSchema); | ||
|
||
let currentText = editor.getText(); | ||
|
||
if (currentText === null) { | ||
currentText = ""; | ||
} else { | ||
currentText = currentText.trim(); | ||
} | ||
|
||
if (currentText.length === 0 || currentText.match(/^\{?\s*}?$/)) { | ||
const newData = buildObjectFromSchema(newSchema); | ||
editor.set(newData); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Attach the `templateTypeChanged` function to the 'change' event for the template specification type selector | ||
*/ | ||
function attachSpecificationTypeChanged() { | ||
const selector = django.jQuery("select[name=template_specification_type]"); | ||
selector.on("change", templateTypeChanged); | ||
} | ||
|
||
/** | ||
* Make sure that the change handler for the template type selector is attached and | ||
* that the proper schema is attached to the editor once the page is done loading | ||
*/ | ||
document.addEventListener( | ||
"DOMContentLoaded", | ||
function() { | ||
attachSpecificationTypeChanged(); | ||
changeConfigurationSchema(); | ||
} | ||
); |
Oops, something went wrong.