it's alive!

This commit is contained in:
Matteo Cominetti
2021-05-07 21:11:08 +01:00
parent aee33d748c
commit 8f5d678141
29 changed files with 20707 additions and 100 deletions
+48
View File
@@ -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
}
]
}
}
+19 -100
View File
@@ -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?
+13
View File
@@ -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
}
+20
View File
@@ -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
}
}
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset']
}
+20016
View File
File diff suppressed because it is too large Load Diff
+51
View File
@@ -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"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+20
View File
@@ -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>
+118
View File
@@ -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>
+54
View File
@@ -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>
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

+44
View File
@@ -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
})
}
+11
View File
@@ -0,0 +1,11 @@
<template>
<v-container></v-container>
</template>
<script>
export default {
name: 'HelloWorld',
data: () => ({})
}
</script>
+26
View File
@@ -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')
+40
View File
@@ -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'
}
})
+29
View File
@@ -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
+51
View File
@@ -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: {}
})
+5
View File
@@ -0,0 +1,5 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
+18
View File
@@ -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>
+106
View File
@@ -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)
}
}
+14
View File
@@ -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']
}