Переглянути джерело

add devices page

pull/1/head
Jonathan Cobb 5 роки тому
джерело
коміт
f6cb4e830d
10 змінених файлів з 259 додано та 12 видалено
  1. +2
    -0
      src/_helpers/router.js
  2. +20
    -0
      src/_services/device.service.js
  3. +1
    -0
      src/_services/index.js
  4. +91
    -0
      src/_store/devices.module.js
  5. +10
    -2
      src/_store/index.js
  6. +6
    -1
      src/_store/system.module.js
  7. +115
    -0
      src/account/DevicesPage.vue
  8. +11
    -6
      src/account/NetworkPage.vue
  9. +2
    -2
      src/account/NetworksPage.vue
  10. +1
    -1
      src/auth/LoginPage.vue

+ 2
- 0
src/_helpers/router.js Переглянути файл

@@ -10,6 +10,7 @@ import MultifactorAuthPage from '../auth/MultifactorAuthPage'
import ProfilePage from '../account/profile/ProfilePage'
import ActionPage from '../account/profile/ActionPage'
import PolicyPage from '../account/profile/PolicyPage'
import DevicesPage from '../account/DevicesPage'
import NotificationsPage from '../account/NotificationsPage'
import ChangePasswordPage from '../account/profile/ChangePasswordPage'
import SshKeysPage from '../account/profile/SshKeysPage'
@@ -51,6 +52,7 @@ export const router = new Router({
{ path: '/me/action', component: ActionPage },
{ path: '/me/changePassword', component: ChangePasswordPage },
{ path: '/me/keys', component: SshKeysPage },
{ path: '/devices', component: DevicesPage },
{ path: '/notifications', component: NotificationsPage },
{
path: '/bubbles', component: NetworksPage ,


+ 20
- 0
src/_services/device.service.js Переглянути файл

@@ -0,0 +1,20 @@
import config from 'config';
import { util } from '../_helpers';

export const deviceService = {
getDevicesByUserId,
addDeviceByUserId,
removeDeviceByUserId
};

function getDevicesByUserId(userId, messages, errors) {
return fetch(`${config.apiUrl}/users/${userId}/devices`, util.getWithAuth()).then(util.handleCrudResponse(messages, errors));
}

function addDeviceByUserId(userId, device, messages, errors) {
return fetch(`${config.apiUrl}/users/${userId}/devices`, util.putWithAuth(device)).then(util.handleCrudResponse(messages, errors));
}

function removeDeviceByUserId(userId, deviceId, messages, errors) {
return fetch(`${config.apiUrl}/users/${userId}/devices/${deviceId}`, util.deleteWithAuth()).then(util.handleCrudResponse(messages, errors));
}

+ 1
- 0
src/_services/index.js Переглянути файл

@@ -6,3 +6,4 @@ export * from './footprint.service';
export * from './paymentMethod.service';
export * from './accountPlan.service';
export * from './network.service';
export * from './device.service';

+ 91
- 0
src/_store/devices.module.js Переглянути файл

@@ -0,0 +1,91 @@
import { deviceService } from '../_services';
import { util } from '../_helpers';

const state = {
loading: {
devices: false, addDevice: false, removeDevice: false
},
error: null,
devices: [],
device: null
};

const actions = {
getDevicesByUserId({ commit }, {userId, messages, errors}) {
commit('getDevicesByUserIdRequest');
deviceService.getDevicesByUserId(userId, messages, errors)
.then(
devices => commit('getDevicesByUserIdSuccess', devices),
error => commit('getDevicesByUserIdFailure', error)
);
},

addDeviceByUserId({ commit }, {userId, device, messages, errors}) {
commit('addDeviceByUserIdRequest');
deviceService.addDeviceByUserId(userId, device, messages, errors)
.then(
device => commit('addDeviceByUserIdSuccess', device),
error => commit('addDeviceByUserIdFailure', error)
);
},

removeDeviceByUserId({ commit }, {userId, deviceId, messages, errors}) {
commit('removeDeviceByUserIdRequest', deviceId);
deviceService.removeDeviceByUserId(userId, deviceId, messages, errors)
.then(
ok => commit('removeDeviceByUserIdSuccess', deviceId),
error => commit('removeDeviceByUserIdFailure', error)
);
}
};

const mutations = {
getDevicesByUserIdRequest(state) {
state.loading.devices = true;
},
getDevicesByUserIdSuccess(state, devices) {
state.loading.devices = false;
state.devices = devices;
},
getDevicesByUserIdFailure(state, error) {
state.loading.users = false;
state.error = error;
},

addDeviceByUserIdRequest(state) {
state.loading.addDevice = true;
},
addDeviceByUserIdSuccess(state, device) {
state.loading.addDevice = false;
state.devices.push(device);
state.device = device;
},
addDeviceByUserIdFailure(state, error) {
state.loading.addDevice = false;
state.error = error;
},

removeDeviceByUserIdRequest(state, deviceId) {
state.loading.removeDevice = true;
},
removeDeviceByUserIdSuccess(state, deviceId) {
state.loading.removeDevice = false;
state.devices = state.devices.filter(function(d) { return d.uuid !== deviceId; });
},
removeDeviceByUserIdFailure(state, error) {
state.loading.removeDevice = false;
state.error = error;
}
};

const getters = {
loading: util.checkLoading(state.loading)
};

export const devices = {
namespaced: true,
state,
actions,
mutations,
getters
};

+ 10
- 2
src/_store/index.js Переглянути файл

@@ -11,6 +11,7 @@ import { domains } from './domains.module';
import { paymentMethods } from './paymentMethods.module';
import { accountPlans } from './accountPlans.module';
import { networks } from './networks.module';
import { devices } from './devices.module';

Vue.use(Vuex);

@@ -25,7 +26,8 @@ export const store = new Vuex.Store({
domains,
paymentMethods,
accountPlans,
networks
networks,
devices
}
});

@@ -53,6 +55,7 @@ String.prototype.parseMessage = function (vue, ctx) {
};

String.prototype.parseDateMessage = function (millis, messages) {
if (typeof millis === 'undefined' || millis === null || millis === 0) return messages.label_date_undefined;
const date = new Date(millis);
const context = {
YYYY: date.getFullYear(),
@@ -60,7 +63,12 @@ String.prototype.parseDateMessage = function (millis, messages) {
M: messages['label_date_month_short_'+date.getMonth()],
EEE: messages['label_date_day_'+date.getDay()],
E: messages['label_date_day_short_'+date.getDay()],
d: date.getDate()
d: date.getDate(),
H: date.getHours(),
h: (date.getHours() > 12 ? date.getHours() - 12 : date.getHours()+1),
a: (date.getHours() > 12 ? messages['label_date_day_half_pm'] : messages['label_date_day_half_am']),
m: date.getMinutes(),
s: date.getSeconds()
};
return this ? ''+this.replace(/{{[\w]+?}}/g, match => {
const expression = match.slice(2, -2);


+ 6
- 1
src/_store/system.module.js Переглянути файл

@@ -1,9 +1,10 @@
import { systemService, userService } from '../_services';
import { systemService } from '../_services';
import { account } from "./account.module";
import { router } from "../_helpers";

const state = {
configs: {
networkUuid: null,
allowRegistration: false,
paymentsEnabled: false,
sageLauncher: false,
@@ -150,6 +151,10 @@ const getters = {
href: '/me',
title: messages.label_menu_account,
icon: messages.label_menu_account_icon
}, {
href: '/devices',
title: messages.label_menu_devices,
icon: messages.label_menu_devices_icon
}, {
href: '/notifications',
title: messages.label_menu_notifications,


+ 115
- 0
src/account/DevicesPage.vue Переглянути файл

@@ -0,0 +1,115 @@
<template>
<div>
<em v-if="loading && loading.devices">{{messages.loading_devices}}</em>
<div v-if="devices && devices.length > 0">
<h2>{{messages.table_title_devices}}</h2>
<table border="1">
<thead>
<tr>
<th nowrap="nowrap">{{messages.label_field_device_name}}</th>
<!-- <th nowrap="nowrap">{{messages.label_field_device_enabled}}</th>-->
<th>{{messages.label_field_device_ctime}}</th>
<th><!-- delete --></th>
</tr>
</thead>
<tbody>
<tr v-for="device in devices">
<td nowrap="nowrap">{{device.name}}</td>
<!-- <td>{{messages['message_'+device.enabled]}}</td>-->
<td nowrap="nowrap">{{messages.label_device_ctime_format.parseDateMessage(device.ctime, messages)}}</td>
<td>
<i @click="removeDevice(device.uuid)" aria-hidden="true" :class="messages.button_label_remove_device_icon" :title="messages.button_label_remove_device"></i>
<span class="sr-only">{{messages.button_label_remove_device}}</span>
</td>
</tr>
</tbody>
</table>
<hr/>
<router-link to="/new_bubble">{{messages.button_label_new_network}}</router-link>
</div>

<div v-if="!devices || devices.length === 0">
{{messages.message_no_devices}}
</div>

<hr/>

<form @submit.prevent="addDevice()">
<h4>{{messages.form_title_add_device}}</h4>

<div class="form-group">
<label htmlFor="name">{{messages.label_field_device_name}}</label>
<input v-model="deviceName" name="name" class="form-control"/>
<div v-if="submitted && errors.has('name')" class="invalid-feedback d-block">{{ errors.first('name') }}</div>
<div v-if="submitted && errors.has('deviceName')" class="invalid-feedback d-block">{{ errors.first('deviceName') }}</div>
</div>

<hr/>
<div class="form-group">
<button class="btn btn-primary" :disabled="loading()">{{messages.button_label_add_device}}</button>
<img v-show="loading()" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
</div>
</form>

</div>
</template>

<script>
import { mapState, mapActions, mapGetters } from 'vuex';
import { util } from '../_helpers';

export default {
data () {
return {
userId: util.currentUser().uuid,
submitted: false,
deviceName: null
};
},
computed: {
...mapState('devices', ['devices', 'device']),
...mapState('system', ['messages'])
},
created () {
this.getDevicesByUserId({
userId: this.userId,
messages: this.messages,
errors: this.errors
});
},
methods: {
...mapActions('devices', ['getDevicesByUserId', 'addDeviceByUserId', 'removeDeviceByUserId']),
...mapGetters('devices', ['loading']),
addDevice () {
this.errors.clear();
this.submitted = true;
this.addDeviceByUserId({
userId: this.userId,
device: {
name: this.deviceName
},
messages: this.messages,
errors: this.errors
});
},
removeDevice (id) {
this.errors.clear();
this.submitted = true;
this.removeDeviceByUserId({
userId: this.userId,
deviceId: id,
messages: this.messages,
errors: this.errors
});
}
},
watch: {
device(dev) {
if (dev) {
// after device added, clear device name field
this.deviceName = null;
}
}
}
};
</script>

+ 11
- 6
src/account/NetworkPage.vue Переглянути файл

@@ -1,6 +1,10 @@
<template>
<div v-if="network">
<h4>{{network.name}}.{{network.domainName}} - <i>{{messages['msg_network_state_'+network.state]}}</i></h4>
<h4 v-if="network.state === 'running' && configs.networkUuid && network.uuid !== configs.networkUuid">
<a :href="'https://'+network.name+'.'+network.domainName+':1443/'">{{network.name}}.{{network.domainName}}</a> - <i>{{messages['msg_network_state_'+network.state]}}</i>
</h4>
<h4 v-else>{{network.name}}.{{network.domainName}} - <i>{{messages['msg_network_state_'+network.state]}}</i></h4>

<div v-if="stats && network.state !== 'stopped'">
<!-- adapted from: https://code-boxx.com/simple-vanilla-javascript-progress-bar/ -->
<div class="progress-wrap">
@@ -20,7 +24,7 @@
<table border="1">
<thead>
<tr>
<th nowrap="nowrap">{{messages.label_field_nodes_fqdn}}</th>
<th nowrap="nowrap">{{messages.label_field_nodes_name}}</th>
<th nowrap="nowrap">{{messages.label_field_nodes_region}}</th>
<th nowrap="nowrap">{{messages.label_field_nodes_ip4}}</th>
<th nowrap="nowrap">{{messages.label_field_nodes_ip6}}</th>
@@ -29,7 +33,7 @@
</thead>
<tbody>
<tr v-for="node in networkNodes">
<td>{{node.fqdn}}</td>
<td>{{node.name}}</td>
<td nowrap="nowrap">{{node.region}}</td>
<td>{{node.ip4}}</td>
<td>{{node.ip6}}</td>
@@ -39,7 +43,7 @@
</table>
</div>

<div v-if="network.state === 'running'">
<div v-if="network.state === 'running' && configs.networkUuid && network.uuid === configs.networkUuid">
<button @click="requestRestoreKey()">{{messages.link_network_action_request_keys}}</button>
<div v-if="errors.has('networkKeys')" class="invalid-feedback d-block">{{ errors.first('networkKeys') }}</div>
<div v-if="networkKeysRequested && networkKeysRequested === networkId">{{messages.message_network_action_keys_requested}}</div>
@@ -66,12 +70,13 @@
</form>
</div>

<hr/>

<div v-if="network.state === 'stopped'">
<!-- todo: add button to restart network in restore mode -->
</div>

<div>
<hr/>
<div class="text-danger"><h4>{{messages.title_network_danger_zone}}</h4></div>
<div v-if="errors.has('node')" class="invalid-feedback d-block">{{ errors.first('node') }}</div>
<div v-if="errors.has('accountPlan')" class="invalid-feedback d-block">{{ errors.first('accountPlan') }}</div>
@@ -111,7 +116,7 @@
'network', 'newNodeNotification', 'networkStatuses', 'networkNodes', 'networkKeysRequested',
'deletedNetwork', 'networkKeys'
]),
...mapState('system', ['messages'])
...mapState('system', ['messages', 'configs'])
},
methods: {
...mapActions('networks', [


+ 2
- 2
src/account/NetworksPage.vue Переглянути файл

@@ -34,8 +34,8 @@
</template>

<script>
import { mapState, mapActions, mapGetters } from 'vuex'
import { util } from '../_helpers'
import { mapState, mapActions, mapGetters } from 'vuex';
import { util } from '../_helpers';

export default {
computed: {


+ 1
- 1
src/auth/LoginPage.vue Переглянути файл

@@ -36,7 +36,7 @@ export default {
return {
name: '',
password: '',
unlockKey: null,
unlockKey: (this.$route.params && this.$route.params.k) ? this.$route.params.k : null,
submitted: false
}
},


Завантаження…
Відмінити
Зберегти