Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Viewer basic structure #1

Closed
flavens opened this issue Jan 7, 2020 · 19 comments · Fixed by #2
Closed

Viewer basic structure #1

flavens opened this issue Jan 7, 2020 · 19 comments · Fixed by #2
Assignees
Labels
documentation Improvements or additions to documentation enhancement New feature or request

Comments

@flavens
Copy link
Collaborator

flavens commented Jan 7, 2020

  • viewer.module
    • property
      • operation components (crud)

        one component per operation, dealing with the different value types defined in type-information components

      • type-information components (knora value types)

        one component per value type (e.g. KnoraDate, KnoraInt... independent of the CRUD operations) that can be used in operation components

    • views
      • resource view
      • property view
      • lists
      • search-results
    • representation (media type)
@flavens flavens added documentation Improvements or additions to documentation enhancement New feature or request labels Jan 7, 2020
@flavens
Copy link
Collaborator Author

flavens commented Jan 7, 2020

How can we switch between the different operation components (e.g. display a value (read), then edit this value (update), and finally reload and display the updated value)?

@flavens
Copy link
Collaborator Author

flavens commented Jan 7, 2020

Project examples with one element component implementing all CRUD-operation methods in the TS file
https://codeburst.io/crud-with-angular-5d8f39805c49
https://adrianmejia.com/angular-2-tutorial-create-a-crud-app-with-angular-cli-and-typescript/

Project example with CRUD-operation components
https://www.javaguides.net/2019/06/angular-8-crud-example-tutorial.html

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Jan 15, 2020

Knora-ui lib

General

The knora-ui elements will be organized in one Angular lib that can then be published on npm. The lib's internal structure (its directory structure) can be similar to the structure of the previous npm libs (core, viewer etc.). Also it can consist of different modules.

Viewer

Structure

The viewer has a part called values and a part called operations. values contains specific components for the Knora value types such as integer, date etc. These components share a common interface. However, each component can have additional specific inputs and outputs for further configuration. operations handles the tasks that are common to all values types and decides which component to use to handle the value specific tasks.

For the new viewer I did some prototyping which you can find here: https://github.com/tobiasschweizer/angular-lib.

API

Values

All value specific components are derived from a common base class so that they share a minimal public API:

export abstract class BaseValueComponent {

    @Input() abstract displayValue?: ReadValue;

    @Input() mode: 'read' | 'update' | 'create' | 'search';

    ...

    abstract restoreDisplayValue(): void;

    abstract getNewValue(): CreateValue;

    abstract getUpdatedValue(): UpdateValue;
}

Each value component will have an optional input displayValue that will have to be implement for its specific type. It allows to set an initial value which is needed for display (read-mode) and edit a value (update-mode).

Each value component has to be initialized to a specific mode: read, update, create, search via an input. The mode can be changed, so a displayed value can be edited.

When a value is being created or updated, the new value can be obtained via getNewValue() or getUpdatedValue() respectively.

restoreDisplayValue value sets a value back to its initial state (for instance when an update operation is aborted).

The components that implement the base class make use of reactive forms and Angular Material elements.

An component's template for dates could look like this:

<span [formGroup]="form">
<span [ngSwitch]="readonly">
    <span class="large-field" *ngSwitchCase="true">
        {{dateCtrl.value.toCalendarPeriod().periodStart.day}}-{{dateCtrl.value.toCalendarPeriod().periodStart.month}}-{{dateCtrl.value.toCalendarPeriod().periodStart.year}}
    </span>
    <mat-form-field class="large-field" *ngSwitchDefault>
        <input matInput [matDatepicker]="picker" placeholder="Choose a date" [formControlName]="'dateValue'">
        <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
        <mat-datepicker #picker></mat-datepicker>
    </mat-form-field>
</span>
</span>

The template's elements are bound to a FormGroup and the actual value is bound to a FormControl (to display the value in read mode and to update it in edit mode).

In addition to the API defined on the base class, a date component could have additional specific inputs that allow for further configuration of a date (e.g., if the calendar or the era should be shown etc.)

Operations

Operation components allow for displaying any type of value, make it editable or create new values.

A component to display a value could look like this:

export class DisplayValueComponent implements OnInit {

    @Input() displayValue: ReadValue;

    @Input() configuration?: IValuesConfigurationOptions;

    constructor() {
    }

    ngOnInit() {
    }

}

As an input, it takes any type of value plus an configuration object as an option. This object allows for type specific configurations (e.g., how a date should be displayed).

Its template contains a part that is common to all value types and also has some logic that decides which component from values to use for type specific tasks:

<div>

    {{displayValue.propertyLabel}}
    <br/>
    {{displayValue.arkUrl}}
    <span [ngSwitch]="displayValue.type">
        <span *ngSwitchCase="'http://api.knora.org/ontology/knora-api/v2#TextValue'">
            <lib-text-value-as-string [displayValue]="displayValue" [mode]="'read'"></lib-text-value-as-string>
        </span>
        <span *ngSwitchDefault>
            {{displayValue.strval}}
        </span>
    </span>
