Skip to content

Commit

Permalink
Merge pull request absmach#39 from manuio/upload
Browse files Browse the repository at this point in the history
UI-23 - Add bulk upload for Things and Channels
  • Loading branch information
drasko committed Feb 5, 2020
2 parents 389859c + 6e1115d commit 51e06d8
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 151 deletions.
16 changes: 16 additions & 0 deletions src/app/common/services/channels/channels.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ export class ChannelsService {
);
}

addChannels(channels: Channel[]) {
return this.http.post(`${environment.channelsUrl}/bulk`, channels, { observe: 'response' })
.map(
resp => {
return resp;
},
)
.catch(
err => {
this.notificationsService.error('Failed to create Channels',
`Error: ${err.status} - ${err.statusText}`);
return Observable.throw(err);
},
);
}

getChannel(channel: string) {
return this.http.get(`${environment.channelsUrl}/${channel}`)
.map(
Expand Down
16 changes: 16 additions & 0 deletions src/app/common/services/things/things.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ export class ThingsService {
);
}

addThings(things: Thing[]) {
return this.http.post(`${environment.thingsUrl}/bulk`, things, { observe: 'response' })
.map(
resp => {
return resp;
},
)
.catch(
err => {
this.notificationsService.error('Failed to create Things',
`Error: ${err.status} - ${err.statusText}`);
return Observable.throw(err);
},
);
}

getThing(thingID: string) {
return this.http.get(environment.thingsUrl + '/' + thingID)
.map(
Expand Down
57 changes: 26 additions & 31 deletions src/app/pages/things/channels/channels.component.html
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
<div class="row">
<div class="col-md-3">
<nb-card status="info">
<nb-card-header>
<nb-card status="info">
<nb-card-header>
<div class="row">
<div class="col-4">
{{ totalChanNumber }} &nbsp; Channels
</nb-card-header>
</nb-card>
</div>
<div class="col-md-3">
<nb-card status="success">
<nb-card-header>
{{ gwCtrlChanNumber }} &nbsp; Gateways Control
</nb-card-header>
</nb-card>
</div>
<div class="col-md-3">
<nb-card status="success">
<nb-card-header>
{{ gwDataChanNumber }} &nbsp; Gateways Data
</nb-card-header>
</nb-card>
</div>
<div class="col-md-3">
<nb-card status="success">
<nb-card-header>
{{ loraChanNumber }} &nbsp; LoRa Applications
</nb-card-header>
</nb-card>
</div>
</div>
</div>
<div class="col-4">
<input nbInput fullWidth placeholder="Search..."
[(ngModel)]="browseServerURI" fieldSize="small">
</div>
<div class="col-2">
<button nbButton size="small" status="success"
(click)="onClickSave($event)">
<nb-icon icon="save-outline"></nb-icon>
Save
</button>
</div>
<div class="col-2">
<button nbButton size="small"
(click)="fileInput.click()">
<nb-icon icon="file-add-outline"></nb-icon>
Upload
<input hidden #fileInput (change)="onFileSelected($event.target.files)" type="file">
</button>
</div>
</div>
</nb-card-header>


<nb-card>
<nb-card-body>
<ng2-smart-table [settings]="settings"
[source]="source"
Expand Down
4 changes: 4 additions & 0 deletions src/app/pages/things/channels/channels.component.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
nb-card-header {
text-align: center;
}

button {
width: 100%;
}
73 changes: 42 additions & 31 deletions src/app/pages/things/channels/channels.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { LocalDataSource } from 'ng2-smart-table';

import { Channel } from 'app/common/interfaces/mainflux.interface';
import { ChannelsService } from 'app/common/services/channels/channels.service';
import { GatewaysService } from 'app/common/services/gateways/gateways.service';
import { LoraService } from 'app/common/services/lora/lora.service';
import { NotificationsService } from 'app/common/services/notifications/notifications.service';
import { ConfirmationComponent } from 'app/shared/confirmation/confirmation.component';
import { DetailsComponent } from 'app/shared/details/details.component';
Expand Down Expand Up @@ -39,6 +37,7 @@ export class ChannelsComponent implements OnInit {
name: {
title: 'Name',
type: 'string',
filter: false,
},
id: {
title: 'ID',
Expand All @@ -51,7 +50,6 @@ export class ChannelsComponent implements OnInit {
type: 'custom',
renderComponent: DetailsComponent,
valuePrepareFunction: (cell, row) => {
row.type = 'channels';
return row;
},
editable: false,
Expand All @@ -68,45 +66,19 @@ export class ChannelsComponent implements OnInit {
source: LocalDataSource = new LocalDataSource();
channels: Channel[];

gwDataChanNumber = 0;
gwCtrlChanNumber = 0;
loraChanNumber = 0;
totalChanNumber = 0;

offset = 0;
limit = 20;
limit = 100;

constructor(
private dialogService: NbDialogService,
private channelsService: ChannelsService,
private gatewaysService: GatewaysService,
private loraService: LoraService,
private notificationsService: NotificationsService,
) { }

ngOnInit() {
this.getChannels();
this.getChannelsStats();
}

getChannelsStats() {
this.gatewaysService.getCtrlChannels(this.offset, this.limit).subscribe(
(resp: any) => {
this.gwCtrlChanNumber = resp.total;
},
);

this.gatewaysService.getDataChannels(this.offset, this.limit).subscribe(
(resp: any) => {
this.gwDataChanNumber = resp.total;
},
);

this.loraService.getChannels(this.offset, this.limit).subscribe(
(resp: any) => {
this.loraChanNumber = resp.total;
},
);
}

getChannels(): void {
Expand All @@ -130,7 +102,6 @@ export class ChannelsComponent implements OnInit {
resp => {
this.notificationsService.success('Channel successfully created', '');
this.getChannels();
this.getChannelsStats();
},
);
}
Expand Down Expand Up @@ -162,4 +133,44 @@ export class ChannelsComponent implements OnInit {
},
);
}

onFileSelected(files: FileList) {
if (files && files.length > 0) {
const file: File = files.item(0);
const reader: FileReader = new FileReader();
reader.readAsText(file);
reader.onload = () => {
const csv: string = reader.result as string;
const lines = csv.split('\n');
const channels: Channel[] = [];

lines.forEach( line => {
const col = line.split('|');
const name = col[0];
if (name !== '' && name !== '<empty string>') {
let metadata = {};
if (col[1] !== undefined) {
try {
metadata = JSON.parse(col[1]);
} catch (e) {
this.notificationsService.warn('Wrong metadata format', '');
}
}

const chann = {
name: name,
metadata: metadata,
};
channels.push(chann);
}
});

this.channelsService.addChannels(channels).subscribe(
resp => {
this.getChannels();
},
);
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export class ChannelsDetailsComponent implements OnInit {
this.thingsService.getThings(this.offset, this.limit).subscribe(
(respThings: any) => {
respThings.things.forEach(thing => {
// Filter get Things resp and keep only disconnected ones.
if (!(this.connections.filter(c => c.id === thing.id).length > 0)) {
this.things.push(thing);
}
Expand All @@ -109,12 +110,14 @@ export class ChannelsDetailsComponent implements OnInit {
}

getchannelMessages() {
this.messagesService.getMessages(this.channel.id, this.connections[0].key).subscribe(
(respMsg: any) => {
if (respMsg.messages) {
this.messages = respMsg.messages;
}
},
);
if (this.connections.length) {
this.messagesService.getMessages(this.channel.id, this.connections[0].key).subscribe(
(respMsg: any) => {
if (respMsg.messages) {
this.messages = respMsg.messages;
}
},
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ export class DevicesDetailsComponent implements OnInit {
} else {
this.messagesService.getMessages(chan.id, this.thing.key, this.thing.id).subscribe(
(respMsg: any) => {
if (respMsg.messages) {
this.messages = respMsg.messages;
}
this.messages = respMsg.messages || this.messages;
},
);
}
Expand Down
59 changes: 20 additions & 39 deletions src/app/pages/things/devices/devices.component.html
Original file line number Diff line number Diff line change
@@ -1,56 +1,37 @@
<div class="row">
<div class="col-xxl-3">
<nb-card status="info">
<nb-card-header>
{{ thingsNumber }} &nbsp; Things
</nb-card-header>
</nb-card>
</div>

<div class="col-xxl-3">
<nb-card status="success">
<nb-card-header>
{{ loraDevicesNumber }} &nbsp; LoRa Devices
</nb-card-header>
</nb-card>
</div>

<div class="col-xxl-3">
<nb-card status="success">
<nb-card-header>
{{ gatewaysNumber }} &nbsp; Gateways
</nb-card-header>
</nb-card>
</div>

<div class="col-xxl-3">
<nb-card status="info">
<nb-card-header>
<div class="row">
<div class="col-md-6">
<button nbButton size="medium" shape="semi-round"
(click)="onClickUpload($event)">
<nb-icon icon="file-add-outline"></nb-icon>
Upload
</button>
<div class="col-4">
{{ thingsNumber }} &nbsp; Devices
</div>
<div class="col-md-6">
<button nbButton size="medium" shape="semi-round"
<div class="col-4">
<input nbInput fullWidth placeholder="Search..."
[(ngModel)]="browseServerURI" fieldSize="small">
</div>
<div class="col-2">
<button nbButton size="small" status="success"
(click)="onClickSave($event)">
<nb-icon icon="save-outline"></nb-icon>
Save
</button>
</div>
<div class="col-2">
<button nbButton size="small"
(click)="fileInput.click()">
<nb-icon icon="file-add-outline"></nb-icon>
Upload
<input hidden #fileInput (change)="onFileSelected($event.target.files)" type="file">
</button>
</div>
</div>
</div>
</div>
</nb-card-header>

<nb-card>
<nb-card-body>
<ng2-smart-table [settings]="settings"
[source]="source"
(createConfirm)="onCreateConfirm($event)"
(editConfirm)="onEditConfirm($event)"
(deleteConfirm)="onDeleteConfirm($event)"
(userRowSelect)="onSelection($event)">
(deleteConfirm)="onDeleteConfirm($event)">
</ng2-smart-table>
</nb-card-body>
</nb-card>
8 changes: 4 additions & 4 deletions src/app/pages/things/devices/devices.component.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
button {
margin: 2px;
}

nb-card-header {
text-align: center;
}

button {
width: 100%;
}
Loading

0 comments on commit 51e06d8

Please sign in to comment.