Skip to content

Commit

Permalink
Merge pull request #316 from MauroDataMapper/enhancement/gh-308
Browse files Browse the repository at this point in the history
gh-308 - Rename DataRequest to DataSpecification
  • Loading branch information
pjmonks authored Apr 3, 2023
2 parents a721714 + 55e02fb commit 34aaecc
Show file tree
Hide file tree
Showing 131 changed files with 2,648 additions and 2,385 deletions.
45 changes: 23 additions & 22 deletions docs/CONCEPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,20 @@ Although not essential, it would be beneficial to apply this profile to the data
2. Providing additional information for help in choosing appropriate data elements to request for a user's own purposes.
3. Auto-populating the search filters to provide advanced search capabilities.

# User Requests
# User Data Specifications

The primary use case of the Mauro Data Explorer is to:

1. Browse or search the provided catalogue for data elements.
2. Gather data elements of interest to the user into a formal _user request_.
3. Submit this user request to the organisation running this instance to gain access to the real data sets owned by the organisation, based on the data elements requested.
2. Gather data elements of interest to the user into a formal _user data specification_.
3. Submit this user data specification to the organisation running this instance to gain access to the real data sets owned by the organisation,
based on the data elements specified.

The current implementation considers user requests to be _data models_ in their own right - they are created under the access level of the user signed-in to the Mauro Data Explorer, then populated with data elements before they are submitted. The sections below go into further detail.
The current implementation considers user data specifications to be _data models_ in their own right - they are created under the access level of the user signed-in to the Mauro Data Explorer, then populated with data elements before they are submitted. The sections below go into further detail.

## Requests Folder
## Data Specifications Folder