</div>

The template controls the mode of the values component. For example, it could switch the mode from read to edit and then read the updated value from the values component public method, send it to Knora and display the new value back in the template. Or it could abort the update process and reset it to the initial value.

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Jan 21, 2020

Value Components

Classes

to be rendered with mermaid:

classDiagram
    
    class BaseValueComponent {
      +@Input ReadValue displayValue?
      +@Input 'read' | 'update' | 'create' | 'search' mode
      +void restoreDisplayValue()
      +CreateValue getNewValue()*
      +UpdateValue getUpdatedValue()*
      +SearchValue getSearchValue()*
    }

    class DateValueComponent {
       +@Input boolean showCalendar
       +@Input boolean showEra
    }
    
    class IntegerValueComponent

    BaseValueComponent <|-- DateValueComponent
    BaseValueComponent <|--  IntegerValueComponent
    
Loading

mermaid-diagram-20200123181120

BaseValueComponent is an abstract class to be extended by specific value classes (value components).

  • @Input displayValue?: ReadValue : optional input to display an existing value (serves as the initial value for read and edit mode, is reinitialized if a new displayValue is set)
  • @Input mode: 'read' | 'update' | 'create' | 'search': sets the mode of the value component
  • restoreDisplayValue(): restores the initially displayed value (in update mode, the user can manipulate the value)
  • getNewValue(): CreateValue: returns a type specific subclass of CreateValue (works only in create mode)
  • getUpdatedValue: UpdateValue: returns a type specific subclass of CreateValue (works only in update mode)
  • getSearchValue(): SearchValue: returns a type specific subclass of SearchValue (works only in search mode)

Class - Template Interaction

The value components make use of ReactiveForms. In the templates, the values are accessed via the FormControl element (formControlName). The FormControl element is also used for validation of the value.

Depending on the mode, the value component sets the template element to readonly.

When a displayValue is provided (when the component is created or a new displayValue is provided), it has to be correctly set in the FormControl element (either as its initial value or as an update via setValue). When restoreDisplayValue is called, the FormControl element's element has to be set back to the given displayValue.

The methods getNewValue, getUpdatedValue, and getSearchValue read the value from the FormControl element. They only return the value if its valid.

Testing

For each value component units tests have to be provided. They have a to define a test host component that controls he inputs of the value component.

