it's alive!
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/recommended",
|
||||
"prettier",
|
||||
"prettier/vue",
|
||||
"plugin:prettier/recommended",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module",
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"plugins": ["vue", "prettier"],
|
||||
"rules": {
|
||||
"arrow-spacing": [
|
||||
2,
|
||||
{
|
||||
"before": true,
|
||||
"after": true
|
||||
}
|
||||
],
|
||||
//"array-bracket-spacing": [2, "always"],
|
||||
"block-spacing": [2, "always"],
|
||||
"camelcase": [
|
||||
1,
|
||||
{
|
||||
"properties": "always"
|
||||
}
|
||||
],
|
||||
// "space-in-parens": [2, "always"],
|
||||
"keyword-spacing": 2,
|
||||
"semi": "off",
|
||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||
"space-unary-ops": [
|
||||
2,
|
||||
{
|
||||
"words": true,
|
||||
"nonwords": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,104 +1,23 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"endOfLine": "auto",
|
||||
"bracketSpacing": true,
|
||||
"eslintIntegration": true,
|
||||
"jsxBracketSameLine": true,
|
||||
"vueIndentScriptAndStyle": false,
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
const path = require('path')
|
||||
|
||||
// Load .env files
|
||||
const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env')
|
||||
const env = loadEnv([path.resolve(__dirname, '.env'), path.resolve(__dirname, '.env.local')])
|
||||
|
||||
module.exports = {
|
||||
client: {
|
||||
service: env.VUE_APP_APOLLO_ENGINE_SERVICE,
|
||||
includes: ['src/**/*.{js,jsx,ts,tsx,vue,gql}']
|
||||
},
|
||||
service: {
|
||||
name: env.VUE_APP_APOLLO_ENGINE_SERVICE,
|
||||
localSchemaFile: path.resolve(__dirname, './node_modules/.temp/graphql/schema.json')
|
||||
},
|
||||
engine: {
|
||||
endpoint: process.env.APOLLO_ENGINE_API_ENDPOINT,
|
||||
apiKey: env.VUE_APP_APOLLO_ENGINE_KEY
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/cli-plugin-babel/preset']
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "speckle-excel",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"excel": "office-addin-debugging start public/manifest.xml",
|
||||
"excel:web": "office-addin-debugging start public/manifest.xml web \"--document\" \"https://teocomi-my.sharepoint.com/:x:/g/personal/teocomi_teocomi_onmicrosoft_com/ERYfc1sKR-hMqkEKNoksYzQBBLvTSF-WH194YhxhGYp36w?e=NTATmK\"",
|
||||
"stop": "office-addin-debugging stop public/manifest.xml",
|
||||
"validate": "office-toolbox validate -m public/manifest.xml"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"office-toolbox": "^0.1.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-apollo": "^3.0.0-beta.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "^2.4.0",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "^4.5.12",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-prettier": "^3.2.0",
|
||||
"eslint-plugin-vue": "^7.2.0",
|
||||
"graphql-tag": "^2.9.0",
|
||||
"office-addin-cli": "^1.0.17",
|
||||
"office-addin-debugging": "^4.0.3",
|
||||
"office-addin-dev-certs": "^1.5.12",
|
||||
"prettier": "^2.2.1",
|
||||
"sass": "^1.32.0",
|
||||
"sass-loader": "^10.0.0",
|
||||
"vue-cli-plugin-apollo": "~0.22.2",
|
||||
"vue-cli-plugin-vuetify": "~2.4.0",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuetify-loader": "^1.7.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,20 @@
|
||||
<!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><%= htmlWebpackPlugin.options.title %></title>
|
||||
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> 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>
|
||||
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OfficeApp
|
||||
xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
|
||||
xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides"
|
||||
xsi:type="TaskPaneApp">
|
||||
<Id>884e0275-50e8-40fd-b51f-06c203c66967</Id>
|
||||
|
||||
<!--Version. Updates from the store only get triggered if there is a version change. -->
|
||||
<Version>1.0.0.0</Version>
|
||||
<ProviderName>AEC Systems Ltd</ProviderName>
|
||||
<DefaultLocale>en-US</DefaultLocale>
|
||||
|
||||
<DisplayName DefaultValue="Excel Connector" />
|
||||
<Description DefaultValue="Speckle connector for Excel"/>
|
||||
|
||||
<!-- Icon for your add-in. Used on installation screens and the add-ins dialog. -->
|
||||
<IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png" />
|
||||
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-80.png"/>
|
||||
|
||||
<SupportUrl DefaultValue="https://speckle.guide/excel" />
|
||||
|
||||
<AppDomains>
|
||||
<AppDomain>https://speckle.xyz</AppDomain>
|
||||
<AppDomain>https://localhost:3000</AppDomain>
|
||||
</AppDomains>
|
||||
|
||||
<Hosts>
|
||||
<Host Name="Workbook" />
|
||||
</Hosts>
|
||||
<DefaultSettings>
|
||||
<SourceLocation DefaultValue="https://localhost:3000/index.html" />
|
||||
</DefaultSettings>
|
||||
|
||||
<Permissions>ReadWriteDocument</Permissions>
|
||||
|
||||
<!-- Begin Add-in Commands Mode integration. -->
|
||||
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
|
||||
|
||||
<Hosts>
|
||||
<Host xsi:type="Workbook">
|
||||
<DesktopFormFactor>
|
||||
<GetStarted>
|
||||
<Title resid="GetStarted.Title"/>
|
||||
<Description resid="GetStarted.Description"/>
|
||||
<LearnMoreUrl resid="GetStarted.LearnMoreUrl"/>
|
||||
</GetStarted>
|
||||
<FunctionFile resid="Commands.Url" />
|
||||
<ExtensionPoint xsi:type="PrimaryCommandSurface">
|
||||
<OfficeTab id="TabHome">
|
||||
<Group id="CommandsGroup">
|
||||
<Label resid="CommandsGroup.Label" />
|
||||
<!-- Icons. Required sizes 16,32,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX. -->
|
||||
<!-- Use PNG icons. All URLs on the resources section must use HTTPS. -->
|
||||
<Icon>
|
||||
<bt:Image size="16" resid="Icon.16x16" />
|
||||
<bt:Image size="32" resid="Icon.32x32" />
|
||||
<bt:Image size="80" resid="Icon.80x80" />
|
||||
</Icon>
|
||||
|
||||
<!-- Control. It can be of type "Button" or "Menu". -->
|
||||
<Control xsi:type="Button" id="TaskpaneButton">
|
||||
<Label resid="TaskpaneButton.Label" />
|
||||
<Supertip>
|
||||
<!-- ToolTip title. resid must point to a ShortString resource. -->
|
||||
<Title resid="TaskpaneButton.Label" />
|
||||
<!-- ToolTip description. resid must point to a LongString resource. -->
|
||||
<Description resid="TaskpaneButton.Tooltip" />
|
||||
</Supertip>
|
||||
<Icon>
|
||||
<bt:Image size="16" resid="Icon.16x16" />
|
||||
<bt:Image size="32" resid="Icon.32x32" />
|
||||
<bt:Image size="80" resid="Icon.80x80" />
|
||||
</Icon>
|
||||
|
||||
<!-- This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFunction or ShowTaskpane. -->
|
||||
<Action xsi:type="ShowTaskpane">
|
||||
<TaskpaneId>ButtonId1</TaskpaneId>
|
||||
<!-- Provide a url resource id for the location that will be displayed on the task pane. -->
|
||||
<SourceLocation resid="Taskpane.Url" />
|
||||
</Action>
|
||||
</Control>
|
||||
</Group>
|
||||
</OfficeTab>
|
||||
</ExtensionPoint>
|
||||
</DesktopFormFactor>
|
||||
</Host>
|
||||
</Hosts>
|
||||
|
||||
<!-- You can use resources across hosts and form factors. -->
|
||||
<Resources>
|
||||
<bt:Images>
|
||||
<bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
|
||||
<bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
|
||||
<bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
|
||||
</bt:Images>
|
||||
<bt:Urls>
|
||||
<bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://speckle.guide/excel" />
|
||||
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html" />
|
||||
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html" />
|
||||
</bt:Urls>
|
||||
<!-- ShortStrings max characters==125. -->
|
||||
<bt:ShortStrings>
|
||||
<bt:String id="GetStarted.Title" DefaultValue="Get started with the Speckle connector for Excel!" />
|
||||
<bt:String id="CommandsGroup.Label" DefaultValue="Speckle" />
|
||||
<bt:String id="TaskpaneButton.Label" DefaultValue="Excel Connector" />
|
||||
</bt:ShortStrings>
|
||||
<!-- LongStrings max characters==250. -->
|
||||
<bt:LongStrings>
|
||||
<bt:String id="GetStarted.Description" DefaultValue="The Speckle connector for Excel has loaded successfully, go to the HOME tab and click the 'Excel Connector' button to get started." />
|
||||
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to Show a Taskpane" />
|
||||
</bt:LongStrings>
|
||||
</Resources>
|
||||
</VersionOverrides>
|
||||
<!-- End Add-in Commands Mode integration. -->
|
||||
|
||||
</OfficeApp>
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-app-bar app color="primary" dark>
|
||||
<div class="d-flex align-center">
|
||||
<v-img
|
||||
alt="Speckle Logo"
|
||||
class="shrink mr-2"
|
||||
contain
|
||||
:src="require(`@/assets/logo.png`)"
|
||||
transition="scale-transition"
|
||||
width="40"
|
||||
height="24"
|
||||
/>
|
||||
<h3>EXCEL CONNECTOR</h3>
|
||||
</div>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-btn v-if="!isAuthenticated" outlined @click="$store.dispatch('redirectToAuth')">
|
||||
<span>Login with Speckle</span>
|
||||
</v-btn>
|
||||
<v-btn v-else outlined @click="$store.dispatch('logout')">Log out</v-btn>
|
||||
</v-app-bar>
|
||||
|
||||
<v-main>
|
||||
<HelloWorld />
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from './components/HelloWorld'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
HelloWorld
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
//
|
||||
}),
|
||||
computed: {
|
||||
isAuthenticated() {
|
||||
return this.$store.getters.isAuthenticated
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.$route.query)
|
||||
if (this.$route.query.access_code)
|
||||
this.$store.dispatch('exchangeAccessCode', this.$route.query.access_code)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
@@ -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 |
@@ -0,0 +1,44 @@
|
||||
export const APP_NAME = process.env.VUE_APP_SPECKLE_NAME
|
||||
export const SERVER_URL = process.env.VUE_APP_SERVER_URL
|
||||
export const TOKEN = `${APP_NAME}.AuthToken`
|
||||
export const REFRESH_TOKEN = `${APP_NAME}.RefreshToken`
|
||||
export const CHALLENGE = `${APP_NAME}.Challenge`
|
||||
|
||||
export function goToSpeckleAuthPage() {
|
||||
// Generate random challenge
|
||||
var challenge =
|
||||
Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
||||
// Save challenge in localStorage
|
||||
localStorage.setItem(CHALLENGE, challenge)
|
||||
// Send user to auth page
|
||||
window.location = `${SERVER_URL}/authn/verify/${process.env.VUE_APP_SPECKLE_ID}/${challenge}`
|
||||
}
|
||||
|
||||
export function speckleLogOut() {
|
||||
localStorage.removeItem(TOKEN)
|
||||
localStorage.removeItem(REFRESH_TOKEN)
|
||||
}
|
||||
|
||||
export function exchangeAccessCode(accessCode) {
|
||||
return fetch(`${SERVER_URL}/auth/token/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
accessCode: accessCode,
|
||||
appId: process.env.VUE_APP_SPECKLE_ID,
|
||||
appSecret: process.env.VUE_APP_SPECKLE_SECRET,
|
||||
challenge: localStorage.getItem(CHALLENGE)
|
||||
})
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if (data.token) {
|
||||
localStorage.removeItem(CHALLENGE)
|
||||
localStorage.setItem(TOKEN, data.token)
|
||||
localStorage.setItem(REFRESH_TOKEN, data.refreshToken)
|
||||
}
|
||||
return data
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<v-container></v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
|
||||
data: () => ({})
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,26 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import vuetify from './plugins/vuetify'
|
||||
import { createProvider } from './vue-apollo'
|
||||
import store from './store'
|
||||
import router from './router'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
window.Office.initialize = () => {
|
||||
new Vue({
|
||||
vuetify,
|
||||
store,
|
||||
router,
|
||||
apolloProvider: createProvider(),
|
||||
render: (h) => h(App)
|
||||
}).$mount('#app')
|
||||
}
|
||||
|
||||
// new Vue({
|
||||
// vuetify,
|
||||
// store,
|
||||
// router,
|
||||
// apolloProvider: createProvider(),
|
||||
// render: (h) => h(App)
|
||||
// }).$mount('#app')
|
||||
@@ -0,0 +1,40 @@
|
||||
import Vue from 'vue'
|
||||
import Vuetify from 'vuetify/lib'
|
||||
|
||||
Vue.use(Vuetify)
|
||||
|
||||
export default new Vuetify({
|
||||
theme: {
|
||||
dark: localStorage.getItem('theme') === 'dark',
|
||||
themes: {
|
||||
light: {
|
||||
primary: '#0480FB', //speckle blue
|
||||
secondary: '#01D1FD', //spark blue
|
||||
accent: '#46B958', //data yellow
|
||||
error: '#FF5555', //red
|
||||
warning: '#D8BF16', //lightning yellow
|
||||
info: '#2D2ADA', //majestic blue
|
||||
success: '#22966C', //mantis green
|
||||
environment: '#AF02CB', //environment purple
|
||||
background: '#eeeeee',
|
||||
background2: '#ffffff',
|
||||
text: '#FFFFFF'
|
||||
},
|
||||
dark: {
|
||||
primary: '#0480FB', //speckle blue
|
||||
secondary: '#01D1FD', //spark blue
|
||||
accent: '#46B958', //data yellow
|
||||
error: '#FF5555', //red
|
||||
warning: '#D8BF16', //lightning yellow
|
||||
info: '#2D2ADA', //majestic blue
|
||||
success: '#22966C', //mantis green
|
||||
environment: '#AF02CB', //environment purple
|
||||
background: '#3a3b3c',
|
||||
background2: '#303132'
|
||||
}
|
||||
}
|
||||
},
|
||||
icons: {
|
||||
iconfont: 'mdi'
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
//import Home from '../views/Home.vue'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const 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')
|
||||
// }
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,51 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import { exchangeAccessCode, getUserData, goToSpeckleAuthPage, speckleLogOut } from '@/auth'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
user: null,
|
||||
serverInfo: null
|
||||
},
|
||||
getters: {
|
||||
isAuthenticated: (state) => state.user != null
|
||||
},
|
||||
mutations: {
|
||||
setUser(state, user) {
|
||||
state.user = user
|
||||
},
|
||||
setServerInfo(state, info) {
|
||||
state.serverInfo = info
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
logout(context) {
|
||||
// Wipe the state
|
||||
context.commit('setUser', null)
|
||||
context.commit('setServerInfo', null)
|
||||
// Wipe the tokens
|
||||
speckleLogOut()
|
||||
},
|
||||
exchangeAccessCode(context, accessCode) {
|
||||
return exchangeAccessCode(accessCode)
|
||||
},
|
||||
getUser(context) {
|
||||
return getUserData()
|
||||
.then((json) => {
|
||||
var data = json.data
|
||||
context.commit('setUser', data.user)
|
||||
context.commit('setServerInfo', data.serverInfo)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
},
|
||||
redirectToAuth() {
|
||||
goToSpeckleAuthPage()
|
||||
}
|
||||
},
|
||||
modules: {}
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<img alt="Vue logo" src="../assets/logo.png" />
|
||||
<HelloWorld msg="Welcome to Your Vue.js App" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// @ is an alias to /src
|
||||
import HelloWorld from '@/components/HelloWorld.vue'
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
components: {
|
||||
HelloWorld
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,106 @@
|
||||
import Vue from 'vue'
|
||||
import VueApollo from 'vue-apollo'
|
||||
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client'
|
||||
|
||||
// Install the vue plugin
|
||||
Vue.use(VueApollo)
|
||||
|
||||
// Name of the localStorage item
|
||||
export const APP_NAME = process.env.VUE_APP_SPECKLE_NAME
|
||||
export const AUTH_TOKEN = `${APP_NAME}.AuthToken`
|
||||
|
||||
// Http endpoint
|
||||
const httpEndpoint = process.env.VUE_APP_SERVER_URL + '/graphql'
|
||||
|
||||
// Config
|
||||
const defaultOptions = {
|
||||
// You can use `https` for secure connection (recommended in production)
|
||||
httpEndpoint,
|
||||
// You can use `wss` for secure connection (recommended in production)
|
||||
// Use `null` to disable subscriptions
|
||||
wsEndpoint: httpEndpoint.replace('http', 'ws'),
|
||||
// LocalStorage token
|
||||
tokenName: AUTH_TOKEN,
|
||||
// Enable Automatic Query persisting with Apollo Engine
|
||||
persisting: false,
|
||||
// Use websockets for everything (no HTTP)
|
||||
// You need to pass a `wsEndpoint` for this to work
|
||||
websocketsOnly: false,
|
||||
// Is being rendered on the server?
|
||||
ssr: false
|
||||
|
||||
// Override default apollo link
|
||||
// note: don't override httpLink here, specify httpLink options in the
|
||||
// httpLinkOptions property of defaultOptions.
|
||||
// link: myLink
|
||||
|
||||
// Override default cache
|
||||
// cache: myCache
|
||||
|
||||
// Override the way the Authorization header is set
|
||||
// getAuth: (tokenName) => ...
|
||||
|
||||
// Additional ApolloClient options
|
||||
// apollo: { ... }
|
||||
|
||||
// Client local data (see apollo-link-state)
|
||||
// clientState: { resolvers: { ... }, defaults: { ... } }
|
||||
}
|
||||
|
||||
// Call this in the Vue app file
|
||||
export function createProvider(options = {}) {
|
||||
// Create apollo client
|
||||
const { apolloClient, wsClient } = createApolloClient({
|
||||
...defaultOptions,
|
||||
...options
|
||||
})
|
||||
apolloClient.wsClient = wsClient
|
||||
|
||||
// Create vue apollo provider
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: apolloClient,
|
||||
defaultOptions: {
|
||||
$query: {
|
||||
// fetchPolicy: 'cache-and-network',
|
||||
}
|
||||
},
|
||||
errorHandler(error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
'%cError',
|
||||
'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;',
|
||||
error.message
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return apolloProvider
|
||||
}
|
||||
|
||||
// Manually call this when user log in
|
||||
export async function onLogin(apolloClient, token) {
|
||||
if (typeof localStorage !== 'undefined' && token) {
|
||||
localStorage.setItem(AUTH_TOKEN, token)
|
||||
}
|
||||
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
|
||||
try {
|
||||
await apolloClient.resetStore()
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('%cError on cache reset (login)', 'color: orange;', e.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Manually call this when user log out
|
||||
export async function onLogout(apolloClient) {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.removeItem(AUTH_TOKEN)
|
||||
}
|
||||
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
|
||||
try {
|
||||
await apolloClient.resetStore()
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
var devCerts = require('office-addin-dev-certs')
|
||||
var options = devCerts.getHttpsServerOptions()
|
||||
|
||||
module.exports = {
|
||||
devServer: {
|
||||
port: 3000,
|
||||
https: options,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*'
|
||||
}
|
||||
},
|
||||
|
||||
transpileDependencies: ['vuetify']
|
||||
}
|
||||