Every user who signs in to the Mauro Data Explorer will automatically be assigned a folder within the Mauro instance to collect their own requests in one place. This folder is located in Mauro where the `explorer.config.root_request_folder` is defined, which is a [configuration key](SETUP.md#configuration-keys) provided by the `mdm-plugin-explorer`. A root request folder is automatically created by the `mdm-plugin-explorer` called "Explorer Content", though the API property can be changed to any other folder if required.
Every user who signs in to the Mauro Data Explorer will automatically be assigned a folder within the Mauro instance to collect their own data specifications in one place. This folder is located in Mauro where the `explorer.config.root_data_specification_folder` is defined, which is a [configuration key](SETUP.md#configuration-keys) provided by the `mdm-plugin-explorer`. A root data specification folder is automatically created by the `mdm-plugin-explorer` called "Explorer Content", though the API property can be changed to any other folder if required.

The user's folder is named after the user's email address for uniqueness.

Expand All @@ -57,30 +58,30 @@ The user's folder is named after the user's email address for uniqueness.
>
> For a user signed-in with the email address `[email protected]`
>
> The user request folder will be located under `explorer.config.root_request_folder` and named `user[at]test.com`.
> The user's data specification folder will be located under `explorer.config.root_data_specification_folder` and named `user[at]test.com`.
This request folder is created along with a new user group containing that user. This group is then assigned to the [editor role](https://maurodatamapper.github.io/user-guides/permissions/permissions/#editor) to allow that user (normally with a read-only role) to create catalogue items underneath it.
This data specification folder is created along with a new user group containing that user. This group is then assigned to the [editor role](https://maurodatamapper.github.io/user-guides/permissions/permissions/#editor) to allow that user (normally with a read-only role) to create catalogue items underneath it.

Once created, the Mauro instance will contain a set of sub-folders similar to below, assuming the default root request folder is used:
Once created, the Mauro instance will contain a set of sub-folders similar to below, assuming the default root data specification folder is used:

* Explorer Content
* user1[at]test.com
* user2[at]test.com
* etc

## Creating Requests
## Creating Data Specifications

Each user will automatically create user request data models, usually via another action to also assign data elements to them. The data models created will:
Each user will automatically create user data specification data models, usually via another action to also assign data elements to them. The data models created will:

1. Be created directly under their own requests folder.
1. Be created directly under their own data specification folder.
2. Be accessible only to that user or administrators.
3. Be created as a draft. In the context of the Mauro Data Explorer, these are "unsent" requests which may still be edited.
3. Be created as a draft. In the context of the Mauro Data Explorer, these are "unsent" data specifications which may still be edited.

A user is able to create more than one unsent request at once.
A user is able to create more than one unsent data specification at once.

## Copying Data Elements

The signed-in user will be able to copy data elements from the root data model into their own request model. This uses the following Mauro endpoint to accomplish this:
The signed-in user will be able to copy data elements from the root data model into their own data specification model. This uses the following Mauro endpoint to accomplish this:

```
PUT api/dataModels/{sourceDataModelId}/subset/{targetDataModelId}
Expand All @@ -102,20 +103,20 @@ The `subset` endpoint is a core Mauro endpoint which allows a deep copy of a set
3. Any related data types from the source data model, if they do not already exist.
4. All requested data elements, stored under the child data class copy.

## Submitting Requests
## Submitting Data Specifications

Once happy with the collection of data elements gathered, the user will be able to submit their request to the organisation hosting the Mauro Data Explorer. Submission covers several areas:
Once happy with the collection of data elements gathered, the user will be able to submit their data specification to the organisation hosting the Mauro Data Explorer. Submission covers several areas:

1. The request data model is [finalised](https://maurodatamapper.github.io/user-guides/finalising-data-models/finalising-data-models/).
1. The data specification data model is [finalised](https://maurodatamapper.github.io/user-guides/finalising-data-models/finalising-data-models/).
2. The current implementation of `mdm-plugin-explorer` will email a notification to an administrator.

At this point, the Mauro Data Explorer does not handle the submitted request anymore, the request for data access now falls under the control/responsibility of the hosting organisation.
At this point, the Mauro Data Explorer does not handle the submitted data specification anymore, the request for data access now falls under the control/responsibility of the hosting organisation.

It is possible for a user to create a new version of a previously submitted request, using the same [versioning](https://maurodatamapper.github.io/user-guides/branch-version-fork/branch-version-fork/) mechanisms that all data models have. This will create a new draft version which can be modified again before being submitted (finalised) a second time.
It is possible for a user to create a new version of a previously submitted data specification, using the same [versioning](https://maurodatamapper.github.io/user-guides/branch-version-fork/branch-version-fork/) mechanisms that all data models have. This will create a new draft version which can be modified again before being submitted (finalised) a second time.

# Template Requests

Instead of creating User Requests from scratch, it is possible to base a request off of a _template_. This is a pre-made request that is finalised and can be forked to make a copy from.
Instead of creating user data specifications from scratch, it is possible to base a data specification off of a _template_. This is a pre-made data specification that is finalised and can be forked to make a copy from.

## Templates Folder

Expand All @@ -125,4 +126,4 @@ The `mdm-plugin-explorer` will automatically:
2. Secure this folder to only be read by the "Explorer Readers" user group.
3. Install the API property `explorer.config.root_-_template_folder` pointing to this folder.

This will be the root folder to store any finalised template requests. The Mauro Data Explorer `/templates` page route will list all available templates and allow the user to inspect them and copy from them. Copying involves forking the Data Model request to build the copy, which is then automatically moved to the current user's personal request folder.
This will be the root folder to store any finalised template data specifications. The Mauro Data Explorer `/templates` page route will list all available templates and allow the user to inspect them and copy from them. Copying involves forking the template data specification to build the copy, which is then automatically moved to the current user's personal data specification folder.
2 changes: 1 addition & 1 deletion docs/SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ It is essential to install the [mdm-plugin-explorer](https://github.com/MauroDat
The [mdm-plugin-explorer](https://github.com/MauroDataMapper-Plugins/mdm-plugin-explorer) will automatically install the following API property keys, which are required for the Mauro Data Explorer to function:

- `explorer.config.root_data_model_path`
- `explorer.config.root_request_folder`
- `explorer.config.root_data_specification_folder`
- `explorer.config.root_template_folder`
- `explorer.config.profile_namespace`
- `explorer.config.profile_service_name`
Expand Down
2 changes: 1 addition & 1 deletion src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
[signedInUserProfileImageSrc]="signedInUserProfileImageSrc"
[rightLinks]="headerRightLinks"
[accountLink]="accountLink"
[unsentRequestCount]="unsentRequestsCount"
[unsentDataSpecificationCount]="unsentDataSpecificationsCount"
></mdm-header>

<main>
Expand Down
10 changes: 5 additions & 5 deletions src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import { ActivatedRoute, RouterOutlet } from '@angular/router';
import { MockDirective } from 'ng-mocks';
import { AppComponent } from './app.component';
import { StateRouterService } from './core/state-router.service';
import { DataRequestsService } from './data-explorer/data-requests.service';
import { DataSpecificationService } from './data-explorer/data-specification.service';
import { MdmEndpointsService } from './mauro/mdm-endpoints.service';
import { FooterComponent } from './shared/footer/footer.component';
import { HeaderComponent } from './shared/header/header.component';
import { createDataRequestsServiceStub } from './testing/stubs/data-requests.stub';
import { createDataSpecificationServiceStub } from './testing/stubs/data-specifications.stub';
import {
createMdmEndpointsStub,
MdmEndpointsServiceStub,
Expand All @@ -38,7 +38,7 @@ import { of } from 'rxjs';

describe('AppComponent', () => {
let harness: ComponentHarness<AppComponent>;
const dataRequestsStub = createDataRequestsServiceStub();
const dataSpecificationStub = createDataSpecificationServiceStub();
const endpointsStub: MdmEndpointsServiceStub = createMdmEndpointsStub();
const dataElementSearchStub = createDataElementSearchServiceStub();
const themesStub = createThemeServiceStub();
Expand All @@ -54,8 +54,8 @@ describe('AppComponent', () => {
useValue: {},
},
{
provide: DataRequestsService,
useValue: dataRequestsStub,
provide: DataSpecificationService,
useValue: dataSpecificationStub,
},
{
provide: MdmEndpointsService,
Expand Down
58 changes: 36 additions & 22 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
import { environment } from '../environments/environment';
import { BroadcastEvent, BroadcastService } from './core/broadcast.service';
import { StateRouterService } from './core/state-router.service';
import { DataRequestsService } from './data-explorer/data-requests.service';
import { DataSpecificationService } from './data-explorer/data-specification.service';
import { ErrorService } from './pages/error/error.service';
import { MdmHttpError } from './mauro/mauro.types';
import { SecurityService } from './security/security.service';
Expand All @@ -53,7 +53,7 @@ export class AppComponent implements OnInit, OnDestroy {
isLoading = false;
loadingCaption = '';

unsentRequestsCount = 0;
unsentDataSpecificationsCount = 0;

signedInUserProfileImageSrc?: string;

Expand Down Expand Up @@ -125,8 +125,8 @@ export class AppComponent implements OnInit, OnDestroy {
];

accountLink: HeaderLink = {
label: 'My requests',
routerLink: '/requests',
label: 'My Data Specifications',
routerLink: '/dataSpecifications',
arrow: 'angle-down',
};

Expand Down Expand Up @@ -172,7 +172,7 @@ export class AppComponent implements OnInit, OnDestroy {
private broadcast: BroadcastService,
private security: SecurityService,
private userDetails: UserDetailsService,
private dataRequests: DataRequestsService,
private dataSpecification: DataSpecificationService,
private stateRouter: StateRouterService,
private toastr: ToastrService,
private userIdle: UserIdleService,
Expand Down Expand Up @@ -207,9 +207,12 @@ export class AppComponent implements OnInit, OnDestroy {
takeUntil(this.unsubscribe$),
switchMap((userSignedIn) => {
this.setupSignedInUser(userSignedIn);
return this.getUnsentRequestCount();
return this.getUnsentDataSpecificationCount();
}),
map((unsentRequestsCount) => (this.unsentRequestsCount = unsentRequestsCount))
map(
(unsentDataSpecificationsCount) =>
(this.unsentDataSpecificationsCount = unsentDataSpecificationsCount)
)
)
.subscribe(() => {});

Expand All @@ -221,8 +224,9 @@ export class AppComponent implements OnInit, OnDestroy {
const user = this.userDetails.get();
if (user) {
this.setupSignedInUser(user);
this.getUnsentRequestCount().subscribe(
(unsentRequestsCount) => (this.unsentRequestsCount = unsentRequestsCount)
this.getUnsentDataSpecificationCount().subscribe(
(unsentDataSpecificationsCount) =>
(this.unsentDataSpecificationsCount = unsentDataSpecificationsCount)
);
}

Expand All @@ -233,7 +237,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.subscribeHttpErrorEvent('http-not-implemented', '/not-implemented');
this.subscribeHttpErrorEvent('http-server-error', '/server-error');

this.subscribeDataRequestChanges();
this.subscribeDataSpecificationChanges();

this.broadcast
.onLoading()
Expand Down Expand Up @@ -292,34 +296,44 @@ export class AppComponent implements OnInit, OnDestroy {
: undefined;
}

private getUnsentRequestCount() {
return this.dataRequests.list().pipe(
private getUnsentDataSpecificationCount() {
return this.dataSpecification.list().pipe(
catchError(() => {
this.toastr.error('There was a problem locating your current requests.');
this.toastr.error(
'There was a problem locating your current data specifications.'
);
return EMPTY;
}),
map((requests) => {
return requests.filter((req) => req.status === 'unsent').length;
map((dataSpecifications) => {
return dataSpecifications.filter(
(specification) => specification.status === 'unsent'
).length;
})
);
}

private subscribeDataRequestChanges() {
private subscribeDataSpecificationChanges() {
this.broadcast
.on('data-request-added')
.on('data-specification-added')
.pipe(
takeUntil(this.unsubscribe$),
switchMap(() => this.getUnsentRequestCount()),
map((unsentRequestsCount) => (this.unsentRequestsCount = unsentRequestsCount))
switchMap(() => this.getUnsentDataSpecificationCount()),
map(
(unsentDataSpecificationsCount) =>
(this.unsentDataSpecificationsCount = unsentDataSpecificationsCount)
)
)
.subscribe(() => {});

this.broadcast
.on('data-request-submitted')
.on('data-specification-submitted')
.pipe(
takeUntil(this.unsubscribe$),
switchMap(() => this.getUnsentRequestCount()),
map((unsentRequestsCount) => (this.unsentRequestsCount = unsentRequestsCount))
switchMap(() => this.getUnsentDataSpecificationCount()),
map(
(unsentDataSpecificationsCount) =>
(this.unsentDataSpecificationsCount = unsentDataSpecificationsCount)
)
)
.subscribe(() => {});
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/broadcast.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ export type BroadcastEvent =
| 'user-signed-in'
| 'user-signed-out'
| 'sign-out-user'
| 'data-request-added'
| 'data-request-submitted'
| 'data-specification-added'
| 'data-specification-submitted'
| 'data-intersections-refreshed'
| 'data-bookmarks-refreshed'
| 'loading';
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/state-router.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type KnownRouterPath =
| '/search'
| '/search/listing'
| '/dashboard'
| '/requests'
| '/dataSpecifications'
| '/account';

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@
SPDX-License-Identifier: Apache-2.0
-->
<h1 mat-dialog-title>Create a new request</h1>
<h1 mat-dialog-title>Create a new data specification</h1>
<mat-dialog-content>
<form [formGroup]="requestForm" role="form" name="requestForm">
<form [formGroup]="dataSpecificationForm" role="form" name="dataSpecificationForm">
<div class="form-input">
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input
matInput
formControlName="name"
placeholder="Enter the name of the new request"
placeholder="Enter the name of the new data specification"
required
/>
<mat-error *ngIf="name?.errors?.required">
Please enter a request name
Please enter a data specification name
</mat-error>
</mat-form-field>
</div>
Expand All @@ -40,7 +40,7 @@ <h1 mat-dialog-title>Create a new request</h1>
matInput
rows="6"
formControlName="description"
placeholder="Enter a description of your request"
placeholder="Enter a description of your data specification"
></textarea>
</mat-form-field>
</div>
Expand All @@ -51,9 +51,9 @@ <h1 mat-dialog-title>Create a new request</h1>
<button
mat-flat-button
color="primary"
[disabled]="requestForm.invalid"
[disabled]="dataSpecificationForm.invalid"
(click)="create()"
>
Create request
Create data specification
</button>
</mat-dialog-actions>
Loading

0 comments on commit 34aaecc

Please sign in to comment.