The following test cases have to be provided:

  • display a value (provide displayValue, set mode to read, check readonly mode)
  • edit a value (provide displayValue, set mode to read, then set mode to edit, manipulate value in DOM , check for validity, call `getUpdateValue)
  • create a value (no displayValue, insert a value in the DOM, check for validity, call getCreateValue)

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Jan 21, 2020

classDiagram
    
    class DisplayValuesComponent {
      +@Input ReadValue[] displayValues
      +@Input ViewerConfiguration viewerConfig
      
      +@ViewChildren QueryList<BaseValueComponent> valueComponents
    }
Loading

mermaid-diagram-20200123182620

DisplayValuesComponent:

  • @Input displayValues: ReadValue[]: a resource's values to be displayed
  • @Input viewerConfig: ViewerConfiguration: a configuration object for the type specific value components
  • @ViewChildren valueComponents: QueryList<BaseValueComponent>: References to the type specific value components (for example showEra input for a date)

Read

DisplayValuesComponent is a component that displays a resource's values passed to its input displayValues. It does so by choosing the apt value component for each individual ReadValue and passing it to the component's input displayValue. The value component's mode is set to read. Common properties (not value specific) such as the property label etc. are handled directly by DisplayValuesComponent.

Type specific configuration options are passed via the input ViewerConfiguration and set in the value specific components' inputs (for example showEra for a date).

Edit

For each given value, the permissions are analysed. If sufficient, the user may edit a value (switching the value component's mode to edit). The user may then manipulate the value and either save it or abort the operation. When cancelling, the value component's method restoreDisplayValue is called and the mode is set back to read. When a value has been edited, it can be fetched via getUpdatedValue and send to the values route. Then it has to be read back from Knora's value route and passed to the value component's input displayValue, setting its mode to read.

Create an additional value

For each given value, the cardinality of its property is analysed. If a another value can be added for a property, a value component is created setting its mode to create without a display value. If the user aborts the operation, the value component has to be destroyed. If the user submits the value, it can be fetched via getNewValue and send to the values route. Then it has to be read back from Knora's value route and passed to the value component's input displayValue, setting its mode to read (same as when editing).

Delete a value

Sufficient permissions provided and if allowed by the property's cardinalities, a value can be deleted. In this case, the value component is destroyed.

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Jan 27, 2020

Analyzing Permissions

Parsing of the permission string should happen in knora-api-js-lib (see dasch-swiss/dsp-js-lib#142). The relevant information is provided by the property knora-api:userHasPermission for each value, see https://docs.knora.org/paradox/02-knora-ontologies/knora-base.html#permissions.

Analyzing Cardinalities

When displaying a resource's values, possibly additional values can be created. This depends on a property's cardinality for the given resource type.

ReadResource.entityInfo.classes[resClassIri].propertiesList -> cardinality for the property in question

Creating Values

  • more values for the same property with existing values can be created if the cardinality is "0-n" or "1-n"
  • values can be created for a property that does not have any values yet if the cardinality is "0-1" or "0-n"

When a value has been created, the calculation has to be redone.

Deleting Values

Existing values can be deleted if the cardinality is "0-1" or "0-n". A value can be deleted with a cardinality of "1-n" if there is at least one remaining value for the property after deletion.

When a value has been deleted, the calculation has to be redone.

@flavens
Copy link
Collaborator Author

flavens commented Jan 27, 2020

The GUI attributes from the Salsah GUI ontology are not up-to-date and some attributes are missing. We can either extend the actual Salsah GUI ontology with GUI new elements or create a new ontology.

TS: The GUI attributes will have an effect in the template (choosing an HTML element).

@flavens
Copy link
Collaborator Author

flavens commented Jan 28, 2020

List of GUI/Form elements needed: dasch-swiss/knora-ui/issues/358. Links to Angular Material Components included.

@lrosenth
Copy link
Collaborator

Please take into account that the comment is part of the value component!

@tobiasschweizer tobiasschweizer mentioned this issue Jan 30, 2020
@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Jan 30, 2020

Validation

Modes

I have realized that validation depends on the mode:

  • "read": no validators needed
  • "update": a value is required, it has to be of the correct type (e.g., numeric), and it has to be different from the previous value
  • "create": a value is required, it has to be of the correct type (e.g., numeric)

I think when switching the mode and/or resting the display value, the validators have to be set accordingly.

Values and Comments

When editing a value

  1. an updated value can be submitted with a comment
  2. a modified comment can be submitted with the same value

An updated value needs to be different from the current value (with or without a comment) or its comment needs to be different.

@flavens
Copy link
Collaborator Author

flavens commented Feb 6, 2020

@tobiasschweizer a large part of your doc here should be copied in knora-proposals in a new design file to describe this new major feature (requested by Ivan)

@tobiasschweizer
Copy link
Contributor

@flavens Ok, I will do that, thanks!

@tobiasschweizer
Copy link
Contributor

@flavens
Copy link
Collaborator Author

flavens commented Feb 10, 2020

@flavens Please have a look at https://github.com/dasch-swiss/knora-proposals/blob/master/designs/2020-02-10-knora-ui-viewer.md

@tobiasschweizer Good text, but I would add some precisions:

  • "An Angular module called "knora-ui viewer" should be created." -> you should mention everywhere that we are creating a new knora-ui repo that will refactor (and not create) the modules.
  • you never mention the "delete" feature that will also be implemented
  • this part in the proposal: "Before, @knora/viewer and @knora/search defined components that now can be combined into one per Knora value, reducing redundancy and facilitating maintenance." -> you could precise that it is only the value elements to build the views/search form and not the combination of the 2 modules in 1 (because for me this sentence is a bit confusing)
  • you also could mention briefly how we will handle values permissions

@flavens
Copy link
Collaborator Author

flavens commented Feb 10, 2020

@tobiasschweizer I also would like to talk about the design of the GUI elements before we start to develop all the components. I am still working on the general views but this is what I have today to start the discussion.

  • André did a mockup on each element in read/edit mode:
    properties-and-elements

  • General views for each mode, except "search":
    view_combination

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Feb 10, 2020

@flavens Thanks for your comments!

Should there be an additional input for the GUI element (e.g., HTML input or textarea for text)?

@flavens
Copy link
Collaborator Author

flavens commented Feb 10, 2020

Should there be an additional input for the GUI element (e.g., HTML input or textarea for text)?

Yes, we should try with an input. It won't be the case for each value and comment will always be a textarea.

@tobiasschweizer
Copy link
Contributor

Yes, we should try with an input. It won't be the case for each value and comment will always be a textarea.

I think each value component can have custom configuration inputs (see #1 (comment)) in addition to those defined on the base class.

@flavens
Copy link
Collaborator Author

flavens commented Feb 12, 2020

@tobiasschweizer @mdelez some suggestions:

  • we must use the prefix "kui" for each component (e.g. kui-text-value-as-string)
  • create and delete operations are missing (but should be already in your todo list)
  • implement the possibility to display a hint message or an error message after each value field (mat-hint and mat-error -> see Input material component)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants