}
logout(): Observable<any> {
+ this.nbTokenService.clear().pipe();
+
return this.http.delete<any>(this.logoutUrl).pipe(
tap(
- ok => this.nbTokenService.clear().pipe(),
+ ok => console.info(`logged out`),
error => console.error(`logout error`),
),
);
import { Component } from '@angular/core';
@Component({
- selector: 'ngx-footer',
+ selector: 'sam-footer',
styleUrls: ['./footer.component.scss'],
template: `
<span class="created-by">Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.</span>
import { Component, Input, OnInit } from '@angular/core';
import { NbMenuService, NbSidebarService } from '@nebular/theme';
-import { NbUserMenuItem } from '@nebular/theme/components/user/user.component';
import { UserService } from '../../../@core/data/users.service';
import { AnalyticsService } from '../../../@core/utils/analytics.service';
import { AuthService } from '../../../@core/auth';
import { tap } from 'rxjs/operators';
@Component({
- selector: 'ngx-header',
+ selector: 'sam-header',
styleUrls: ['./header.component.scss'],
templateUrl: './header.component.html',
})
menuItemClick(event) {
if (event.target === 'logout') {
- this.authService.logout().subscribe(() => this.router.navigate(['/auth/login']));
+ this.authService.logout().subscribe();
+ this.router.navigate(['/auth/login']);
}
}
}
import { Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core';
@Component({
- selector: 'ngx-search-input',
+ selector: 'sam-search-input',
styleUrls: ['./search-input.component.scss'],
template: `
<i class="control-icon ion ion-ios-search"
<nb-layout [center]="layout.id === 'center-column'" windowMode>
<nb-layout-header fixed>
- <ngx-header [position]="sidebar.id === 'left' ? 'normal': 'inverse'"></ngx-header>
+ <sam-header [position]="sidebar.id === 'left' ? 'normal': 'inverse'"></sam-header>
</nb-layout-header>
<nb-sidebar class="menu-sidebar"
</nb-layout-column>
<nb-layout-footer fixed>
- <ngx-footer></ngx-footer>
+ <sam-footer></sam-footer>
</nb-layout-footer>
</nb-layout>
// TODO: move layouts into the framework
@Component({
- selector: 'ngx-main-layout',
+ selector: 'sam-main-layout',
styleUrls: ['./main.layout.scss'],
templateUrl: './main.layout.html',
})
--- /dev/null
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({ name: 'chunks' })
+export class ChunksPipe implements PipeTransform {
+ transform(arr: any, chunkSize: number) {
+ return arr.reduce((prev, cur, index) =>
+ (index % chunkSize) ?
+ prev :
+ prev.concat([arr.slice(index, index + chunkSize)]), []);
+ }
+}
export * from './plural.pipe';
export * from './round.pipe';
export * from './timing.pipe';
+export * from './chunks.pipe';
SearchInputComponent,
} from './components';
-import { CapitalizePipe, PluralPipe, RoundPipe, TimingPipe } from './pipes';
+import { CapitalizePipe, PluralPipe, RoundPipe, TimingPipe, ChunksPipe } from './pipes';
import {
MainLayoutComponent,
} from './layout';
PluralPipe,
RoundPipe,
TimingPipe,
+ ChunksPipe,
];
const NB_THEME_PROVIDERS = [
-/**
- * @license
- * Copyright Akveo. All Rights Reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- */
import { Component, OnInit } from '@angular/core';
import { AnalyticsService } from './@core/utils/analytics.service';
@Component({
- selector: 'ngx-app',
+ selector: 'sam-app',
template: '<router-outlet></router-outlet>',
})
export class AppComponent implements OnInit {
--- /dev/null
+export class Device {
+ duid: string;
+ id: number;
+ ctime: string;
+ descr: string;
+ locked: number;
+ sn: string;
+ model: string;
+ os: OS;
+ type: Type;
+ geo: Geo;
+}
+
+class OS {
+ version: string;
+ name: string;
+ sw: string;
+}
+
+class Type {
+ name: string;
+ descr: string;
+}
+
+class Geo {
+ ip: string;
+ country_code: string;
+ country_name: string;
+ city: string;
+ latitude: string;
+ longitude: string;
+}
--- /dev/null
+export * from './device';
+export * from './update-device';
+export * from './update-devices';
--- /dev/null
+export class UpdateDevice {
+ constructor(id: number, locked: number) {
+ this.id = id;
+ this.locked = locked;
+ }
+
+ id: number;
+ locked: number;
+}
--- /dev/null
+import { UpdateDevice } from './update-device';
+
+export class UpdateDevices {
+ constructor(updates: UpdateDevice[]) {
+ this.updates = updates;
+ }
+
+ updates: UpdateDevice[];
+}
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
- selector: 'ngx-dashboard',
+ selector: 'sam-dashboard',
templateUrl: './dashboard.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
--- /dev/null
+<nb-card class="device-card {{device.type.name}}">
+ <nb-card-body>
+ <div cass="row">
+ <button class="btn btn-icon" [ngClass]="(device.locked===0) ? 'btn-hero-info' : 'btn-hero-danger'" type="button" (click)=toggleLock(device.id,device.locked)>
+ <div class="icon"></div>
+ </button>
+ <div class="info">
+ <div class="title font-w-bold">{{device.type.name | uppercase}}</div>
+ <div class="description font-w-light">{{device.model}}</div>
+ </div>
+ <div *ngIf="device.locked===1" class="locked"><i class="nb-locked"></i></div>
+ </div>
+ </nb-card-body>
+ <nb-card-footer>
+ <nb-actions fullwidth="" size="medium" class="medium full-width">
+ <nb-action>
+ <i class="nb-arrow-retweet"></i><span>Details</span>
+ </nb-action>
+ <nb-action>
+ <i class="nb-list"></i><span>Logs</span>
+ </nb-action>
+ <nb-action>
+ <i class="nb-gear"></i><span>Policies</span>
+ </nb-action>
+ </nb-actions>
+ </nb-card-footer>
+</nb-card>
--- /dev/null
+@import '../../@theme/styles/themes';
+@import '~@nebular/theme/styles/global/bootstrap/breakpoints';
+@import '~bootstrap/scss/mixins/breakpoints';
+
+.nomargin {
+ margin: 0 !important;
+}
+
+.device-card {
+ .btn-icon {
+ float: left;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ .icon {
+ height: 3em;
+ width: 3em;
+ float:left;
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: 3em;
+ background-image: url("/assets/ui/devices/default.png");
+ }
+
+ &.tv .icon {
+ background-image: url("/assets/ui/devices/tv.png");
+ }
+
+ &.smartphone .icon {
+ background-image: url("/assets/ui/devices/smartphone.png");
+ }
+
+ &.lamp .icon {
+ background-image: url("/assets/ui/devices/lamp.png");
+ }
+
+ &.robotcleaner .icon {
+ background-image: url("/assets/ui/devices/robotcleaner.png");
+ }
+
+ &.airconditioner .icon {
+ background-image: url("/assets/ui/devices/aircon.png");
+ }
+
+ &.refrigerator .icon {
+ background-image: url("/assets/ui/devices/refrigerator.png");
+ }
+
+ &.smartplug .icon {
+ background-image: url("/assets/ui/devices/plug.png");
+ }
+
+ &.washer .icon {
+ background-image: url("/assets/ui/devices/washer.png");
+ }
+
+ .info {
+ padding-left: 1em;
+ width: 54%;
+ float:left;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ .title {
+ width: 100%;
+ float:left;
+ font-size: 1.4rem;
+ }
+
+ .description {
+ width: 100%;
+ float:left;
+ opacity: 0.5;
+ font-size: 11pt;
+ }
+ }
+
+ .locked {
+ float: right;
+ font-size: 2rem;
+ }
+
+ //tmp solution, remove after migration
+ nb-actions {
+ &:hover {
+ cursor: pointer;
+ }
+ i {
+ font-size: 1.5em;
+ }
+ }
+}
--- /dev/null
+import { Component, OnInit, Input } from '@angular/core';
+import { DeviceService } from '../../services/device.service';
+import { Device, UpdateDevice } from '../../models';
+
+
+@Component({
+ selector: 'sam-device',
+ templateUrl: './device.component.html',
+ styleUrls: ['./device.component.scss'],
+})
+export class DeviceComponent implements OnInit {
+ @Input() device: Device;
+
+ constructor(private deviceService: DeviceService) {
+ }
+
+ ngOnInit() {
+ }
+
+ toggleLock(): void {
+ const newState = (this.device.locked === 0) ? 1 : 0;
+ const update = new UpdateDevice(this.device.id, newState);
+ this.deviceService.updateDevice(update).subscribe((devices) => this.device = devices[0]);
+ }
+}
--- /dev/null
+import { NgModule } from '@angular/core';
+
+import { ThemeModule } from '../../@theme/theme.module';
+import { DeviceComponent } from './device.component';
+import { DeviceService } from '../../services/device.service';
+
+
+@NgModule({
+ imports: [
+ ThemeModule,
+ ],
+ declarations: [
+ DeviceComponent,
+ ],
+ providers: [
+ DeviceService,
+ ],
+ exports: [
+ DeviceComponent,
+ ],
+})
+export class DeviceModule { }
-<div class="row">
- <nb-card>
- <nb-card-body>Hello Devices page</nb-card-body>
- </nb-card>
+<div *ngFor="let chunk of devices | chunks: 4" class="row">
+ <sam-device *ngFor="let device of chunk" [device]="device" class="col-xxxl-3 col-md-6"></sam-device>
</div>
-import { Component, ChangeDetectionStrategy } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { DeviceService } from '../../services/device.service';
+import { Device } from '../../models';
+
@Component({
- selector: 'ngx-devices',
+ selector: 'sam-devices',
templateUrl: './devices.component.html',
})
-export class DevicesComponent {
+export class DevicesComponent implements OnInit {
+ devices: Device[];
+
+ constructor(private deviceService: DeviceService) {
+ }
+
+ ngOnInit() {
+ this.getAllDevices();
+ }
+
+ getAllDevices(): void {
+ this.deviceService.getAllDevices().subscribe(devices => this.devices = devices);
+ }
}
import { ThemeModule } from '../../@theme/theme.module';
import { DevicesComponent } from './devices.component';
+import { DeviceModule } from '../device/device.module';
+import { DeviceComponent } from '../device/device.component';
+import { DeviceService } from '../../services/device.service';
@NgModule({
imports: [
ThemeModule,
+ DeviceModule,
],
declarations: [
DevicesComponent,
],
+ providers: [
+ DeviceService,
+ ],
})
export class DevicesModule { }
import { MENU_ITEMS } from './pages-menu';
@Component({
- selector: 'ngx-pages',
+ selector: 'sam-pages',
template: `
- <ngx-main-layout>
+ <sam-main-layout>
<nb-menu [items]="menu"></nb-menu>
<router-outlet></router-outlet>
- </ngx-main-layout>
+ </sam-main-layout>
`,
})
export class PagesComponent {
import { PagesComponent } from './pages.component';
import { DashboardModule } from './dashboard/dashboard.module';
import { DevicesModule } from './devices/devices.module';
+import { DeviceModule } from './device/device.module';
import { PagesRoutingModule } from './pages-routing.module';
import { ThemeModule } from '../@theme/theme.module';
PagesRoutingModule,
ThemeModule,
DashboardModule,
+ DeviceModule,
DevicesModule,
],
declarations: [
--- /dev/null
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs/Observable';
+import { tap } from 'rxjs/operators';
+import { Device, UpdateDevice, UpdateDevices } from '../models';
+import { SERVER_URL } from '../../../config';
+
+@Injectable()
+export class DeviceService {
+ private getAllDevicesUrl = SERVER_URL + '/devices';
+ private updateDevicesUrl = SERVER_URL + '/devices/update';
+
+ constructor(private http: HttpClient) { }
+
+ getAllDevices(): Observable<Device[]> {
+ return this.http.get<Device[]>(this.getAllDevicesUrl).pipe(
+ tap(
+ ok => console.info(`got devices`),
+ error => console.error(`get all devices error`),
+ ),
+ );
+ }
+
+ updateDevices(updateDevices: UpdateDevice[]): Observable<Device[]> {
+ const updates = new UpdateDevices(updateDevices);
+
+ return this.http.put<Device[]>(this.updateDevicesUrl, updates).pipe(
+ tap(
+ ok => console.info(`successfully updated`),
+ error => console.error(`error during update`),
+ ),
+ );
+ }
+
+ updateDevice(updateDevices: UpdateDevice): Observable<Device[]> {
+ return this.updateDevices(new Array(updateDevices));
+ }
+}
</head>
<body>
- <ngx-app>Loading...</ngx-app>
+ <sam-app>Loading...</sam-app>
<style>
@-webkit-keyframes spin {
width: 100%;
height: 100%;
z-index: 1003;
- background: #000000;
- overflow: hidden
+ background: #ffffff;
+ overflow: hidden;
}
.spinner div:first-child {
-/**
- * @license
- * Copyright Akveo. All Rights Reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- */
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
"directive-selector": [
true,
"attribute",
- "ngx",
+ "sam",
"camelCase"
],
"component-selector": [
true,
"element",
- "ngx",
+ "sam",
"kebab-case"
],
"ban": [