Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f88c63a
feat: added possibility to set prefix key in user to service api conf…
RenzoPrats May 3, 2024
4a4cfee
Merge branch 'next-oort' into feat/HIT_integrate_kobo_in_oort # Pleas…
RenzoPrats May 9, 2024
7b18f20
feat: started import kobo questions
RenzoPrats May 10, 2024
d3b055b
merged next-oort
RenzoPrats May 17, 2024
b8564dc
last fix
RenzoPrats May 23, 2024
1de2c1d
Merge branch 'next-oort' into feat/HIT_integrate_kobo_in_oort
estelafs Jun 19, 2024
3aefab1
remove console.log
estelafs Jun 19, 2024
320ba19
updated isSnakeCase method to allow the Kobo questions star with _ an…
estelafs Jun 20, 2024
c874320
updated regex to allow Kobo questions with capital letters
estelafs Jun 25, 2024
c3c21e5
created custom functions: once, formatDateTime, join, concat
estelafs Jun 26, 2024
215d1f4
created custom functions: indexedRepeat, string
estelafs Jun 27, 2024
1b7be63
created custom functions: join, maxElements, minElements, sumElements…
estelafs Jun 28, 2024
5492967
created custom functions: int and selected
estelafs Jul 1, 2024
4aca1a3
Merge branch 'next-oort' into feat/HIT_integrate_kobo_in_oort
estelafs Jul 3, 2024
7f7eb5a
added kobo info to form model - to save kobo info on forms imported f…
estelafs Jul 8, 2024
504bc22
Merge branch 'next-oort' into feat/HIT-340-Kobo-import-collected-data…
estelafs Jul 8, 2024
d63873a
created SynchronizeKoboModalComponent
estelafs Jul 9, 2024
97eb1c9
added ADD_RECORDS_FROM_KOBO mutation
estelafs Jul 11, 2024
df82b9e
fix interface and import order
estelafs Jul 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ <h3 class="font-semibold">{{ 'models.form.new' | translate }}</h3>
</div>
<div
class="flex flex-col mb-5 gap-1"
formControlName="newResource"
uiRadioGroupDirective="newResourceOptions"
formControlName="type"
uiRadioGroupDirective="typeOptions"
>
<ui-radio [value]="true">
<ui-radio value="core">
<ng-container ngProjectAs="label">
<span class="flex items-center gap-1">
{{ 'components.form.create.choice.resource' | translate }}
Expand All @@ -35,7 +35,7 @@ <h3 class="font-semibold">{{ 'models.form.new' | translate }}</h3>
</span>
</ng-container>
</ui-radio>
<ui-radio [value]="false">
<ui-radio value="template">
<ng-container ngProjectAs="label">
<span class="flex items-center gap-1">
{{ 'components.form.create.choice.inherit' | translate }}
Expand All @@ -52,8 +52,25 @@ <h3 class="font-semibold">{{ 'models.form.new' | translate }}</h3>
</span>
</ng-container>
</ui-radio>
<ui-radio value="kobo">
<ng-container ngProjectAs="label">
<span class="flex items-center gap-1">
{{ 'components.form.create.choice.kobo' | translate }}
<ui-icon
class="cursor-help"
[size]="18"
icon="info_outline"
variant="grey"
[uiTooltip]="
'components.form.create.tooltip.kobo' | translate
"
>
</ui-icon>
</span>
</ng-container>
</ui-radio>
</div>
<ng-container *ngIf="!form.value.newResource">
<ng-container *ngIf="form.value.type === 'template'">
<div uiFormFieldDirective>
<label>{{
'components.form.create.template.title' | translate
Expand Down Expand Up @@ -108,6 +125,37 @@ <h3 class="font-semibold">{{ 'models.form.new' | translate }}</h3>
</ng-container>
</ng-container>
</ng-container>

<ng-container *ngIf="form.value.type === 'kobo'">
<!-- API Configuration -->
<div uiFormFieldDirective class="flex-auto">
<label>{{ 'common.apiConfiguration.one' | translate }}</label>
<ui-graphql-select
valueField="id"
textField="name"
[query]="apiConfigurationsQuery"
formControlName="apiConfiguration"
[selectedElements]="[selectedApiConfiguration]"
[filterable]="true"
(searchChange)="onSearchChange($event)"
[placeholder]="
'components.form.create.kobo.apiConfiguration.placeholder'
| translate
"
>
</ui-graphql-select>
</div>
<div uiFormFieldDirective>
<label>{{ 'components.form.create.kobo.label' | translate }}</label>
<input
formControlName="kobo"
type="text"
[placeholder]="
'components.form.create.kobo.placeholder' | translate
"
/>
</div>
</ng-container>
</div>
</form>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Apollo } from 'apollo-angular';
import { Apollo, QueryRef } from 'apollo-angular';
import { Component, OnInit } from '@angular/core';
import { Validators, FormBuilder } from '@angular/forms';
import { GET_RESOURCE_BY_ID } from './graphql/queries';
Expand All @@ -14,6 +14,7 @@ import {
SelectMenuModule,
ChipModule,
FormWrapperModule,
GraphQLSelectModule,
} from '@oort-front/ui';
import { DialogModule } from '@oort-front/ui';
import { DialogRef } from '@angular/cdk/dialog';
Expand All @@ -22,6 +23,18 @@ import {
ResourceQueryResponse,
ResourceSelectComponent,
} from '@oort-front/shared';
import {
ApiConfiguration,
ApiConfigurationsQueryResponse,
ApiConfigurationQueryResponse,
} from '@oort-front/shared';
import {
GET_API_CONFIGURATION,
GET_API_CONFIGURATIONS_NAMES,
} from './graphql/queries';

/** Default pagination parameter. */
const ITEMS_PER_PAGE = 10;

/**
* Add form component (modal)
Expand All @@ -44,6 +57,7 @@ import {
FormWrapperModule,
ChipModule,
ResourceSelectComponent,
GraphQLSelectModule,
],
selector: 'app-add-form-modal',
templateUrl: './add-form-modal.component.html',
Expand All @@ -53,13 +67,19 @@ export class AddFormModalComponent implements OnInit {
/** Form group */
public form = this.fb.group({
name: ['', Validators.required],
newResource: this.fb.nonNullable.control(true),
type: this.fb.nonNullable.control('core'),
resource: [null],
inheritsTemplate: this.fb.nonNullable.control(false),
template: null,
apiConfiguration: [null],
kobo: [''],
});
/** Available templates */
public templates: Form[] = [];
/** Selected API configuration */
public selectedApiConfiguration?: ApiConfiguration;
/** Api configurations query */
public apiConfigurationsQuery!: QueryRef<ApiConfigurationsQueryResponse>;

/**
* Selected template
Expand Down Expand Up @@ -87,16 +107,35 @@ export class AddFormModalComponent implements OnInit {

/** Load the resources and build the form. */
ngOnInit(): void {
this.form.get('newResource')?.valueChanges.subscribe((value: boolean) => {
if (value) {
this.form.get('type')?.valueChanges.subscribe((value: string) => {
if (value == 'core') {
this.form.get('resource')?.clearValidators();
this.form.get('kobo')?.clearValidators();
this.form.get('apiConfiguration')?.clearValidators();
this.form.patchValue({
resource: null,
inheritsTemplate: false,
template: null,
apiConfiguration: null,
kobo: null,
});
} else if (value == 'template') {
this.form.get('kobo')?.clearValidators();
this.form.get('apiConfiguration')?.clearValidators();
this.form.patchValue({
apiConfiguration: null,
kobo: null,
});
} else {
this.form.get('resource')?.setValidators([Validators.required]);
} else {
this.form.get('resource')?.clearValidators();
this.form.patchValue({
resource: null,
inheritsTemplate: false,
template: null,
});
this.loadApiConfigurations();
this.form.get('kobo')?.setValidators([Validators.required]);
}
this.form.get('resource')?.updateValueAndValidity();
});
Expand Down Expand Up @@ -147,4 +186,57 @@ export class AddFormModalComponent implements OnInit {
this.templates = data.resource.forms || [];
});
}

/**
* Load all Api Configurations.
*
*/
loadApiConfigurations(): void {
this.form.get('apiConfiguration')?.setValidators(Validators.required);
if (this.form.value.apiConfiguration) {
this.apollo
.query<ApiConfigurationQueryResponse>({
query: GET_API_CONFIGURATION,
variables: {
id: this.form.value.apiConfiguration,
},
})
.subscribe(({ data }) => {
if (data.apiConfiguration) {
this.selectedApiConfiguration = data.apiConfiguration;
}
});
}

this.apiConfigurationsQuery =
this.apollo.watchQuery<ApiConfigurationsQueryResponse>({
query: GET_API_CONFIGURATIONS_NAMES,
variables: {
first: ITEMS_PER_PAGE,
},
});
this.form?.get('apiConfiguration')?.updateValueAndValidity();
}

/**
* Update query based on text search.
*
* @param search Search text from the graphql select
*/
onSearchChange(search: string): void {
const variables = this.apiConfigurationsQuery.variables;
this.apiConfigurationsQuery.refetch({
...variables,
filter: {
logic: 'and',
filters: [
{
field: 'name',
operator: 'contains',
value: search,
},
],
},
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,40 @@ export const GET_RESOURCE_BY_ID = gql`
}
}
`;

/** Get API configuration gl query */
export const GET_API_CONFIGURATION = gql`
query GetApiConfiguration($id: ID!) {
apiConfiguration(id: $id) {
id
name
authType
graphQLEndpoint
}
}
`;

// === GET API CONFGIURATIONS NAME ===
/** API configuration names query */
export const GET_API_CONFIGURATIONS_NAMES = gql`
query GetApiConfigurationsName($first: Int, $afterCursor: ID, $filter: JSON) {
apiConfigurations(
first: $first
afterCursor: $afterCursor
filter: $filter
) {
edges {
node {
id
name
}
cursor
}
totalCount
pageInfo {
hasNextPage
endCursor
}
}
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { gql } from 'apollo-angular';

/** Edit form Kobo preferences gql mutation definition */
export const EDIT_FORM_KOBO_PREFERENCES = gql`
mutation editForm($id: ID!, $dataFromDeployedVersion: Boolean) {
editForm(id: $id, dataFromDeployedVersion: $dataFromDeployedVersion) {
id
name
kobo {
dataFromDeployedVersion
}
}
}
`;

/** For the form created from a Kobotoolbox form, import data submissions to create records. */
export const ADD_RECORDS_FROM_KOBO = gql`
mutation addRecordsFromKobo($form: ID!) {
addRecordsFromKobo(form: $form)
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<ui-dialog size="medium" [closable]="false">
<ng-container ngProjectAs="header">
<h3 class="font-semibold">{{ 'components.form.create.kobo.data.synchronize' | translate }}</h3>
</ng-container>
<ng-container ngProjectAs="content">
<ui-spinner *ngIf="loading" size="medium"></ui-spinner>
<div class="flex flex-col items-center my-2">
<ui-button category="secondary" variant="primary" (click)="onSynchronize()">{{
'components.form.create.kobo.data.start' | translate
}}</ui-button>
</div>
<ui-alert>
{{ 'components.form.create.kobo.data.fromFormWithVersion' | translate : { formName: data.form.name, versionId: data.deployedVersionId} }}
</ui-alert>
<!-- Loading indicator -->
<form [formGroup]="formGroup" class="mt-2">
<ui-toggle formControlName="dataFromDeployedVersion" class="mb-5">
<ng-container ngProjectAs="label">
{{ 'components.form.create.kobo.data.syncOnlyFromDeployedVersion' | translate }}
<ui-icon
class="ml-1 cursor-help self-center"
icon="info_outline"
variant="grey"
[size]="18"
[uiTooltip]="
'components.form.create.kobo.data.tooltip.syncOnlyFromDeployedVersion' | translate
"
></ui-icon>
</ng-container>
</ui-toggle>
</form>
</ng-container>

<ng-container ngProjectAs="actions">
<ui-button [uiDialogClose]="updated ? formGroup.get('dataFromDeployedVersion')?.value : null" variant="default">{{
'common.close' | translate
}}</ui-button>
<ui-button
category="secondary"
variant="primary"
(click)="onSave()"
cdkFocusInitial
[disabled]="formGroup.pristine"
>
{{ 'common.save' | translate }}
</ui-button>
</ng-container>
</ui-dialog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SynchronizeKoboModalComponent } from './synchronize-kobo-modal.component';


describe('SynchronizeKoboModalComponent', () => {
let component: SynchronizeKoboModalComponent;
let fixture: ComponentFixture<SynchronizeKoboModalComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SynchronizeKoboModalComponent],
}).compileComponents();

fixture = TestBed.createComponent(SynchronizeKoboModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading