adds existing app

This commit is contained in:
Dimitrie Stefanescu
2019-08-12 11:18:02 +01:00
commit e793b13320
24 changed files with 12074 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
> 1%
last 2 versions
not ie <= 8
+21
View File
@@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
+29
View File
@@ -0,0 +1,29 @@
# speckle-ui
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}
+10923
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
{
"name": "speckle-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"material-design-icons-iconfont": "^3.0.3",
"roboto-fontface": "*",
"vue": "^2.6.6",
"vue-router": "^3.0.1",
"vuetify": "^1.5.5",
"vuex": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.5.0",
"@vue/cli-service": "^3.5.0",
"axios": "^0.18.0",
"node-sass": "^4.9.0",
"sass-loader": "^7.1.0",
"sockette": "^2.0.5",
"vue-cli-plugin-vuetify": "^0.5.0",
"vue-template-compiler": "^2.5.21",
"vue-timeago": "^5.0.0"
}
}
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>speckle-ui</title>
</head>
<body>
<noscript>
<strong>We're sorry but speckle-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
+96
View File
@@ -0,0 +1,96 @@
<template>
<v-app>
<v-toolbar app>
<v-toolbar-title class="headline text-uppercase">
<span @click='showDev()'>Speckle </span>
<span class="font-weight-light">{{$store.state.hostAppName}}</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn color="secondary" dark absolute bottom right fab :ripple="false" @click.native='showAddNewReceiver=true'>
<v-icon>cloud_download</v-icon>
</v-btn>
<v-btn color="primary" absolute bottom right fab :ripple="false" @click.native='showAddNewSender=true' style="margin-right:60px">
<v-icon>cloud_upload</v-icon>
</v-btn>
</v-toolbar>
<v-dialog v-model="showAddNewReceiver" scrollable fullscreen>
<NewClient :is-visible='showAddNewReceiver' @close='showAddNewReceiver=false'>
</NewClient>
</v-dialog>
<v-dialog v-model="showAddNewSender" scrollable fullscreen>
<NewClientSender :is-visible='showAddNewSender' @close='showAddNewSender=false'>
</NewClientSender>
</v-dialog>
<v-content>
<v-container grid-list-md pa-0 mt-4>
<v-layout row wrap>
<v-flex xs12 md6 pa-3 xxxv-if='receivers.length>0'>
<span class='headline text-uppercase secondary--text'>Receivers</span>
<v-divider class='my-4 secondary'></v-divider>
<span class="" v-if="receivers.length===0">There are no receiver clients in this file.</span>
<v-container grid-list-xl>
<v-layout row wrap>
<client-receiver v-for='client in receivers' :key='client.streamId + ":" + client.AccountId' :client='client '>
</client-receiver>
</v-layout>
</v-container>
</v-flex>
<v-flex xs12 md6 pa-3>
<span class='headline text-uppercase primary--text'>Senders</span>
<v-divider class='my-4 primary'></v-divider>
<v-container grid-list-xl>
<v-layout row wrap>
<client-sender v-for='client in senders' :key='client.streamId + ":" + client.AccountId' :client='client'>{{client}}</client-sender>
</v-layout>
</v-container>
</v-flex>
</v-layout>
</v-container>
</v-content>
</v-app>
</template>
<script>
import HelloWorld from './components/HelloWorld'
import NewClient from './components/NewClient.vue'
import NewClientSender from './components/NewClientSender.vue'
import ClientReceiver from './components/ClientReceiver.vue'
import ClientSender from './components/ClientSender.vue'
export default {
name: 'App',
components: {
HelloWorld,
NewClient,
NewClientSender,
ClientReceiver,
ClientSender
},
computed: {
receivers( ) {
return this.$store.state.clients.filter( cl => cl.type === 'receiver' )
},
senders( ) {
return this.$store.state.clients.filter( cl => cl.type === 'sender' )
}
},
data( ) {
return {
showAddNewReceiver: false,
showAddNewSender: false
}
},
methods: {
showDev( ) {
console.log( 'showing dev' )
UiBindings.showDev( )
}
},
mounted( ) {
console.log( 'app mounted!' )
this.$store.dispatch( 'getAccounts' )
this.$store.dispatch( 'getApplicationHostName' )
this.$store.dispatch( 'getExistingClients' )
}
}
</script>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>

After

Width:  |  Height:  |  Size: 539 B

+183
View File
@@ -0,0 +1,183 @@
<template>
<v-flex xs12>
<v-hover>
<v-card
:class="`elevation-${client.expired ? '15' : '1'} ${client.expired ? 'expired' : ''}`"
slot-scope="{ hover }"
>
<v-toolbar color="secondary text-truncate elevation-0" dark>
<v-icon color="white">cloud_download</v-icon>
<v-toolbar-title class="text-truncate font-weight-light">{{client.name}}</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn
icon
:href="`${client.account.RestApi.replace('api','#')}streams/${client.streamId}`"
target="_blank"
>
<v-icon>open_in_new</v-icon>
</v-btn>
<v-btn :flat="!client.expired" @click.native="bakeReceiver()">
Pull
<v-icon small right>cloud_download</v-icon>
</v-btn>
</v-toolbar>
<v-card-text class="caption">
<span>
<v-icon small>developer_board</v-icon>
{{account.ServerName}}
</span>&nbsp;
<span class="caption">
<v-icon small>vpn_key</v-icon>StreamId:
<span style="user-select:all;">
<b>{{client.streamId}}</b>
</span>
</span>&nbsp;
<span class="caption">
<v-icon small>hourglass_full</v-icon>Last update:
<timeago :datetime="client.updatedAt" :auto-update="60"></timeago>
</span>
<v-progress-linear
v-show="client.loading"
:active="client.loading"
:indeterminate="client.isLoadingIndeterminate"
height="2"
v-model="client.loadingProgress"
color="primary darken-1"
></v-progress-linear>
<br>
<span class="caption text--lighten-3">{{client.loadingBlurb}}</span>&nbsp;
<span class="caption grey--text">Total objects: {{client.objects.length}}</span>
</v-card-text>
<v-card-actions>
<v-btn small icon @click.native="selectObjects">
<v-icon small>gps_fixed</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn small flat outline icon color="error" @click.native="deleteClient">
<v-icon small>delete</v-icon>
</v-btn>
</v-card-actions>
<v-alert
v-model="client.expired"
dismissible
color="grey darken-2"
v-if="client.message && client.message!== ''"
>{{client.message}}</v-alert>
<v-alert
v-model="client.errors"
dismissible
type="warning"
xxxcolor="grey darken-2"
v-if="client.errors && client.errors!== ''"
><div v-html="client.errors"></div></v-alert>
</v-card>
</v-hover>
</v-flex>
</template>
<script>
import Sockette from "sockette";
export default {
name: "Client",
props: {
client: {
type: Object,
default: null
}
},
computed: {
account() {
return this.$store.state.accounts.find(
ac => ac.AccountId === this.client.AccountId
);
},
updatedAt() {
return new Date(this.client.updatedAt).toLocaleDateString();
}
},
data: () => ({}),
methods: {
bakeReceiver() {
this.$store.dispatch("bakeReceiver", this.client);
},
deleteClient() {
this.$store.dispatch("removeReceiverClient", this.client);
this.sockette.close();
},
selectObjects() {
UiBindings.selectClientObjects(JSON.stringify(this.client));
},
wsOpen(e) {
this.sockette.json({
eventName: "join",
resourceType: "stream",
resourceId: this.client.streamId
});
},
wsMessage(e) {
console.log(e.data);
if (e.data === "ping") {
this.sockette.send("alive");
return;
}
try {
let message = JSON.parse(e.data);
switch (message.args.eventType) {
case "update-global":
this.$store.dispatch("updateClient", {
client: this.client,
expire: true
});
break;
case "update-meta":
this.$store.dispatch("updateClient", {
client: this.client,
expire: false
});
break;
}
} catch (err) {
console.warn(
`Could not parse/interpret ${e.data} for ${this.client.streamId}`
);
console.log(e.data);
}
},
wsError(e) {
console.log(e);
},
wsReconnect(e) {
console.log(e);
},
wsClose(e) {
console.log(e);
}
},
mounted() {
console.log("client mounted!");
console.log(this.client);
let wsUrl = this.account.RestApi.replace("http", "ws");
this.sockette = new Sockette(
`${wsUrl}?client_id=${this.client.clientId}&access_token=${
this.account.Token
}`,
{
timeout: 5e3,
maxAttempts: 100,
onopen: this.wsOpen,
onmessage: this.wsMessage,
onerror: this.wsError,
onreconnect: this.wsReconnect,
onclose: this.wsClose
}
);
},
beforeDestroy() {
console.log("bye bye...");
this.sockette.close();
}
};
</script>
<style scoped lang='scss'>
</style>
+216
View File
@@ -0,0 +1,216 @@
<template>
<v-flex xs12>
<v-hover>
<v-card
:class="`elevation-${client.expired ? '15' : '1'} ${client.expired ? 'expired' : ''}`"
slot-scope="{ hover }"
>
<v-toolbar color="primary xxxdarken-1 text-truncate elevation-0" dark>
<v-icon color="white">cloud_upload</v-icon>
<v-toolbar-title class="text-truncate font-weight-light">{{client.name}}</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn
icon
:href="`${client.account.RestApi.replace('api','#')}streams/${client.streamId}`"
target="_blank"
>
<v-icon>open_in_new</v-icon>
</v-btn>
<v-btn :flat="!client.expired" @click.native="startUpload()">
Push
<v-icon small right>cloud_upload</v-icon>
</v-btn>
</v-toolbar>
<v-card-text class="caption">
<span>
<v-icon small>developer_board</v-icon>
{{account.ServerName}}
</span>&nbsp;
<span class="caption">
<v-icon small>vpn_key</v-icon>StreamId:
<span style="user-select:all;">
<b>{{client.streamId}}</b>
</span>
</span>&nbsp;
<span class="caption">
<v-icon small>hourglass_full</v-icon>Last update:
<timeago :datetime="client.updatedAt" :auto-update="60"></timeago>
</span>
<v-progress-linear
:active="client.loading"
:indeterminate="client.isLoadingIndeterminate"
height="2"
v-model="client.loadingProgress"
color="primary darken-1"
></v-progress-linear>
<span class="caption text--lighten-3">{{client.loadingBlurb}}</span>&nbsp;
<span class="caption grey--text">Total objects: {{client.objects.length}}</span>
</v-card-text>
<!-- <v-card-text class="caption text--lighten-3">{{client.message}}</v-card-text> -->
<v-card-actions>
<!-- <v-btn @click.native="startUpload()">PUSH</v-btn>&nbsp; -->
<v-btn
small
round
:disabled="$store.state.selectionCount===0"
@click.native="addSelection()"
>
add
<v-icon right>add</v-icon>
</v-btn>&nbsp;
<v-btn
small
round
:disabled="$store.state.selectionCount===0"
@click.native="removeSelection()"
>
remove
<v-icon right>remove</v-icon>
</v-btn>&nbsp;&nbsp;
<span
class="caption grey--text"
>{{$store.state.selectionCount}} selected objects</span>
<v-btn small icon @click.native="selectObjects">
<v-icon small>gps_fixed</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn small flat outline icon color="error" @click.native="deleteClient">
<v-icon small>delete</v-icon>
</v-btn>
</v-card-actions>
<v-alert
v-model="client.expired"
dismissible
color="grey darken-2"
v-if="client.message && client.message!== ''"
>{{client.message}}</v-alert>
<v-alert
v-model="client.errors"
dismissible
type="warning"
xxxcolor="grey darken-2"
v-if="client.errors && client.errors!== ''"
>{{client.errors}}</v-alert>
</v-card>
</v-hover>
</v-flex>
</template>
<script>
import Sockette from "sockette";
export default {
name: "SenderClient",
props: {
client: {
type: Object,
default: null
}
},
computed: {
account() {
return this.$store.state.accounts.find(
ac => ac.AccountId === this.client.AccountId
);
},
updatedAt() {
return new Date(this.client.updatedAt).toLocaleDateString();
}
},
watch: {
"client.loading"(val, oldVal) {
if (!val && this.sendStarted) this.broadcastSendEnd();
},
client: {
handler(val, oldVal) {
console.log(val);
},
deep: true
}
},
data: () => ({
sendStarted: false
}),
methods: {
startUpload() {
this.sendStarted = true;
this.$store.dispatch("cloneStream", this.client);
this.client.updatedAt = new Date().toISOString();
this.client.message = "";
this.client.expired = false;
UiBindings.updateSender(JSON.stringify(this.client));
},
deleteClient() {
this.$store.dispatch("removeReceiverClient", this.client);
this.sockette.close();
},
broadcastSendEnd() {
this.sendStarted = false;
this.sockette.json({
eventName: "broadcast",
resourceType: "stream",
resourceId: this.client.streamId,
args: {
eventType: "update-global"
}
});
},
addSelection() {
UiBindings.addSelectionToSender(JSON.stringify(this.client));
},
removeSelection() {
UiBindings.removeSelectionFromSender(JSON.stringify(this.client));
},
selectObjects() {
UiBindings.selectClientObjects(JSON.stringify(this.client));
},
wsOpen(e) {
this.sockette.json({
eventName: "join",
resourceType: "stream",
resourceId: this.client.streamId
});
},
wsMessage(e) {
console.log(e.data);
if (e.data === "ping") {
this.sockette.send("alive");
return;
}
},
wsError(e) {
console.log(e);
},
wsReconnect(e) {
console.log(e);
},
wsClose(e) {
console.log(e);
}
},
mounted() {
let wsUrl = this.account.RestApi.replace("http", "ws");
this.sockette = new Sockette(
`${wsUrl}?client_id=${this.client.clientId}&access_token=${
this.account.Token
}`,
{
timeout: 5e3,
maxAttempts: 100,
onopen: this.wsOpen,
onmessage: this.wsMessage,
onerror: this.wsError,
onreconnect: this.wsReconnect,
onclose: this.wsClose
}
);
},
beforeDestroy() {
this.sockette.close();
}
};
</script>
<style scoped lang='scss'>
.expired {
// border-left: 12px solid red;
}
</style>
+18
View File
@@ -0,0 +1,18 @@
<template>
<v-container>
<v-layout text-xs-center wrap>
<v-flex xs12>
Hello World.
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
data: ( ) => ( {
} )
}
</script>
<style scoped lang='scss'>
</style>
+114
View File
@@ -0,0 +1,114 @@
<template>
<v-card>
<v-toolbar card dark color="secondary">
<v-btn icon dark @click="$emit('close')">
<v-icon>close</v-icon>
</v-btn>
<v-toolbar-title class="text-truncate font-weight-light">Add a new receiver</v-toolbar-title>
</v-toolbar>
<v-card-text class="pa-5">
<v-layout row wrap align-center>
<v-flex xs12>
<p class="headline font-weight-light">Account</p>
<p class="caption">We first need to know which speckle server the data is coming from.</p>
<v-overflow-btn
:items="$store.state.accounts"
label="Account"
editable
solo
v-model="selectedAccount"
item-text="fullName"
return-object
></v-overflow-btn>
</v-flex>
</v-layout>
<v-layout row wrap align-center v-if="selectedAccount && selectedAccount.streams.length > 0">
<v-flex xs12>
<p class="headline font-weight-light">Stream</p>
<p
class="caption"
>If the stream you're looking for doesn't show up here, try refreshing the list and make sure it's shared with you!</p>
<v-overflow-btn
append-icon="refresh"
@click:append="refreshStreamsAtAccount()"
:items="selectedAccount.streams"
:label="'Streams from ' + selectedAccount.fullName"
editable
v-model="selectedStream"
item-text="fullName"
return-object
></v-overflow-btn>
<!-- <v-select :items="selectedAccount.streams" item-text="name"></v-select> -->
</v-flex>
<v-flex xs12 v-if="selectedStream" class="caption">
Last updated:
<timeago :datetime="selectedStream.updatedAt" :auto-update="60"></timeago>
</v-flex>
</v-layout>
<v-layout row wrap align-center>
<v-flex
xs12
class="text-xs-left"
v-if="selectedAccount && selectedAccount.streams.length===0"
>Seems like you don't have any streams to receive. Get someone to share some with you, or, even better, create one!</v-flex>
<v-flex
xs12
class="text-xs-left"
v-if="!selectedAccount || !selectedAccount.validated"
>Could not access that server (is it online?) or no server selected.</v-flex>
</v-layout>
<v-layout row wrap align-center>
<v-btn
color="secondary"
block
:ripple="false"
:disabled="selectedStream===null"
@click.native="addReceiver()"
>Create Receiver</v-btn>
</v-layout>
<v-alert
value="true"
type="info"
>If the stream contains objects that cannot be converted to Revit, they will not be visible in any way.</v-alert>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: "NewClient",
props: {
isVisible: { type: Boolean, default: false }
},
watch: {
selectedAccount(val) {
// todo: get streams for the account
},
isVisible(val) {
if (val) {
this.selectedAccount = this.$store.state.accounts.find(
ac => ac.IsDefault === true
);
this.selectedStream = null;
}
}
},
data: () => ({
selectedAccount: null,
selectedStream: null
}),
methods: {
refreshStreamsAtAccount() {
this.$store.dispatch("getAccountStreams", this.selectedAccount);
},
async addReceiver() {
let res = await this.$store.dispatch("addReceiverClient", {
account: this.selectedAccount,
stream: this.selectedStream
});
this.$emit("close");
}
}
};
</script>
<style scoped lang='scss'>
</style>
+92
View File
@@ -0,0 +1,92 @@
<template>
<v-card>
<v-toolbar card dark color="primary">
<v-btn icon dark @click="$emit('close')">
<v-icon>close</v-icon>
</v-btn>
<v-toolbar-title class="text-truncate font-weight-light">Add a new sender</v-toolbar-title>
</v-toolbar>
<v-card-text class='pa-5'>
<v-layout row wrap align-center >
<v-flex xs12>
<p class='headline font-weight-light'>Account</p>
<p class='caption'>We first need to know which speckle server the data is going to go to.</p>
<v-overflow-btn :items="$store.state.accounts" label="Account" editable solo v-model='selectedAccount' item-text='fullName' return-object></v-overflow-btn>
</v-flex>
</v-layout>
<v-layout row wrap align-center v-if='selectedAccount'>
<v-flex xs12>
<p class='headline font-weight-light'>Stream Name</p>
<p class='caption'>Something meaningful would do, like 'walls-final-final-2'.</p>
<v-text-field label="walls-final-final-2" single-line solo v-model='newStreamName'></v-text-field>
</v-flex>
<v-flex xs12>
<p class='headline font-weight-light'>Objects</p>
<p class='caption'>Will add current object selection to this stream ({{$store.state.selectionCount}}). If no objects are selected in the host application, you will be able to add some later.</p>
</v-flex>
</v-layout>
<v-layout row wrap align-center>
<v-flex xs12 class='text-xs-left' v-if='!selectedAccount || !selectedAccount.validated'>
Could not access that server (is it online?) or no server selected.
</v-flex>
</v-layout>
<br>
<v-layout row wrap align-center>
<!-- <v-spacer></v-spacer> -->
<v-btn block color="primary" :ripple="false" :disabled='!validated' @click.native='addSender()'>
Create Sender
</v-btn>
</v-layout>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: 'NewClient',
props: {
isVisible: { type: Boolean, default: false }
},
watch: {
isVisible( val ) {
if ( val ) {
this.selectedAccount = this.$store.state.accounts.find( ac => ac.IsDefault === true )
this.selectedStream = null
}
}
},
computed: {
validated( ) {
if ( this.newStreamName !== null )
return true
return false
}
},
data: ( ) => ( {
selectedAccount: null,
newStreamName: null,
selectedObjects: [ ]
} ),
methods: {
async refreshSelection( ) {
let res = await UiBindings.getObjectSelection( )
if ( res ) {
this.selectedObjects = JSON.parse( res )
} else
this.selectedObjects = [ ]
},
refreshStreamsAtAccount( ) {
this.$store.dispatch( 'getAccountStreams', this.selectedAccount )
},
async addSender( ) {
let res = await this.$store.dispatch( 'addSenderClient', { account: this.selectedAccount, streamName: this.newStreamName, objects: this.selectedObjects } )
this.$emit( "close" )
}
},
mounted( ) {
this.refreshSelection( )
}
}
</script>
<style scoped lang='scss'>
</style>
+39
View File
@@ -0,0 +1,39 @@
import Vue from 'vue'
import './plugins/vuetify'
import App from './App.vue'
import router from './router'
import store from './store'
import 'roboto-fontface/css/roboto/roboto-fontface.css'
import 'material-design-icons-iconfont/dist/material-design-icons.css'
Vue.config.productionTip = false
import VueTimeago from 'vue-timeago'
Vue.use( VueTimeago, {
name: 'Timeago',
locale: 'en',
} )
// set up an event bus on the window, to be used by the SpeckleUiBindings class to send events here
window.EventBus = new Vue( )
// generic route used for quite a bit of comms
window.EventBus.$on( 'update-client', args => {
let cl = JSON.parse( args )
console.log( cl )
window.Store.commit( 'SET_CLIENT_DATA', cl )
} )
// keeps track of the selected objects in revit
window.EventBus.$on( 'update-selection-count', args => {
let parsed = JSON.parse( args )
if ( window.Store )
window.Store.commit( "SET_SELECTION_COUNT", parsed.selectedObjectsCount )
} )
window.Store = store
window.app = new Vue( {
router,
store,
render: h => h( App )
} ).$mount( '#app' )
+16
View File
@@ -0,0 +1,16 @@
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
Vue.use(Vuetify, {
theme: {
primary: '#0080FF',
secondary: '#26c2f2',
accent: '#82B1FF',
error: '#FF5252',
info: '#2196F3',
success: '#4CAF50',
warning: '#FFC107'
},
iconfont: 'md',
})
+23
View File
@@ -0,0 +1,23 @@
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
})
+224
View File
@@ -0,0 +1,224 @@
import Vue from 'vue'
import Vuex from 'vuex'
import Axios from 'axios'
Vue.use( Vuex )
export default new Vuex.Store( {
state: {
test: {},
accounts: [ ],
clients: [ ],
hostAppName: null,
currentFileName: null,
errors: [ ],
selectionCount: 0
},
mutations: {
ADD_CLIENT( state, client ) {
if ( !client.hasOwnProperty( "objects" ) ) client.objects = [ ]
state.clients.unshift( client )
},
REMOVE_CLIENT( state, _id ) {
let index = state.clients.findIndex( cl => cl._id === _id )
if ( index >= 0 )
state.clients.splice( index, 1 )
else
console.error( 'client not found', _id )
},
SET_CLIENT_DATA( state, props ) {
let found = state.clients.find( cl => cl._id === props._id )
Object.keys( props ).forEach( key => {
found[ key ] = props[ key ]
} )
},
DELETE_ALL_CLIENTS( state ) {
state.clients = [ ]
},
SET_ACCOUNTS( state, accounts ) {
state.accounts = accounts
},
SET_ACCOUNT_DATA( state, props ) {
let found = state.accounts.find( a => a.AccountId === props.AccountId )
Object.keys( props ).forEach( key => {
found[ key ] = props[ key ]
} )
},
SET_HOST_APP( state, appName ) {
state.hostAppName = appName
},
SET_SELECTION_COUNT( state, count ) {
state.selectionCount = count
}
},
actions: {
bakeReceiver: ( context, client ) => new Promise( async( resolve, reject ) => {
await UiBindings.bakeReceiver( JSON.stringify( client ) )
client.expired = false
client.loading = false
context.commit( 'SET_CLIENT_DATA', { _id: client._id, expired: false, loading: false } )
} ),
addSenderClient: ( context, { account, streamName, objects } ) => new Promise( async( resolve, reject ) => {
console.log( streamName, objects )
let res = await Axios.post( `${account.RestApi}/streams`, { name: streamName }, { headers: { Authorization: account.Token } } )
let stream = res.data.resource
console.log( stream )
let client = {...stream }
client.objects = objects
client.AccountId = account.AccountId
client.account = { RestApi: account.RestApi, Email: account.Email, Token: account.Token }
client.type = 'sender'
client.expired = true
client.loading = false
client.loadingBlurb = 'This stream might be expired.'
client.isLoadingIndeterminate = true
client.loadingProgress = 0
client.message = ''
client.errors = null
client.clientId = null
let docName = await UiBindings.getFileName( )
let docId = await UiBindings.getDocumentId( )
let clientCreationRes = await Axios.post( `${account.RestApi}/clients`, { documentType: context.state.hostAppName, streamId: stream.streamId, documentName: docName, documentGuid: docId, role: 'sender' }, { headers: { Authorization: account.Token } } )
client.clientId = clientCreationRes.data.resource._id
context.commit( 'ADD_CLIENT', client )
let dupe = {...client }
dupe.account = {...dupe.account }
delete dupe.account.Token
console.log( 'Sending this to ui bindings to add as a receiver' )
console.log( client )
await UiBindings.addSender( JSON.stringify( client ) )
return resolve( )
} ),
addReceiverClient: ( context, { account, stream } ) => new Promise( async( resolve, reject ) => {
let client = {...stream }
client.AccountId = account.AccountId
client.account = { RestApi: account.RestApi, Email: account.Email, Token: account.Token }
client.type = 'receiver'
client.expired = true
client.loading = false
client.loadingBlurb = ''
client.isLoadingIndeterminate = true
client.loadingProgress = 0
client.message = ''
client.errors = null
client.objects = [ ]
client.clientId = null
let docName = await UiBindings.getFileName( )
let docId = await UiBindings.getDocumentId( )
let res = await Axios.post( `${account.RestApi}/clients`, { documentType: context.state.hostAppName, streamId: stream.streamId, documentName: docName, documentGuid: docId, role: 'receiver' }, { headers: { Authorization: account.Token } } )
client.clientId = res.data.resource._id
context.commit( 'ADD_CLIENT', client )
let dupe = {...client }
dupe.account = {...dupe.account }
delete dupe.account.Token
await UiBindings.addReceiver( JSON.stringify( client ) )
return resolve( )
} ),
removeReceiverClient: ( context, client ) => new Promise( async( resolve, reject ) => {
await UiBindings.removeClient( JSON.stringify( client ) )
try {
await Axios.delete( `${client.account.RestApi}/clients/${client.clientId}`, { headers: { Authorization: client.account.Token } } )
// TODO: mark stream as deleted too!
} catch {}
context.commit( 'REMOVE_CLIENT', client._id )
console.log( 'hello refresh - this is important' )
} ),
updateClient: ( context, { client, expire } ) => new Promise( async( resolve, reject ) => {
// note: real update, with all the heavy object lifting, happens in .NET
let res = await Axios.get( `${client.account.RestApi}/streams/${client.streamId}?fields=name,updatedAt`, { headers: { Authorization: client.account.Token } } )
console.log( res.data.resource )
let cl = { _id: res.data.resource._id, name: res.data.resource.name, updatedAt: res.data.resource.updatedAt }
console.log( expire )
if ( expire ) cl.expired = true
context.commit( 'SET_CLIENT_DATA', cl )
} ),
flushClients: ( context ) => new Promise( async( resolve, reject ) => {
context.commit( 'DELETE_ALL_CLIENTS' )
} ),
getAccounts: ( context ) => new Promise( async( resolve, reject ) => {
let res = await UiBindings.getAccounts( )
let accounts = JSON.parse( res )
accounts.forEach( ac => {
ac.fullName = ac.Email + ' - ' + ac.ServerName
ac.streams = [ ]
ac.validated = false
context.dispatch( 'getAccountStreams', ac )
} )
context.commit( 'SET_ACCOUNTS', accounts )
} ),
getAccountStreams: ( context, account ) => new Promise( async( resolve, reject ) => {
Axios.get( `${account.RestApi}/streams?fields=streamId,name,updatedAt,parent&deleted=false&isComputedResult=false&sort=updatedAt`, { headers: { Authorization: account.Token } } )
.then( res => {
res.data.resources.forEach( s => s.fullName = `${s.streamId} - ${s.name}` )
let sorted = res.data.resources.sort( ( a, b ) => {
let ad = new Date( a.updatedAt )
let bd = new Date( b.updatedAt )
return ad > bd ? -1 : 1
} ).filter( s => s.parent === null )
context.commit( 'SET_ACCOUNT_DATA', {...account, validated: true, streams: sorted } )
resolve( res.data.resources )
} )
.catch( err => {
// console.log( err )
context.commit( 'SET_ACCOUNT_DATA', {...account, validated: false } )
reject( err )
} )
} ),
getApplicationHostName: ( context ) => new Promise( async( resolve, reject ) => {
let res = await UiBindings.getApplicationHostName( )
context.commit( 'SET_HOST_APP', res )
} ),
getExistingClients: ( context ) => new Promise( async( resolve, reject ) => {
let clients = JSON.parse( await UiBindings.getFileClients( ) )
console.log( clients )
if ( clients.length === 0 ) return resolve( )
clients.forEach( existingClient => {
try {
let account = context.state.accounts.find( ac => ac.Email === existingClient.account.Email && ac.RestApi === existingClient.account.RestApi )
if ( account !== null ) {
existingClient.account.Token = account.Token
context.commit( 'ADD_CLIENT', existingClient )
// TODO: update state on server (client: online)
} else {
console.warn( 'no account found for client. sorrrrry!', existingClient )
}
} catch {
console.warn( 'Error in recreating client ' + existingClient.streamId )
}
} )
} ),
cloneStream: ( context, client ) => new Promise( async( resolve, reject ) => {
let res = await Axios.post( `${client.account.RestApi}/streams/${client.streamId}/clone`, null, { headers: { Authorization: client.account.Token } } )
console.log( res.data )
let tempClient = { _id: client._id, children: res.data.parent.children }
context.commit( 'SET_CLIENT_DATA', tempClient )
} )
}
} )
+5
View File
@@ -0,0 +1,5 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
+13
View File
@@ -0,0 +1,13 @@
<template>
<HelloWorld />
</template>
<script>
import HelloWorld from '../components/HelloWorld'
export default {
components: {
HelloWorld
}
}
</script>
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
publicPath: ""
}