-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patharchitecture.qmd
191 lines (132 loc) · 12.7 KB
/
architecture.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
---
title: "Metadata schema manager"
format:
# html:
# embed-resources: true
# theme: ../sass/main.scss
# toc: true
# title-block-banner: true
# title-block-banner-color: primary
# pdf:
# language: en-GB
# date-format: iso
gfm: default
rst: default
number-sections: true
---
# How to use
Most of the Javascript files contained in this repository define classes used for the schema management and application. However, two of these files define global variables and kicks off whatever needs to happen: ["manager.js"](src/manager.js) for the schema maanager and ["annotator.js"](src/annotator.js) for the metadata application form. Each of them hooks to one or two specific HTML elements, described in @sec-html. The variables defined in each of these scripts are documented in the scripts themselves.
The HTML page that calls these scripts needs to call ["doms"](src/doms.js), ["fields"](src/fields.js), ["schema"](src/schema.js) and ["httprequests"](src/httprequests.js), followed by either ["manager"](src/manager.js) or ["annotator"](src/annotator.js):
```html
<script src="doms.js"></script>
<script src="fields.js"></script>
<script src="schema.js"></script>
<script src="httprequests.js"></script>
<script src="manager.js"></script>
```
Or, for example, given a Jinja2 template:
```djangotemplate
{% for file in ['doms', 'fields', 'schema', 'httprequests', 'manager'] %}
<script src="{{'dist/{}.js'.format(file)}}"></script>
{% endfor %}
```
## HTML Elements {#sec-html}
The file from which ["manager.js"](src/manager.js) is called should contain:
- An element with id "metadata_template_list_container" (as defined at the beginning of manager.js)
- An element with the custom tag `url-list` and the attributes described in @tbl-urls. The last two attributes are used to focus on the tabs corresponding to the latest schema that was modified (created, edited, published, deleted or archived).
- A [Bootstrap 5.2 Modal](https://getbootstrap.com/docs/5.2/components/modal/) following the model of @lst-modal, which is used for confirmation dialogs.
Attribute | Value description
--- | ----------
`new` | url used to post schemas (on creation, editing or publication)
`list` | url to request the list of existing schemas
`delete` | url to post the information of a draft schema that must be deleted
`archive` | url to post the information of a published schema that is archived
`realm` | the name of the current realm
`schema-name` | name of the latest schema modified
`schema-version` | version of the latest schema modified
: Attributes to include in the `url-list` tag for the metadata schema manager. {#tbl-urls}
<!-- When the code is published, we can just link to the lines in the jinja template. -->
```{#lst-modal .html lst-cap="Confirmation modal for metadata schema manager."}
<div class="modal" id="confirmation-dialog" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">Are you sure?</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form id="confirmation-form">
<div class="modal-body">
<p id="confirmation-text">.</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" id="action">I'm sure</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
</div>
</form>
</div>
</div>
</div>
```
The file from which ["annotator.js"](src/annotator.js) is called should contain an element with id "metadata_form" and the custom attributes described in @tbl-annotator.
Attribute | Value description
--- | ----------
`schema-url` | url used to retrieve the metadata schema
`post-url` | url to post the metadata on submission of the form
`schema-values` | an encoded JSON with the existing metadata related to the schema
`prefix` | prefix used for the metadata related to the schema (e.g. `mgs.book`)
: Attributes to include in the "metadata_form" tag for the metadata schema manager. {#tbl-annotator}
The JSON with the metadata provided to `schema-values` is then decoded with `atob()` and parsed. Given that JSON does not allow repeated keys, if one attribute name is associated with multiple values, the values should be provided as a list.
## Communication with the backend
In this section we describe the format expected for the information obtained from and sent to the backend for various operations, as shown in @tbl-backend.
Program | GET | POST
--- | ----- | -----
Manager | list of schemas <br> existing schema | (modified) schema
Annotator | existing schema | (modified) metadata
: HTTP Requests to the backend. {#tbl-backend}
### GET list of schemas (Manager)
The list of existing schemas is requested via the url coded in the `list` attribute of the `url-list` tag. The contents are parsed and manipulated by the `TemplatesRequest` class in [httprequests.js](src/httprequests.js).
The request must return a (JSON) list with one item per existing schema, each represented as an object. Each object must have three elements: `name`, `url` and `schema_info`. The first two attributes contain the name of the schema and the url that can be used to retrieve a specific version of the schema. This url includes "status" as placeholder for the status that will be requested.
<!-- Note: this will also have to include versions if we can ask for archived versions -->
The `schema_info` attribute is an object with the following key-value pairs:
- `archived`, `published` and `draft`, which can be "true" or "false". If `archived` is true, there is at least one archived version but no published or draft versions. The values of `draft` and `published` indicate whether there are draft or published versions, respectively.
- `draft_count` and `published_count` are 0 if there are no draft/published versions and 1 if there is one version with that status. `total_count` keeps track of the total number of versions.
- `draft_name` and `published_name` indicate the filename of the draft and published version, respectively, if they exist.
- `latest_version` provides the number of the latest version that was created. `versions_sorted` is a sorted list of the versions that have been created.
- `realm`, `title` and `timestamp`
### GET schema
In the metadata schema manager, a specific schema can be requested via the url provided in the list of schemas, by replacing "status" with the status of the desired version. The contents are parsed and manipulated by the `TempalateReader` class in [httprequests.js](src/httprequests.js), which is called by the `load_versions()` method of the `SchemaGroup` class.
The same url is provided as the `schema-url` attribute of the required element in the annotation section, with "status" changed to "published". In this case, the contents are parsed and manipulated by the `AnnotationRequest` class in[httprequests.js](src/httprequests.js).
The contents sent from the backend are the contents of the JSON file of the requested version, as described in [the documentation](docs/metadata-schemas.md).
### POST schema
When posting a modified schema, the following information must be sent:
- `realm`: the realm in which the schema is designed and where it will be stored.
- `with_status`: the status of the version of the schema.
- `schema_name`: the name of the schema.
These three fields are necessary for any posting action: saving, deleting or archiving. Deleting is achieved by using the url stored in the `delete` attribute indicated above and is only possible for draft versions. Archiving requires the `archive` url and is only possible for published versions.
Other actions, such as saving or publishing a draft, require more fields to be sent:
- `current_version`: the version number of the version to be saved.
- `parent` : if the schema is a clone of another schema, the name and version number of the parent.
- `raw_schema` : a stringified and encoded (`btoa()`) object with the contents of the `properties` element of the schema, i.e. the fields.
- `title`: the title of the schema, i.e. a user-friendly label.
### POST metadata
When posting metadata, the different AVUs (or, more specifically, metadata attribute-value pairs) must be sent as such with the appropriate namespacing, along with the following fields, which in the ManGO portal are provided via URL parameters:
- `item_type` : "collection" or "data_object"
- `object_path` : the path to the collection or data object that is being annotated
- `schema` : the name of the schema
- `realm`
# Structure of the Javascript files {#sec-files}
As mentioned above, the only files that actually run code are ["manager.js"](src/manager.js) for the metadata schema manager and ["annotator.js"](src/annotator.js) for the schema application, which hook to specific DOM elements and trigger the creation of others. The first file also creates a `Schema()` instance for a new schema you may want to design and a `TemplatesRequest()` instance, which retrieves the list of existing schemas and then renders them. The annotation script, instead, creates an `AnnotationRequest()` instance, which retrieves the existing schema and parses it along with the existing metadata to generate and (if relevant) prefill the form.
The rest of the files define different classes then instantiated through the workflow. More detailed documentation can be found in the files themselves.
## [doms.js](src/doms.js)
The DOMs file contains a number of classes that programmatically generate and manipulate DOM elements.
- The `Field` class only contains static elements that can be reused: from a basic element with some tag and inner text to standard dropdowns, checkboxes and input labels.
- The `MovingField` class defines a box with an input field and buttons to move it up and down, delete it and, if relevant, copy it or edit it. It has the `MovingViewer` and `MovingChoice` subclasses which are used, respectively, to edit and copy created fields and to defe the options in a multiple-choice field.
- The `BasicForm` class sets up the common aspects to the forms that design the different fields, such as inputs and labels, switches and buttons. Its subclass `SchemaDraftForm`, used to generate a form for a schema, adds the hidden fields necessary to post a schema.
- The `Modal`, `AccordionItem` and `NavBar` classes help create modals (to create forms), accordion items (each harboring a schema) and tabs (to view and edit specific versions of a schema).
## [fields.js](src/fields.js)
The Fields file contains a parent class called `InputField` that sets up the common ground for all kinds of fields that can be designed. It includes important attributes and methods to select them, design them, view them, edit them and retrieve information from their forms.
Its three main children are `TypedInput`, `MultipleInput` and `ObjectInput`, which are used to create simple inputs (text, numbers and individual checkboxes), multiple-choice inputs (radio and checkbox as well as dropdowns) and composite fields (combinations of other kinds of inputs), respectively. The `MultipleInput` subclass has two further children: `SelectInput` for single-value multiple-choice, i.e. when only one of the possible answers can be selected, and `CheckboxInput` for multiple-value multiple-choice, i.e. when many of the possible answers can be selected. Both can be eventually rendered as dropdowns, but their alternative shapes are different: radio buttons for the former and checkbox for the latter.
## [schema.js](src/schema.js)
The Schema file contains three main classes: `ComplexField`, `SchemaGroup` and `SchemaForm`. First, the `ComplexField` class is an abstraction of its three children: `DummyObject`, `ObjectEditor` and `Schema`. A `Schema` is used to represent and manipulate a version of a schema; `ObjectEditor` is its simpler sibling used to represent composite fields (or, rather, their collections of fields), and `DummyObject` is a fixed implementation of the `ObjectEditor` used to render an example of a composite field. Second, the `SchemaGroup` class is used to represent a collection of versions of the same schema, manipulating the corresponding tabs. Finally, the `SchemaForm` class is the key of the annotation section of the code, and is used to parse a schema, connect it to annotated data and generate the corresponding form.
## [httprequests.js](src/httprequests.js)
The HttpRequests file contains a class that extends `XMLHttpRequest`, `MangoRequest`, with three children: `TemplatesRequest`, `TemplateReader` and `AnnotationRequest`. These classes are used to retrieve information from the server: the list of existing schemas for `TemplatesRequest` and individual schemas for the other two, which are used in the Manager and Annotator sections repsectively.