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

Feature/location list updates #3541

Merged
merged 32 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b34d6fd
Add vertical mat-tab display of location levels and content
Feb 23, 2023
5ded93b
Add button to export Location Lists as JSON
Feb 27, 2023
bab4d09
Revert Change to Location List Content UI
Feb 27, 2023
3edacba
Trigger changes of location list metadata tab content
Feb 27, 2023
1325dc0
Update button color and layouts of location list tab content
Feb 27, 2023
88e110d
Update styles of location list import and export
Feb 27, 2023
faaf30d
Update the import location list ui to make the export ui
Feb 27, 2023
abac540
Merge remote-tracking branch 'origin/develop' into feature/location-l…
Feb 28, 2023
7988f31
Post-review fixes
Feb 28, 2023
7ab0b85
Show JSON data after Location List import
Feb 28, 2023
cc5bad6
Revert "Show JSON data after Location List import"
Feb 28, 2023
5bdbe41
Add location list levels and counts to import
Feb 28, 2023
8d428c3
Update manage location list levels css
Feb 28, 2023
aaa60e0
Move Add Metadata button to top of location levels
Feb 28, 2023
49a7423
updates after review
Feb 28, 2023
3c31bdd
Merge branch 'main' into feature/location-list-updates
Sep 13, 2023
3282158
Allow configuration of multiple location lists
Oct 10, 2023
b18e30f
Merge remote-tracking branch 'origin/main' into feature/location-list…
Oct 10, 2023
c3e121f
Multipl location list functionality
Oct 23, 2023
f120d5b
Update navigation and styles for location list configuration
Oct 23, 2023
86f9bd2
During new group creation, add id and name to location-list metadata
Oct 25, 2023
e86c4ad
Make LocationList a class
Oct 25, 2023
aa3818c
CSV and MySQL-JS modules: parse data from multiple locaiton lists
Nov 1, 2023
f6d0d52
Simplify group location lists read script
Nov 1, 2023
152c27c
Add location list data to tangy-form-editor instance
Nov 1, 2023
1c2ff92
Merge remote-tracking branch 'origin/develop' into feature/location-l…
Nov 1, 2023
6af2f07
Add multiple locations list dir to online survey releases
Nov 2, 2023
757dcce
remove unused file
Nov 7, 2023
0c1cbf1
Fix group location list express app script responses
Nov 7, 2023
c28a4e5
Load context when switching between location list tabs
Nov 7, 2023
37932d0
Updates to tangy-form and tangy-form-editor; fixes
Nov 9, 2023
1eedf26
Update device user list to use multiple location lists
Nov 9, 2023
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
14 changes: 14 additions & 0 deletions content-sets/teach/client/location-lists.json
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"id": "location-1",
"name": "Schools",
"src": "./school-locations.json",
"default": true
},
{
"id": "location-2",
"name": "Hospitals",
"src": "./hospital-locations.json",
"default": false
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.tangy-full-width {
width: 95%;
}

span.tangy-foreground-secondary {
padding-top: 0.3rem;
}

a.faux-anchor {
cursor: pointer;
}

* {
word-wrap: break-word;
}

.gray-bottom-border {
border-bottom: #cccccc 0.5px solid;
}

.text-indent-3 {
text-indent: 3rem;
}

.header {
margin: 15px;
}

.submit {
margin-left: 15px;
margin-bottom: 15px;
}

.export-div {
margin: 15px;
padding-bottom: 30px;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
<div class="tangy-content tangy-full-width">
<p *ngIf="isExporting">{{'Downloading file...'}}</p>
<button mat-raised-button color="warn" (click)="export()" [disabled]="isExporting">{{'Export Location List'|translate}}</button>
<div class="export-div">
<h3> {{'Export CSV'|translate}} </h3>
<p *ngIf="isExportingCSV">{{'Downloading CSV file...'}}</p>
<button mat-raised-button color="primary" (click)="exportAsCSV()" [disabled]="isExportingCSV">{{'Export Location List as CSV'|translate}}</button>
<p>Export a CSV file of the Location List with columns of the location levels and unique identifiers</p>
<p>The file can be modified and imported to update the location list.</p>
</div>
<div class="export-div">
<h3> {{'Export JSON'|translate}} </h3>
<p *ngIf="isExportingJSON">{{'Downloading JSON file...'}}</p>
<button mat-raised-button color="primary" (click)="exportAsJSON()" [disabled]="isExportingJSON">{{'Export Location List as JSON'|translate}}</button>
<p>Export a JSON file of the Location List</p>
<p>This file can be imported in another Group copy over the Location List.</p>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Input } from '@angular/core';
import { GroupsService } from '../services/groups.service';
import { ActivatedRoute } from '@angular/router';
import { Loc } from 'tangy-form/util/loc.js';
Expand All @@ -10,35 +10,41 @@ import * as XLSX from 'xlsx';
styleUrls: ['./export-location-list.component.css']
})
export class ExportLocationListComponent implements OnInit {

@Input() locationListFileName;

groupId:string;
locationEntries = [];
locationObject = {};
nextLevelProcessed = '';
locationLevels = [];
coreProperties = ['level', 'label', 'id', 'children', 'parent', 'descendantsCount'];
isExporting = false;
isExportingCSV = false;
isExportingJSON = false;
constructor(private groupService: GroupsService, private route: ActivatedRoute) { }

async ngOnInit() {
this.groupId = this.route.snapshot.paramMap.get('groupId')
}
async export() {
this.isExporting = true;
const data = await this.groupService.getLocationList(this.route.snapshot.paramMap.get('groupId'));

async exportAsCSV() {
this.isExportingCSV = true;
const data:any = await this.groupService.getLocationList(this.groupId, this.locationListFileName);
const locationListId = data.id
this.locationLevels = data['locationsLevels'] as [];
Object.values(data['locations']).forEach(e => {
this.unwrap(e);
});
const worksheet = XLSX.utils.json_to_sheet(this.locationEntries);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'location-list');
XLSX.writeFile(workbook, 'location-list.xlsx');
XLSX.writeFile(workbook, `${this.groupId}-location-list-${locationListId}.xlsx`);
this.resetValues();
}

resetValues() {
this.locationEntries = [];
this.locationObject = {};
this.nextLevelProcessed = '';
this.isExporting = false;
this.isExportingCSV = false;
}
/**
*
Expand All @@ -60,4 +66,18 @@ export class ExportLocationListComponent implements OnInit {
this.locationEntries.push(this.locationObject);
}
}

async exportAsJSON() {
this.isExportingJSON = true;
const data:any = await this.groupService.getLocationList(this.groupId, this.locationListFileName);
const locationListId = data.id
const jsonData = JSON.stringify(data)
const fileName = `${this.groupId}-location-list-${locationListId}.json`
var downloader = document.createElement('a');
downloader.setAttribute('href', "data:text/json;charset=UTF-8," + encodeURIComponent(jsonData));
downloader.setAttribute('download', fileName);
downloader.click();

this.isExportingJSON = false;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<div *ngIf="ready">
<app-breadcrumb [title]="title" [breadcrumbs]="breadcrumbs"></app-breadcrumb>
<mat-card class="is-link mat-elevation-z3" routerLink="location-list" *appHasAPermission="let i;group:groupId; permission:'can_access_configure_location_list'">
<mat-card class="is-link mat-elevation-z3" routerLink="location-lists" *appHasAPermission="let i;group:groupId; permission:'can_access_configure_location_list'">
<mat-card-header>
<div mat-card-avatar>
<mwc-icon class="tangy-foreground-secondary">place</mwc-icon>
</div>
<mat-card-title>
<a>{{'Location List'|translate}}</a>
<a>{{'Location Lists'|translate}}</a>
</mat-card-title>
<mat-card-subtitle>{{'Manage locations levels and content related to choosing locations on forms, sync, and more.'|translate}}</mat-card-subtitle>
</mat-card-header>
Expand Down
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add container with margin

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.button {
background: var(--mdc-theme-secondary);
color: var(--accent-text-color);
}

.container {
margin: 15px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<app-breadcrumb [title]="title" [breadcrumbs]="breadcrumbs"></app-breadcrumb>
<div id="container" #container>
<p>
Enter a title for the new location list. After clicking submit, you will be able to enter location values manually or import a location list from csv or json.
</p>
<form class="form">
<mat-form-field class="example-full-width">
<mat-label>Title</mat-label>
<input matInput placeholder="Location Title" [(ngModel)]="locationListTitle" name="title" required>
</mat-form-field>
<paper-button class="button" (click)="onSubmit()">submit</paper-button>
</form>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { GroupLocationListNewComponent } from './group-location-list-new.component';

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

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GroupLocationListNewComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(GroupLocationListNewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Component, OnInit, Input } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Breadcrumb } from './../../shared/_components/breadcrumb/breadcrumb.component';
import { GroupsService, LocationList } from '../services/groups.service';
import { _TRANSLATE } from 'src/app/shared/_services/translation-marker';

@Component({
selector: 'app-group-location-list-new',
templateUrl: './group-location-list-new.component.html',
styleUrls: ['./group-location-list-new.component.css']
})
export class GroupLocationListNewComponent implements OnInit {

title = _TRANSLATE('New Location List')
breadcrumbs:Array<Breadcrumb> = [
<Breadcrumb>{
label: _TRANSLATE('Location Lists'),
url: `location-lists/new`
}
]

// Mat form field control type implied
locationListTitle

groupId:string
generatedLocationId:string

constructor(
private groupsService: GroupsService,
private route: ActivatedRoute,
private router: Router
) { }

async ngOnInit() {
this.route.params.subscribe(async params => {
this.groupId = params['groupId'];
this.generatedLocationId = params['locationListId'];
});
}

async onSubmit() {
if (!this.locationListTitle) {
alert(_TRANSLATE('Please provide a title for this location list.'))
return
}

const locationList = new LocationList(
{
id: this.generatedLocationId,
name: this.locationListTitle,
locationsLevels: [],
locations: {},
metadata: {}
}
)
try {
await this.groupsService.createLocationList(this.groupId, locationList)
this.router.navigate(['groups', this.groupId, 'configure', 'location-lists', this.generatedLocationId])
} catch (err) {
alert("Failed to create new location list.")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<app-breadcrumb [title]="title" [breadcrumbs]="breadcrumbs"></app-breadcrumb>
<mat-tab-group>

<mat-tab label="{{'Levels'|translate}}">
<app-manage-location-list-levels></app-manage-location-list-levels>
<mat-tab label="{{'Levels'|translate}}" *ngIf="ready">
<app-manage-location-list-levels locationListFileName="{{ locationListFileName }}"></app-manage-location-list-levels>
</mat-tab>

<mat-tab label="{{'Content'|translate}}">
<app-location-list-editor></app-location-list-editor>
<mat-tab label="{{'Content'|translate}}" *ngIf="ready">
<app-location-list-editor locationListFileName="{{ locationListFileName }}"></app-location-list-editor>
</mat-tab>

<mat-tab label="{{'Import'|translate}}">
<app-import-location-list></app-import-location-list>
<mat-tab label="{{'Import'|translate}}" *ngIf="ready">
<app-import-location-list locationListFileName="{{ locationListFileName }}"></app-import-location-list>
</mat-tab>
<mat-tab label="{{'Export'|translate}}">
<app-export-location-list></app-export-location-list>
<mat-tab label="{{'Export'|translate}}" *ngIf="ready">
<app-export-location-list locationListFileName="{{ locationListFileName }}"></app-export-location-list>
</mat-tab>


Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { _TRANSLATE } from 'src/app/shared/_services/translation-marker';
import { Breadcrumb } from './../../shared/_components/breadcrumb/breadcrumb.component';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { GroupsService } from '../services/groups.service';
import { TangyErrorHandler } from '../../shared/_services/tangy-error-handler.service';

@Component({
selector: 'app-group-location-list',
Expand All @@ -9,18 +12,47 @@ import { Component, OnInit } from '@angular/core';
})
export class GroupLocationListComponent implements OnInit {

title = _TRANSLATE("Location List")
breadcrumbs:Array<Breadcrumb> = []
title = _TRANSLATE("Location Lists")
groupId:string
locationListFileName:string
locationListId:string
stopPolling = false
ready = false

constructor() { }
breadcrumbs:Array<Breadcrumb> = [
<Breadcrumb>{
label: this.title,
url: `location-lists`
}
]

ngOnInit() {
this.breadcrumbs = [
<Breadcrumb>{
label: _TRANSLATE('Location List'),
url: `location-list`
}
]
constructor(
private route: ActivatedRoute,
private groupsService: GroupsService,
private errorHandler: TangyErrorHandler
) {
this.groupId = this.route.snapshot.paramMap.get('groupId');
this.locationListId = this.route.snapshot.paramMap.get('locationListId');

}

async ngOnInit() {
try {
const data: any = await this.groupsService.getLocationLists(this.groupId);
const locationListData = data.find(loc => loc.id == this.locationListId);
this.locationListFileName = locationListData.path

this.breadcrumbs = [
...this.breadcrumbs,
<Breadcrumb>{
label: locationListData.name,
url: `location-lists/${locationListData.id}`
}
]
this.ready = true
} catch (error) {
this.errorHandler.handleError('Could Not Load Location List Data');
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.container {
margin: 15px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<app-breadcrumb [title]="title" [breadcrumbs]="breadcrumbs"></app-breadcrumb>
<div id="container">
{{'Location Lists allow you to define sets of locations that appear as drop down lists. Each location list can be used as inputs in forms or to assign locations to devices.'|translate}}
</div>
<div id="container">
<app-dynamic-table
*ngIf="locationListTableData.length > 0"
[data]="locationListTableData"
(rowDelete)="onRowDelete($event)"
(rowEdit)="onRowEdit($event)"
>
</app-dynamic-table>
</div>
<div *ngIf="locationLists.length === 0" id="no-spreadsheets container">
{{'No Location Lists have been created. Click the + icon in the bottom right to get started.'|translate}}
</div>
<paper-fab (click)="createLocationList()" mat-raised-button icon="add" color="accent" class="action">
</paper-fab>
Loading
Loading