Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24137fd6c0 | |||
| 3a027dcd6d | |||
| 6ad15f6a38 | |||
| 3dad1a0849 | |||
| e6d667c951 | |||
| 226693f82d | |||
| 8caf0e5a77 | |||
| 050aab39d0 | |||
| c7d7806a30 | |||
| a9cc5ed161 | |||
| eeba4f860e | |||
| 7aa91c2d86 | |||
| e9edf0fb17 |
+9
-2
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true,
|
||||
@@ -9,12 +10,15 @@
|
||||
"prettier",
|
||||
"prettier/vue",
|
||||
"plugin:prettier/recommended",
|
||||
"eslint:recommended"
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "vue-eslint-parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module",
|
||||
"parser": "@babel/eslint-parser"
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
"plugins": ["vue", "prettier"],
|
||||
"rules": {
|
||||
@@ -25,6 +29,9 @@
|
||||
"after": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/no-array-constructor": "off",
|
||||
//"array-bracket-spacing": [2, "always"],
|
||||
"block-spacing": [2, "always"],
|
||||
"camelcase": [
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
@@ -1,63 +1,52 @@
|
||||
# Speckle Excel Connector
|
||||
<h1 align="center">
|
||||
<img src="https://user-images.githubusercontent.com/2679513/131189167-18ea5fe1-c578-47f6-9785-3748178e4312.png" width="150px"/><br/>
|
||||
Speckle | Excel
|
||||
</h1>
|
||||
|
||||
[](https://twitter.com/SpeckleSystems) [](https://discourse.speckle.works) [](https://speckle.systems) [](https://speckle.guide/dev/)
|
||||
<p align="center">
|
||||
<a href="https://speckle.community"><img src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fspeckle.community&style=flat-square&logo=discourse&logoColor=white" alt="Community forum users"></a>
|
||||
<a href="https://speckle.systems"><img src="https://img.shields.io/badge/https://-speckle.systems-royalblue?style=flat-square" alt="website"></a>
|
||||
<a href="https://docs.speckle.systems"><img src="https://img.shields.io/badge/docs-docs.speckle.systems-orange?style=flat-square&logo=read-the-docs&logoColor=white" alt="docs"></a>
|
||||
</p>
|
||||
|
||||
> Status: deprecated; not compatible with Speckle v3.
|
||||
> Retained as open source for reference and community use.
|
||||
> No active maintenance or feature updates are planned.
|
||||
|
||||
<h3 align="center">
|
||||
Speckle Connector for Excel
|
||||
</h3>
|
||||
|
||||
## Introduction
|
||||
|
||||
This repo holds Speckle's Excel Connector, it's currently released as early alpha.
|
||||
This repository contains the Speckle Excel Connector, originally released as an early alpha. It enabled sending and receiving data between Microsoft Excel and the Speckle platform. The project is no longer maintained and is not compatible with Speckle v3. For modern workflows, use current SDKs and APIs documented at docs.speckle.systems
|
||||
|
||||
## Documentation
|
||||
## Developing and debugging
|
||||
|
||||
Comprehensive developer and user documentation can be found in our:
|
||||
Note: the instructions below are preserved for archival purposes.
|
||||
|
||||
#### 📚 [Speckle Docs website](https://speckle.guide/dev/)
|
||||
### App setup
|
||||
|
||||
## Developing & Debugging
|
||||
You need a Speckle App. The server must be on https. Do not use a local server on http://localhost:3000.
|
||||
|
||||
### App Set up
|
||||
Use: https://app.speckle.systems/
|
||||
|
||||
For developing and debugging this connector you'll need to set up a Speckle App.
|
||||
The server on which the app runs must be on `https`, so **do not use a local Speckle server** on `http://localhost:3000/` as it will not work.
|
||||
In the server frontend, register a new app.
|
||||
|
||||
You can use `https://latest.speckle.dev/` or `https://speckle.xyz/`.
|
||||
Example values for an app while the Excel add-in runs on https://localhost:3000:
|
||||
|
||||
Now open up its frontend, and under your profile register a new app.
|
||||
- Name: ExcelConnector
|
||||
- Redirect URL: `https://localhost:3000`
|
||||
- Permissions: `streams:read, streams:write, profile:read, profile:email, users:read`
|
||||
|
||||
I've used the following values since my excel-connector app is running at `https://localhost:3000`:
|
||||
Then in your local `speckle-excel` repo:
|
||||
|
||||
- name: ExcelConnector
|
||||
- redirect url: `https://localhost:3000`
|
||||
- permissions: `streams:read, streams:write, profile:read, profile:email, users:read`
|
||||
- Duplicate `.env sample` to `.env.local`
|
||||
- Add your `app id` and `secret`
|
||||
- Set `BASE_URL=https://localhost:3000`
|
||||
|
||||
Take note of the `app id` and `secret`, then in your speckle-excel repo:
|
||||
### Running locally
|
||||
|
||||
- duplicate `.env sample` to `.env.local`
|
||||
- then fill it in with your new `app id` and `secret`
|
||||
- note that the `BASE_URL=https://localhost:3000`
|
||||
|
||||
### Running the connector locally
|
||||
|
||||
Run it locally:
|
||||
|
||||
- `npm install` (first time only)
|
||||
- `npm run serve`
|
||||
- _You might be prompted to install some certificates, go ahead and accept_
|
||||
- _Wait for the the process to start the Vue app, then in a separate terminal either_
|
||||
- `npm run excel` will run excel desktop and sideload the plugin
|
||||
- `npm run excel:web` will run excel web, open the document defined in `packages.json` and sideload the plugin
|
||||
|
||||
If this worked out well, you should see the connector sideloaded correctly:
|
||||
|
||||

|
||||
|
||||
## Contributing
|
||||
|
||||
Please make sure you read the [contribution guidelines](.github/CONTRIBUTING.md) for an overview of the best practices we try to follow.
|
||||
|
||||
## Community
|
||||
|
||||
The Speckle Community hangs out on [the forum](https://discourse.speckle.works), do join and introduce yourself & feel free to ask us questions!
|
||||
|
||||
## License
|
||||
|
||||
Unless otherwise described, the code in this repository is licensed under the Apache-2.0 License. Please note that some modules, extensions or code herein might be otherwise licensed. This is indicated either in the root of the containing folder under a different license file, or in the respective file's header. If you have any questions, don't hesitate to get in touch with us via [email](mailto:hello@speckle.systems).
|
||||
```bash
|
||||
npm install
|
||||
npm run serve
|
||||
Generated
+403
-81
@@ -4607,6 +4607,12 @@
|
||||
"integrity": "sha1-YcyEaYSeW83QxwRBIiZcOc7BDPQ=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/crypto-js": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz",
|
||||
"integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/express/download/@types/express-4.17.11.tgz",
|
||||
@@ -4771,6 +4777,18 @@
|
||||
"integrity": "sha1-5IbQ2XOW15vu3QpuM/RTT/a0lz4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/office-js": {
|
||||
"version": "1.0.364",
|
||||
"resolved": "https://registry.npmjs.org/@types/office-js/-/office-js-1.0.364.tgz",
|
||||
"integrity": "sha512-sEoI3Rhtyz83WjMo3GamshNU7/j8CNY/UVrSVr3n6yOTWo6eG94pZvT4f00g0bvOYlY7Wi+OTZWEqY+MtQ81MQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/office-runtime": {
|
||||
"version": "1.0.35",
|
||||
"resolved": "https://registry.npmjs.org/@types/office-runtime/-/office-runtime-1.0.35.tgz",
|
||||
"integrity": "sha512-qrP3bkDNoPY6WZMTOoutFdkZHdK91OUC1/Ohzw94bE8OD8pVoPjHKSoYaS+NlTFyXH3SNKYmQU+E6o966zARIA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/q": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npm.taobao.org/@types/q/download/@types/q-1.5.4.tgz",
|
||||
@@ -4906,6 +4924,297 @@
|
||||
"integrity": "sha1-gIyfp+RRcnTtVV+hWPLeS09GjnE=",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
|
||||
"integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "4.33.0",
|
||||
"@typescript-eslint/scope-manager": "4.33.0",
|
||||
"debug": "^4.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"ignore": "^5.1.8",
|
||||
"regexpp": "^3.1.0",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ignore": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
|
||||
"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz",
|
||||
"integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"@typescript-eslint/scope-manager": "4.33.0",
|
||||
"@typescript-eslint/types": "4.33.0",
|
||||
"@typescript-eslint/typescript-estree": "4.33.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
|
||||
"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
|
||||
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
|
||||
"integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "4.33.0",
|
||||
"@typescript-eslint/types": "4.33.0",
|
||||
"@typescript-eslint/typescript-estree": "4.33.0",
|
||||
"debug": "^4.3.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz",
|
||||
"integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.33.0",
|
||||
"@typescript-eslint/visitor-keys": "4.33.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz",
|
||||
"integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz",
|
||||
"integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.33.0",
|
||||
"@typescript-eslint/visitor-keys": "4.33.0",
|
||||
"debug": "^4.3.1",
|
||||
"globby": "^11.0.3",
|
||||
"is-glob": "^4.0.1",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true
|
||||
},
|
||||
"array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true
|
||||
},
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.4"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"globby": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.2.9",
|
||||
"ignore": "^5.2.0",
|
||||
"merge2": "^1.4.1",
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
|
||||
"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz",
|
||||
"integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.33.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-visitor-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
|
||||
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/babel-helper-vue-jsx-merge-props": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz",
|
||||
@@ -5215,6 +5524,63 @@
|
||||
"integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"ssri": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npm.taobao.org/ssri/download/ssri-8.0.1.tgz?cache=0&sync_timestamp=1617826339976&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fssri%2Fdownload%2Fssri-8.0.1.tgz",
|
||||
@@ -5223,6 +5589,28 @@
|
||||
"requires": {
|
||||
"minipass": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"vue-loader-v16": {
|
||||
"version": "npm:vue-loader@16.8.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
||||
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"loader-utils": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -18672,6 +19060,15 @@
|
||||
"integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=",
|
||||
"dev": true
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "3.21.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
|
||||
"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"tty": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npm.taobao.org/tty/download/tty-1.0.1.tgz",
|
||||
@@ -18739,6 +19136,12 @@
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.9.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.28",
|
||||
"resolved": "https://registry.npm.taobao.org/ua-parser-js/download/ua-parser-js-0.7.28.tgz?cache=0&sync_timestamp=1618065908450&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fua-parser-js%2Fdownload%2Fua-parser-js-0.7.28.tgz",
|
||||
@@ -19669,87 +20072,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-loader-v16": {
|
||||
"version": "npm:vue-loader@16.8.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
||||
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-mixpanel": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-mixpanel/-/vue-mixpanel-1.0.7.tgz",
|
||||
|
||||
+12
-2
@@ -4,9 +4,10 @@
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"compile": "tsc && prettier ./src/**/*.js --write",
|
||||
"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://skfn3-my.sharepoint.com/:x:/r/personal/connorisadmin_skfn3_onmicrosoft_com/_layouts/15/Doc.aspx?sourcedoc=%7B46999CFC-9B5A-4716-9F71-FECAEA59A6E8%7D",
|
||||
"excel:web": "office-addin-debugging start public/manifest.xml web --document https://v2k0p-my.sharepoint.com/:x:/r/personal/connor_v2k0p_onmicrosoft_com/_layouts/15/Doc.aspx?sourcedoc=%7B101920A4-0AEA-4E82-B0E5-36E3162F7E86%7D&file=signalisation-permanente.xlsx&action=default&mobileredirect=true&DefaultItemOpen=1&ct=1705007910553&wdOrigin=OFFICECOM-WEB.MAIN.REC&cid=634f97aa-c5a2-411a-a705-412dc57eaaf7&wdPreviousSessionSrc=HarmonyWeb&wdPreviousSession=96a3ad12-6cd0-44ee-bf8b-c523c706e44e",
|
||||
"excel:web2": "office-addin-debugging start public/manifest.xml web --document https://teocomi-my.sharepoint.com/:x:/g/personal/teocomi_teocomi_onmicrosoft_com/EdxKPPFhnMdDoGclr4J-xJABLf-Ao6CJ902W95kcFPL2fA?e=mD0B8a",
|
||||
"excel:prod": "office-addin-debugging start public/manifest-prod.xml",
|
||||
"excel:web-prod": "office-addin-debugging start public/manifest-prod.xml web --document https://teocomi-my.sharepoint.com/:x:/g/personal/teocomi_teocomi_onmicrosoft_com/EdxKPPFhnMdDoGclr4J-xJAB7H6-TRJ5s5ZnXzVdrdFyUg?e=VAFmBN",
|
||||
@@ -34,6 +35,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.14.3",
|
||||
"@types/crypto-js": "^4.2.1",
|
||||
"@types/office-js": "^1.0.364",
|
||||
"@types/office-runtime": "^1.0.35",
|
||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||
"@typescript-eslint/parser": "^4.33.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.13",
|
||||
"@vue/cli-plugin-eslint": "~4.5.13",
|
||||
"@vue/cli-plugin-router": "^4.5.13",
|
||||
@@ -52,6 +58,7 @@
|
||||
"prettier": "^2.2.1",
|
||||
"sass": "^1.32.0",
|
||||
"sass-loader": "^10.0.0",
|
||||
"typescript": "^4.9.5",
|
||||
"vue-cli-plugin-apollo": "~0.22.2",
|
||||
"vue-cli-plugin-vuetify": "~2.4.0",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
@@ -61,5 +68,8 @@
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.0.0 <15.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -18,6 +18,7 @@
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ user.name }}</v-list-item-title>
|
||||
<v-list-item-subtitle class="smaller-text">{{ serverUrl }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
@@ -56,7 +57,7 @@
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item href="https://speckle.systems/tag/excel/" target="_blank">
|
||||
<v-list-item href="https://v1.speckle.systems/tag/excel/" target="_blank">
|
||||
<v-list-item-icon>📺</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
@@ -94,6 +95,7 @@
|
||||
<span class="caption">CONNECTOR</span>
|
||||
</v-btn>
|
||||
</v-app-bar>
|
||||
<global-toast />
|
||||
|
||||
<v-main :style="background">
|
||||
<router-view />
|
||||
@@ -105,13 +107,15 @@
|
||||
const crypto = require('crypto')
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {},
|
||||
components: {
|
||||
GlobalToast: () => import('@/components/GlobalToast')
|
||||
},
|
||||
data: () => ({
|
||||
drawer: null,
|
||||
showSnackbar: false,
|
||||
items: [
|
||||
{
|
||||
name: 'Streams',
|
||||
name: 'Projects',
|
||||
icon: '📃',
|
||||
to: '/'
|
||||
},
|
||||
@@ -186,9 +190,6 @@ export default {
|
||||
'@' +
|
||||
crypto.createHash('md5').update(this.user.email.toLowerCase()).digest('hex').toUpperCase()
|
||||
|
||||
console.log(server_id)
|
||||
console.log(distinct_id)
|
||||
|
||||
this.$mixpanel.register({ server_id: server_id, hostApp: 'excel', type: 'action' })
|
||||
|
||||
this.$mixpanel.identify(distinct_id)
|
||||
@@ -311,4 +312,8 @@ export default {
|
||||
opacity: 1;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
|
||||
.smaller-text {
|
||||
font-size: 0.7rem; /* Example: Adjust the size as needed */
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<v-snackbar v-if="text" v-model="snack" app bottom :color="color">
|
||||
<div v-for="(line, index) in text.split('\n')" :key="index">
|
||||
{{ line }}
|
||||
</div>
|
||||
<template #action="{}">
|
||||
<v-btn v-if="actionName" small outlined @click="openUrl(url)" @click:append="snack = false">
|
||||
{{ actionName }}
|
||||
</v-btn>
|
||||
<v-btn small icon @click="snack = false">
|
||||
<v-icon small>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
snack: false,
|
||||
color: 'primary',
|
||||
text: null,
|
||||
actionName: null,
|
||||
url: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
snack(newVal) {
|
||||
if (!newVal) {
|
||||
this.text = null
|
||||
this.actionName = null
|
||||
this.url = null
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$eventHub.$on('success', (args) => {
|
||||
this.snack = true
|
||||
this.color = 'green'
|
||||
this.text = args.text
|
||||
this.actionName = args.action ? args.action.name : null
|
||||
this.url = args.action ? args.action.url : null
|
||||
})
|
||||
this.$eventHub.$on('notification', (args) => {
|
||||
this.snack = true
|
||||
this.color = 'primary'
|
||||
this.text = args.text
|
||||
this.actionName = args.action ? args.action.name : null
|
||||
this.url = args.action ? args.action.url : null
|
||||
})
|
||||
this.$eventHub.$on('error', (args) => {
|
||||
this.snack = true
|
||||
this.color = '#CC3300'
|
||||
this.text = args.text
|
||||
this.actionName = args.action ? args.action.name : null
|
||||
this.url = args.action ? args.action.url : null
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
openUrl(link) {
|
||||
this.$mixpanel.track('Connector Action', { name: 'Open In Web' })
|
||||
window.open(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<v-card class="pa-5 mb-3" style="transition: all 0.2s" @click="openStream">
|
||||
<v-card class="px-5 py-2 mb-3" style="transition: all 0.2s" @click="openStream">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="8" class="align-self-center">
|
||||
<div class="subtitle-1">
|
||||
<div class="text-h6">
|
||||
{{ stream.name }}
|
||||
</div>
|
||||
<div class="caption mb-2 mt-1 text-truncate">
|
||||
@@ -19,11 +19,7 @@
|
||||
{{ role }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-tooltip="
|
||||
stream.branches.totalCount +
|
||||
' branch' +
|
||||
(stream.branches.totalCount === 1 ? '' : 'es')
|
||||
"
|
||||
v-tooltip="`${stream.branches.totalCount === 1 ? '1 model' : 'models'}`"
|
||||
outlined
|
||||
class="ml-2"
|
||||
small
|
||||
@@ -33,9 +29,7 @@
|
||||
</v-chip>
|
||||
|
||||
<v-chip
|
||||
v-tooltip="
|
||||
stream.commits.totalCount + ' commit' + (stream.commits.totalCount === 1 ? '' : 's')
|
||||
"
|
||||
v-tooltip="`${stream.commits.totalCount === 1 ? '1 version' : 'versions'}`"
|
||||
outlined
|
||||
class="ml-2"
|
||||
small
|
||||
@@ -45,7 +39,7 @@
|
||||
</v-chip>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="4" class="text-sm-center text-md-right align-self-center">
|
||||
<v-col cols="12" sm="4" class="text-sm-center text-md-right align-self-center pt-0">
|
||||
<div>
|
||||
<span v-for="user in collaboratorsSlice" :key="user.id">
|
||||
<user-avatar
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<v-card :class="`my-1 mb-0 pa-0 pb-2 ${localExpand ? 'elevation-3' : 'elevation-0'} my-0`">
|
||||
<v-card-title>
|
||||
<v-chip @click="toggleLoadExpand">
|
||||
<v-icon small class="mr-2">mdi-code-array</v-icon>
|
||||
{{ keyName }}
|
||||
<span class="caption ml-2">List ( >{{ (value.length - 1) * 5000 }} elements)</span>
|
||||
<v-icon class="ml-2" small>
|
||||
{{ localExpand ? 'mdi-minus' : 'mdi-plus' }}
|
||||
</v-icon>
|
||||
</v-chip>
|
||||
<v-dialog v-model="progress" persistent>
|
||||
<v-card class="pt-3">
|
||||
<v-card-text class="caption">
|
||||
Receiving data from the Speckleverse...
|
||||
<v-progress-linear
|
||||
class="mt-2"
|
||||
:value="`${(numChunksReceived / value.length) * 100}`"
|
||||
color="primary"
|
||||
></v-progress-linear>
|
||||
<v-btn class="mt-3" outlined x-small color="primary" @click="cancel">Cancel</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-btn icon small @click="bake">
|
||||
<v-icon small>mdi-download</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text v-if="localExpand" class="pb-0 pr-0 pl-3">
|
||||
<component
|
||||
:is="entry.type"
|
||||
v-for="(entry, index) in rangeEntries"
|
||||
:key="index"
|
||||
:key-name="entry.key"
|
||||
:full-key-name="fullKeyName ? `${fullKeyName}.${entry.key}` : entry.key"
|
||||
:value="entry.value"
|
||||
:stream-id="streamId"
|
||||
:commit-id="commitId"
|
||||
:commit-msg="commitMsg"
|
||||
:nearest-object-id="nearestObjectId"
|
||||
:path-from-nearest-object="`${entry.pathFromNearestObject}`"
|
||||
></component>
|
||||
</v-card-text>
|
||||
<v-card-text v-if="localExpand && currentLimit < value.length">
|
||||
<v-btn small @click="loadMore">Show more</v-btn>
|
||||
</v-card-text>
|
||||
<filter-modal ref="modal" />
|
||||
</v-card>
|
||||
</template>
|
||||
<script>
|
||||
import { bake } from '../plugins/excel'
|
||||
import objectQuery from '../graphql/object.gql'
|
||||
import { createClient } from '../vue-apollo'
|
||||
|
||||
let ac = new AbortController()
|
||||
export default {
|
||||
name: 'ObjectChunkedListViewer',
|
||||
components: {
|
||||
FilterModal: () => import('./FilterModal'),
|
||||
ObjectSpeckleViewer: () => import('./ObjectSpeckleViewer'),
|
||||
ObjectSimpleViewer: () => import('./ObjectSimpleViewer'),
|
||||
ObjectValueViewer: () => import('./ObjectValueViewer')
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
keyName: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
fullKeyName: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
streamId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
commitId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
commitMsg: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
nearestObjectId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
pathFromNearestObject: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localExpand: false,
|
||||
itemsPerLoad: 3,
|
||||
currentLimit: 3,
|
||||
progress: false,
|
||||
numChunksReceived: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rangeEntries() {
|
||||
let arr = []
|
||||
let index = 0
|
||||
const delimiter = ':::'
|
||||
for (let val of this.range) {
|
||||
index++
|
||||
if (Array.isArray(val)) {
|
||||
arr.push({
|
||||
key: `${index}`,
|
||||
value: val,
|
||||
type: 'ObjectChunkedListViewer',
|
||||
pathFromNearestObject: this.pathFromNearestObject
|
||||
? this.pathFromNearestObject + (index - 1) + delimiter
|
||||
: index - 1 + delimiter
|
||||
})
|
||||
} else if (typeof val === 'object' && val !== null) {
|
||||
if (val.speckle_type && val.speckle_type === 'reference') {
|
||||
arr.push({
|
||||
key: `${index}`,
|
||||
value: val,
|
||||
type: 'ObjectSpeckleViewer'
|
||||
})
|
||||
} else {
|
||||
arr.push({
|
||||
key: `${index}`,
|
||||
value: val,
|
||||
type: 'ObjectSimpleViewer'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
arr.push({
|
||||
key: `${index}`,
|
||||
value: val,
|
||||
type: 'ObjectValueViewer'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
arr.sort((a, b) => {
|
||||
if (a.type === b.type) return 0
|
||||
if (a.type === 'ObjectValueViewer') return -1
|
||||
return 0
|
||||
})
|
||||
return arr
|
||||
},
|
||||
range() {
|
||||
return this.value.slice(0, this.currentLimit)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleLoadExpand() {
|
||||
this.localExpand = !this.localExpand
|
||||
},
|
||||
loadMore() {
|
||||
this.currentLimit += this.itemsPerLoad
|
||||
},
|
||||
cancel() {
|
||||
ac.abort()
|
||||
},
|
||||
async bake() {
|
||||
ac = new AbortController()
|
||||
|
||||
this.progress = true
|
||||
this.$mixpanel.track('Receive')
|
||||
|
||||
let allData = []
|
||||
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
if (ac.signal.aborted) {
|
||||
break
|
||||
}
|
||||
|
||||
let speckleObj = await this.getObjectFromCurrentStreamWithId(this.value[i].referencedId)
|
||||
let speckleType = speckleObj?.data?.stream?.object?.data?.speckle_type
|
||||
if (speckleType !== 'Speckle.Core.Models.DataChunk') {
|
||||
continue
|
||||
}
|
||||
|
||||
allData.push(...speckleObj.data.stream.object.data.data)
|
||||
this.numChunksReceived++
|
||||
}
|
||||
|
||||
let receiverSelection = null
|
||||
if (!ac.signal.aborted) {
|
||||
receiverSelection = await bake(
|
||||
allData,
|
||||
this.streamId,
|
||||
this.commitId,
|
||||
this.commitMsg,
|
||||
this.$refs.modal,
|
||||
ac.signal,
|
||||
this.nearestObjectId,
|
||||
this.pathFromNearestObject
|
||||
)
|
||||
}
|
||||
|
||||
if (receiverSelection) {
|
||||
receiverSelection.fullKeyName = this.fullKeyName
|
||||
|
||||
this.$store.dispatch('setReceiverSelection', {
|
||||
id: this.streamId,
|
||||
receiverSelection: receiverSelection
|
||||
})
|
||||
}
|
||||
|
||||
this.progress = false
|
||||
this.numChunksReceived = 0
|
||||
},
|
||||
async getObjectFromCurrentStreamWithId(id) {
|
||||
let client = createClient()
|
||||
return await client.query({
|
||||
query: objectQuery,
|
||||
variables: {
|
||||
streamId: this.streamId,
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -55,8 +55,7 @@ export default {
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
type: Object
|
||||
},
|
||||
streamId: {
|
||||
type: String,
|
||||
|
||||
@@ -60,6 +60,7 @@ export default {
|
||||
components: {
|
||||
FilterModal: () => import('./FilterModal'),
|
||||
ObjectListViewer: () => import('./ObjectListViewer'),
|
||||
ObjectChunkedListViewer: () => import('./ObjectChunkedListViewer'),
|
||||
ObjectSimpleViewer: () => import('./ObjectSimpleViewer'),
|
||||
ObjectValueViewer: () => import('./ObjectValueViewer')
|
||||
},
|
||||
@@ -123,8 +124,8 @@ export default {
|
||||
id: this.value.referencedId
|
||||
}
|
||||
},
|
||||
result() {
|
||||
this.objectEntries = this.getObjectEntries()
|
||||
async result() {
|
||||
this.objectEntries = await this.getObjectEntries()
|
||||
},
|
||||
skip() {
|
||||
return !this.localExpand
|
||||
@@ -145,14 +146,12 @@ export default {
|
||||
cancel() {
|
||||
ac.abort()
|
||||
},
|
||||
getObjectEntries() {
|
||||
async getObjectEntries() {
|
||||
if (!this.object) return []
|
||||
let entries = Object.entries(this.object.data)
|
||||
let arr = []
|
||||
this.updatedObjectId = this.object.data.id ?? this.nearestObjectId
|
||||
const delimiter = ':::'
|
||||
console.log(this.updatedObjectId, delimiter)
|
||||
console.log(this.nearestObjectId)
|
||||
for (let [key, val] of entries) {
|
||||
let name = key
|
||||
if (key.startsWith('__')) continue
|
||||
@@ -161,13 +160,29 @@ export default {
|
||||
if (key === 'speckle_type') name = 'speckle type'
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
arr.push({
|
||||
key,
|
||||
name,
|
||||
value: val,
|
||||
type: 'ObjectListViewer',
|
||||
pathFromNearestObject: key + delimiter
|
||||
})
|
||||
let speckleTypeOfFirstObj = null
|
||||
if (val.length > 0 && val[0].referencedId) {
|
||||
let firstObj = await this.getObjectFromCurrentStreamWithId(val[0].referencedId)
|
||||
speckleTypeOfFirstObj = firstObj?.data?.stream?.object?.data?.speckle_type
|
||||
}
|
||||
|
||||
if (speckleTypeOfFirstObj === 'Speckle.Core.Models.DataChunk') {
|
||||
arr.push({
|
||||
key,
|
||||
name,
|
||||
value: val,
|
||||
type: 'ObjectChunkedListViewer',
|
||||
pathFromNearestObject: key + delimiter
|
||||
})
|
||||
} else {
|
||||
arr.push({
|
||||
key,
|
||||
name,
|
||||
value: val,
|
||||
type: 'ObjectListViewer',
|
||||
pathFromNearestObject: key + delimiter
|
||||
})
|
||||
}
|
||||
} else if (typeof val === 'object' && val !== null) {
|
||||
if (val.speckle_type && val.speckle_type === 'reference') {
|
||||
arr.push({
|
||||
@@ -236,6 +251,16 @@ export default {
|
||||
}
|
||||
|
||||
this.progress = false
|
||||
},
|
||||
async getObjectFromCurrentStreamWithId(id) {
|
||||
let client = createClient()
|
||||
return await client.query({
|
||||
query: objectQuery,
|
||||
variables: {
|
||||
streamId: this.streamId,
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
small
|
||||
icon
|
||||
color="primary"
|
||||
:href="`${serverUrl}/streams/${stream.id}/branches/${selectedBranch.name}`"
|
||||
:href="commitViewUrl()"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon small>mdi-open-in-new</v-icon>
|
||||
@@ -313,6 +313,17 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
commitViewUrl() {
|
||||
if (this.$store.state.isFE2) {
|
||||
if (this.selectedCommit && this.selectedCommit.id) {
|
||||
return `${this.serverUrl}/projects/${this.stream.id}/models/${this.selectedBranch.id}@${this.selectedCommit.id}`
|
||||
} else {
|
||||
return `${this.serverUrl}/projects/${this.stream.id}/models/${this.selectedBranch.id}`
|
||||
}
|
||||
} else {
|
||||
return `${this.serverUrl}/streams/${this.stream.id}/branches/${this.selectedBranch.name}`
|
||||
}
|
||||
},
|
||||
swapReceiver() {
|
||||
this.isReceiver = !this.isReceiver
|
||||
this.$emit('loadByCommitId', this.selectedCommitId)
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5 mb-1">Create a New Branch</v-card-title>
|
||||
<v-card-title class="text-h5 mb-1">
|
||||
{{ `Create a New Model` }}
|
||||
</v-card-title>
|
||||
<v-card-subtitle class="py-0 my-0 font-italic">under {{ streamName }} stream</v-card-subtitle>
|
||||
<v-container class="px-6" pb-0>
|
||||
<v-text-field
|
||||
@@ -48,6 +50,7 @@
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { createClient } from '../../vue-apollo'
|
||||
// import { bus } from '@/main'
|
||||
export default {
|
||||
name: 'CreateBranchDialog',
|
||||
@@ -66,7 +69,7 @@ export default {
|
||||
showCreateBranch: false,
|
||||
branchName: '',
|
||||
description: '',
|
||||
defaultDescription: 'Stream created from SketchUp',
|
||||
defaultDescription: 'Stream created from Excel',
|
||||
accountToCreateStream: null
|
||||
}
|
||||
},
|
||||
@@ -76,6 +79,9 @@ export default {
|
||||
return this.$store.getters.isAuthenticated
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
client: createClient()
|
||||
},
|
||||
methods: {
|
||||
async createBranch() {
|
||||
let res = await this.$apollo.mutate({
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<v-container fluid class="px-1 pb-0 pt-1">
|
||||
<v-row>
|
||||
<v-col class="center-content">
|
||||
<v-row class="px-3 py-0">
|
||||
<v-col class="d-flex justify-center pb-0">
|
||||
<!-- DIALOG: Create New Stream -->
|
||||
<v-dialog v-model="showCreateNewStream">
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn class="ma-2 pa-3" x-small v-bind="attrs" v-on="on">
|
||||
<v-btn block class="pa-3" small v-bind="attrs" v-on="on">
|
||||
<v-icon dark left>mdi-plus-circle</v-icon>
|
||||
Create New Stream
|
||||
{{ `Create New Project` }}
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card>
|
||||
<v-card-title class="text-h5">Create a New Stream</v-card-title>
|
||||
<v-card-title class="text-h5">
|
||||
{{ `Create New Project` }}
|
||||
</v-card-title>
|
||||
<v-container class="px-6" pb-0>
|
||||
<v-text-field
|
||||
v-model="streamName"
|
||||
@@ -20,7 +22,7 @@
|
||||
hide-details
|
||||
dense
|
||||
flat
|
||||
placeholder="Stream Name (Optional)"
|
||||
:placeholder="`Project Name (Optional)`"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="description"
|
||||
@@ -30,7 +32,7 @@
|
||||
flat
|
||||
placeholder="Description (Optional)"
|
||||
/>
|
||||
<v-switch v-model="privateStream" :label="'Private Stream'"></v-switch>
|
||||
<v-switch v-model="privateStream" label="Private Project"></v-switch>
|
||||
</v-container>
|
||||
|
||||
<v-card-actions>
|
||||
@@ -40,19 +42,24 @@
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
</v-col>
|
||||
<v-col class="d-flex justify-center">
|
||||
<!-- DIALOG: Add a Stream by ID or URL -->
|
||||
<v-dialog v-model="showCreateStreamById">
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn class="ma-2 pa-3" x-small min-width="163" v-bind="attrs" v-on="on">
|
||||
<v-btn block class="pa-3" small min-width="163" v-bind="attrs" v-on="on">
|
||||
<v-icon dark left>mdi-link-plus</v-icon>
|
||||
Add By ID or URL
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card>
|
||||
<v-card-title class="text-h5">Add a Stream by ID or URL</v-card-title>
|
||||
<v-card-text>Stream IDs and Stream/Branch/Commit URLs are supported.</v-card-text>
|
||||
<v-card-title class="text-h5">
|
||||
{{ `Add a Project by ID or URL` }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
{{ 'Project IDs and Project/Model/Version URLs are supported.' }}
|
||||
</v-card-text>
|
||||
<v-container class="px-6">
|
||||
<v-text-field
|
||||
v-model="createStreamByIdText"
|
||||
@@ -60,7 +67,7 @@
|
||||
hide-details
|
||||
dense
|
||||
flat
|
||||
placeholder="Stream URL"
|
||||
:placeholder="'Project URL'"
|
||||
/>
|
||||
</v-container>
|
||||
<v-card-actions>
|
||||
@@ -85,6 +92,7 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { StreamWrapper } from '@/utils/streamWrapper'
|
||||
import { createClient } from '../../vue-apollo'
|
||||
|
||||
export default {
|
||||
name: 'CreateStreamDialog',
|
||||
@@ -117,14 +125,26 @@ export default {
|
||||
return this.$store.getters.isAuthenticated
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
$client: createClient()
|
||||
},
|
||||
methods: {
|
||||
async getStream() {
|
||||
try {
|
||||
const streamWrapper = new StreamWrapper(
|
||||
this.createStreamByIdText,
|
||||
this.accountId,
|
||||
this.serverUrl
|
||||
this.serverUrl,
|
||||
this.$store.state.isFE2
|
||||
)
|
||||
const match = streamWrapper.matchUrl(this.createStreamByIdText)
|
||||
if (match.groups.additionalModels !== undefined) {
|
||||
this.$eventHub.$emit('error', {
|
||||
text:
|
||||
'Multi-model URLs are not supported!\nTry to select just one single model in the web app and paste that in.'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$router.push(`/streams/${streamWrapper.streamId}/${streamWrapper.commitId}`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
@@ -150,7 +170,6 @@ export default {
|
||||
this.streamName = ''
|
||||
this.description = ''
|
||||
this.$mixpanel.track('Connector Action', { name: 'Create Stream' })
|
||||
this.refresh()
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
query Stream($id: String!) {
|
||||
query Stream($id: String!, $limit: Int!) {
|
||||
stream(id: $id) {
|
||||
id
|
||||
name
|
||||
role
|
||||
branches {
|
||||
branches (limit: $limit) {
|
||||
totalCount
|
||||
items {
|
||||
id
|
||||
|
||||
@@ -6,6 +6,8 @@ import { apolloProvider } from './vue-apollo'
|
||||
import vuetify from './plugins/vuetify'
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
|
||||
Vue.prototype.$eventHub = new Vue()
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
import VueTimeago from 'vue-timeago'
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
'use strict'
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
exports.SerializedBase = exports.ObjectReference = exports.DataChunk = exports.BaseObjectSerializer = void 0
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
const crypto_js_1 = require('crypto-js')
|
||||
/**
|
||||
* Serializer for Speckle objects written in Typescript
|
||||
*/
|
||||
class BaseObjectSerializer {
|
||||
constructor(transports) {
|
||||
this.transports = transports
|
||||
}
|
||||
async SerializeBase(object) {
|
||||
return await this.SerializeBaseWithClosures(object, [])
|
||||
}
|
||||
async SerializeBaseWithClosures(object, closures) {
|
||||
const thisClosure = new Map()
|
||||
closures.push(thisClosure)
|
||||
const converted = await this.PreserializeEachObjectProperty(object, closures)
|
||||
let json = this.SerializeMap(converted)
|
||||
const id = this.GetId(json)
|
||||
converted.set('id', id)
|
||||
this.AddSelfToParentClosures(id, closures)
|
||||
if (thisClosure.size > 0) {
|
||||
converted.set('__closure', Object.fromEntries(thisClosure))
|
||||
}
|
||||
converted.set('totalChildrenCount', thisClosure.size)
|
||||
json = this.SerializeMap(converted)
|
||||
await this.StoreObject(id, converted)
|
||||
return new SerializedBase(id, json)
|
||||
}
|
||||
async PreserializeObject(object, closures) {
|
||||
if (!(object instanceof Object) || object instanceof String) {
|
||||
return object
|
||||
}
|
||||
if (object instanceof DataChunk) {
|
||||
const serialized = await this.SerializeBaseWithClosures(object, [...closures])
|
||||
return new ObjectReference(serialized.id)
|
||||
}
|
||||
if (object instanceof Array) {
|
||||
// chunk array into 5000 by default
|
||||
const chunkSize = 5000
|
||||
if (object.length > chunkSize) {
|
||||
let serializedCount = 0
|
||||
const data = new Array()
|
||||
while (serializedCount < object.length) {
|
||||
const dataChunkCount = Math.min(chunkSize, object.length - serializedCount)
|
||||
data.push(new DataChunk(object.slice(serializedCount, serializedCount + dataChunkCount)))
|
||||
serializedCount += dataChunkCount
|
||||
}
|
||||
return await this.PreserializeObject(data, closures)
|
||||
}
|
||||
const convertedList = new Array()
|
||||
for (const element of object) {
|
||||
convertedList.push(await this.PreserializeObject(element, closures))
|
||||
}
|
||||
return convertedList
|
||||
}
|
||||
if (object instanceof Object) {
|
||||
return Object.fromEntries(await this.PreserializeEachObjectProperty(object, closures))
|
||||
}
|
||||
throw new Error(`Cannot serialize object ${object}`)
|
||||
}
|
||||
async PreserializeEachObjectProperty(o, closures) {
|
||||
const converted = new Map()
|
||||
const getters = Object.entries(Object.getOwnPropertyDescriptors(Reflect.getPrototypeOf(o)))
|
||||
.filter(([key, descriptor]) => typeof descriptor.get === 'function' && key !== '__proto__')
|
||||
.map(([key]) => key)
|
||||
const objectKeys = new Array()
|
||||
objectKeys.push(...Object.keys(o))
|
||||
objectKeys.push(...getters)
|
||||
for (const key of objectKeys) {
|
||||
const objKey = key
|
||||
converted.set(
|
||||
BaseObjectSerializer.CleanKey(key),
|
||||
await this.PreserializeObject(o[objKey], closures)
|
||||
)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
static CleanKey(originalKey) {
|
||||
const newStringChars = []
|
||||
for (let i = 0; i < originalKey.length; i++) {
|
||||
if (i == 1 && originalKey[i] == '@' && originalKey[0] == '@') {
|
||||
continue
|
||||
}
|
||||
if (this.disallowedCharacters.includes(originalKey[i])) {
|
||||
continue
|
||||
}
|
||||
newStringChars.push(originalKey[i])
|
||||
}
|
||||
return newStringChars.join('')
|
||||
}
|
||||
async StoreObject(objectId, object) {
|
||||
for (const transport of this.transports) {
|
||||
await transport.SaveObject(objectId, object)
|
||||
}
|
||||
}
|
||||
SerializeMap(map) {
|
||||
return JSON.stringify(Object.fromEntries(map))
|
||||
}
|
||||
GetId(json) {
|
||||
return (0, crypto_js_1.MD5)(json).toString(crypto_js_1.enc.Hex)
|
||||
}
|
||||
AddSelfToParentClosures(objectId, closureTables) {
|
||||
// only go to closureTable length - 1 because the last closure table belongs to the object with the
|
||||
// provided id
|
||||
const parentClosureTablesCount = closureTables.length - 1
|
||||
for (let parentLevel = 0; parentLevel < parentClosureTablesCount; parentLevel++) {
|
||||
const childDepth = parentClosureTablesCount - parentLevel
|
||||
closureTables[parentLevel].set(objectId, childDepth)
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.BaseObjectSerializer = BaseObjectSerializer
|
||||
BaseObjectSerializer.disallowedCharacters = ['.', '/']
|
||||
class DataChunk {
|
||||
constructor(data) {
|
||||
this.speckle_type = 'Speckle.Core.Models.DataChunk'
|
||||
this.data = data ?? []
|
||||
}
|
||||
}
|
||||
exports.DataChunk = DataChunk
|
||||
class ObjectReference {
|
||||
constructor(referencedId) {
|
||||
this.referencedId = referencedId
|
||||
this.speckle_type = 'reference'
|
||||
}
|
||||
}
|
||||
exports.ObjectReference = ObjectReference
|
||||
class SerializedBase {
|
||||
constructor(id, json) {
|
||||
this.id = id
|
||||
this.json = json
|
||||
}
|
||||
}
|
||||
exports.SerializedBase = SerializedBase
|
||||
@@ -0,0 +1,166 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { MD5, enc } from 'crypto-js'
|
||||
|
||||
/**
|
||||
* Serializer for Speckle objects written in Typescript
|
||||
*/
|
||||
export class BaseObjectSerializer {
|
||||
constructor(public transports: ITransport[]) {}
|
||||
|
||||
public async SerializeBase(object: object): Promise<SerializedBase> {
|
||||
return await this.SerializeBaseWithClosures(object, [])
|
||||
}
|
||||
|
||||
private async SerializeBaseWithClosures(object: object, closures: Array<Map<string, number>>) {
|
||||
const thisClosure = new Map<string, number>()
|
||||
closures.push(thisClosure)
|
||||
|
||||
const converted = await this.PreserializeEachObjectProperty(object, closures)
|
||||
let json = this.SerializeMap(converted)
|
||||
const id = this.GetId(json)
|
||||
converted.set('id', id)
|
||||
|
||||
this.AddSelfToParentClosures(id, closures)
|
||||
if (thisClosure.size > 0) {
|
||||
converted.set('__closure', Object.fromEntries(thisClosure))
|
||||
}
|
||||
converted.set('totalChildrenCount', thisClosure.size)
|
||||
|
||||
json = this.SerializeMap(converted)
|
||||
await this.StoreObject(id, converted)
|
||||
return new SerializedBase(id, json)
|
||||
}
|
||||
|
||||
private async PreserializeObject(
|
||||
object: any,
|
||||
closures: Array<Map<string, number>>
|
||||
): Promise<any> {
|
||||
if (!(object instanceof Object) || object instanceof String) {
|
||||
return object
|
||||
}
|
||||
|
||||
if (object instanceof DataChunk) {
|
||||
const serialized = await this.SerializeBaseWithClosures(object, [...closures])
|
||||
return new ObjectReference(serialized.id)
|
||||
}
|
||||
|
||||
if (object instanceof Array) {
|
||||
// chunk array into 5000 by default
|
||||
const chunkSize = 5000
|
||||
if (object.length > chunkSize) {
|
||||
let serializedCount = 0
|
||||
const data = new Array<DataChunk>()
|
||||
while (serializedCount < object.length) {
|
||||
const dataChunkCount = Math.min(chunkSize, object.length - serializedCount)
|
||||
data.push(new DataChunk(object.slice(serializedCount, serializedCount + dataChunkCount)))
|
||||
serializedCount += dataChunkCount
|
||||
}
|
||||
return await this.PreserializeObject(data, closures)
|
||||
}
|
||||
|
||||
const convertedList = new Array<any>()
|
||||
for (const element of object) {
|
||||
convertedList.push(await this.PreserializeObject(element, closures))
|
||||
}
|
||||
return convertedList
|
||||
}
|
||||
|
||||
if (object instanceof Object) {
|
||||
return Object.fromEntries(await this.PreserializeEachObjectProperty(object, closures))
|
||||
}
|
||||
|
||||
throw new Error(`Cannot serialize object ${object}`)
|
||||
}
|
||||
|
||||
private async PreserializeEachObjectProperty(
|
||||
o: object,
|
||||
closures: Array<Map<string, number>>
|
||||
): Promise<Map<string, any>> {
|
||||
const converted = new Map<string, any>()
|
||||
|
||||
const getters = Object.entries(Object.getOwnPropertyDescriptors(Reflect.getPrototypeOf(o)))
|
||||
.filter(([key, descriptor]) => typeof descriptor.get === 'function' && key !== '__proto__')
|
||||
.map(([key]) => key)
|
||||
|
||||
const objectKeys = new Array<string>()
|
||||
objectKeys.push(...Object.keys(o))
|
||||
objectKeys.push(...getters)
|
||||
|
||||
for (const key of objectKeys) {
|
||||
const objKey = key as keyof object
|
||||
converted.set(
|
||||
BaseObjectSerializer.CleanKey(key),
|
||||
await this.PreserializeObject(o[objKey], closures)
|
||||
)
|
||||
}
|
||||
|
||||
return converted
|
||||
}
|
||||
|
||||
private static disallowedCharacters: string[] = ['.', '/']
|
||||
private static CleanKey(originalKey: string): string {
|
||||
const newStringChars = []
|
||||
for (let i = 0; i < originalKey.length; i++) {
|
||||
if (i == 1 && originalKey[i] == '@' && originalKey[0] == '@') {
|
||||
continue
|
||||
}
|
||||
if (this.disallowedCharacters.includes(originalKey[i])) {
|
||||
continue
|
||||
}
|
||||
|
||||
newStringChars.push(originalKey[i])
|
||||
}
|
||||
return newStringChars.join('')
|
||||
}
|
||||
|
||||
private async StoreObject(objectId: string, object: Map<string, any>) {
|
||||
for (const transport of this.transports) {
|
||||
await transport.SaveObject(objectId, object)
|
||||
}
|
||||
}
|
||||
|
||||
private SerializeMap(map: Map<string, any>): string {
|
||||
return JSON.stringify(Object.fromEntries(map))
|
||||
}
|
||||
|
||||
private GetId(json: string): string {
|
||||
return MD5(json).toString(enc.Hex)
|
||||
}
|
||||
|
||||
private AddSelfToParentClosures(objectId: string, closureTables: Array<Map<string, number>>) {
|
||||
// only go to closureTable length - 1 because the last closure table belongs to the object with the
|
||||
// provided id
|
||||
const parentClosureTablesCount = closureTables.length - 1
|
||||
|
||||
for (let parentLevel = 0; parentLevel < parentClosureTablesCount; parentLevel++) {
|
||||
const childDepth = parentClosureTablesCount - parentLevel
|
||||
closureTables[parentLevel].set(objectId, childDepth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DataChunk implements IBase {
|
||||
public speckle_type = 'Speckle.Core.Models.DataChunk'
|
||||
public data: any[]
|
||||
constructor(data: any[] | null) {
|
||||
this.data = data ?? []
|
||||
}
|
||||
}
|
||||
|
||||
export class ObjectReference implements IBase {
|
||||
public speckle_type = 'reference'
|
||||
|
||||
constructor(public referencedId: string) {}
|
||||
}
|
||||
|
||||
export interface IBase {
|
||||
readonly speckle_type: string
|
||||
}
|
||||
|
||||
export interface ITransport {
|
||||
SaveObject(id: string, object: Map<string, any>): Promise<void>
|
||||
}
|
||||
|
||||
export class SerializedBase {
|
||||
constructor(public id: string, public json: string) {}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
'use strict'
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
exports.ExcelSheetDataRetriever = void 0
|
||||
class ExcelSheetDataRetriever {
|
||||
// Takes address as a string formatted like this 'Sheet1!A1:B4' and returns a 2d array of values.
|
||||
// This queries the document in batches in order to avoid api errors about requests that are too large
|
||||
static async GetValuesAsNestedList(context, address) {
|
||||
const sheetName = address.split('!')[0].replace(/'/g, '')
|
||||
const rangeAddress = address.split('!')[1]
|
||||
const sheet = context.workbook.worksheets.getItem(sheetName)
|
||||
const totalRange = sheet.getRange(rangeAddress)
|
||||
totalRange.load('columnCount, columnIndex, rowCount, rowIndex')
|
||||
await context.sync()
|
||||
let numRowsRetrieved = 0
|
||||
const chunkSize = 5000
|
||||
let values = []
|
||||
while (numRowsRetrieved < totalRange.rowCount) {
|
||||
const numRowsToRetrieve = Math.min(chunkSize, totalRange.rowCount - numRowsRetrieved)
|
||||
const currentRange = sheet.getRangeByIndexes(
|
||||
totalRange.rowIndex + numRowsRetrieved,
|
||||
totalRange.columnIndex,
|
||||
numRowsToRetrieve,
|
||||
totalRange.columnCount
|
||||
)
|
||||
currentRange.load('values')
|
||||
await context.sync()
|
||||
values = values.concat(currentRange.values)
|
||||
numRowsRetrieved += numRowsToRetrieve
|
||||
}
|
||||
return values
|
||||
}
|
||||
}
|
||||
exports.ExcelSheetDataRetriever = ExcelSheetDataRetriever
|
||||
@@ -0,0 +1,37 @@
|
||||
export class ExcelSheetDataRetriever {
|
||||
// Takes address as a string formatted like this 'Sheet1!A1:B4' and returns a 2d array of values.
|
||||
// This queries the document in batches in order to avoid api errors about requests that are too large
|
||||
static async GetValuesAsNestedList(
|
||||
context: Excel.RequestContext,
|
||||
address: string
|
||||
): Promise<any[][]> {
|
||||
const sheetName = address.split('!')[0].replace(/'/g, '')
|
||||
const rangeAddress = address.split('!')[1]
|
||||
const sheet = context.workbook.worksheets.getItem(sheetName)
|
||||
|
||||
const totalRange = sheet.getRange(rangeAddress)
|
||||
totalRange.load('columnCount, columnIndex, rowCount, rowIndex')
|
||||
await context.sync()
|
||||
|
||||
let numRowsRetrieved = 0
|
||||
const chunkSize = 5000
|
||||
let values: any[][] = []
|
||||
|
||||
while (numRowsRetrieved < totalRange.rowCount) {
|
||||
const numRowsToRetrieve = Math.min(chunkSize, totalRange.rowCount - numRowsRetrieved)
|
||||
const currentRange = sheet.getRangeByIndexes(
|
||||
totalRange.rowIndex + numRowsRetrieved,
|
||||
totalRange.columnIndex,
|
||||
numRowsToRetrieve,
|
||||
totalRange.columnCount
|
||||
)
|
||||
currentRange.load('values')
|
||||
await context.sync()
|
||||
values = values.concat(currentRange.values)
|
||||
|
||||
numRowsRetrieved += numRowsToRetrieve
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
'use strict'
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
exports.ServerTransport = void 0
|
||||
class ServerTransport {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor(serverUrl, token, streamId) {
|
||||
this.serverUrl = serverUrl
|
||||
this.token = token
|
||||
this.streamId = streamId
|
||||
}
|
||||
async SaveObject(id, map) {
|
||||
const query = `mutation objectCreate ($object: ObjectCreateInput!) {objectCreate(objectInput: $object)}`
|
||||
await fetch(`${this.serverUrl}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: {
|
||||
object: {
|
||||
streamId: this.streamId,
|
||||
objects: [Object.fromEntries(map)]
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
// const data = (await response.json()) as any
|
||||
}
|
||||
async CreateCommit(branchName, objectId, message) {
|
||||
const query = `mutation commitCreate($myCommit: CommitCreateInput!){ commitCreate(commit: $myCommit)}`
|
||||
await fetch(`${this.serverUrl}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: {
|
||||
myCommit: {
|
||||
streamId: this.streamId,
|
||||
branchName: branchName,
|
||||
objectId: objectId,
|
||||
message: message ? message : 'Data from Excel',
|
||||
sourceApplication: 'excel'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
// const data = (await response.json()) as any
|
||||
}
|
||||
}
|
||||
exports.ServerTransport = ServerTransport
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ITransport } from './BaseObjectSerializer'
|
||||
|
||||
export class ServerTransport implements ITransport {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor(private serverUrl: string, private token: string, private streamId: string) {}
|
||||
|
||||
async SaveObject(id: string, map: Map<string, any>): Promise<void> {
|
||||
const query = `mutation objectCreate ($object: ObjectCreateInput!) {objectCreate(objectInput: $object)}`
|
||||
|
||||
await fetch(`${this.serverUrl}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: {
|
||||
object: {
|
||||
streamId: this.streamId,
|
||||
objects: [Object.fromEntries(map)]
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// const data = (await response.json()) as any
|
||||
}
|
||||
|
||||
async CreateCommit(branchName: string, objectId: string, message: string | null) {
|
||||
const query = `mutation commitCreate($myCommit: CommitCreateInput!){ commitCreate(commit: $myCommit)}`
|
||||
|
||||
await fetch(`${this.serverUrl}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: {
|
||||
myCommit: {
|
||||
streamId: this.streamId,
|
||||
branchName: branchName,
|
||||
objectId: objectId,
|
||||
message: message ? message : 'Data from Excel',
|
||||
sourceApplication: 'excel'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// const data = (await response.json()) as any
|
||||
}
|
||||
}
|
||||
+10
-9
@@ -11,6 +11,7 @@ import {
|
||||
onTableChanged,
|
||||
onTableDeleted
|
||||
} from './dataTable.js'
|
||||
import { ExcelSheetDataRetriever } from './ExcelSheetDataRetreiver.js'
|
||||
|
||||
const unflatten = require('flat').unflatten
|
||||
|
||||
@@ -214,7 +215,7 @@ export function hideRowOrColumn(sheet, columnIndex = -1, rowIndex = -1) {
|
||||
}
|
||||
}
|
||||
|
||||
async function addIdDataToObjectData() {
|
||||
async function addIdDataToObjectData(arrayData) {
|
||||
if (
|
||||
arrayData.length != arrayIdData.length ||
|
||||
arrayData.length <= 1 ||
|
||||
@@ -599,14 +600,13 @@ export async function bake(
|
||||
} else if (previousHeaders) {
|
||||
selectedHeaders = filterArrayData(previousHeaders, arrayData)
|
||||
}
|
||||
|
||||
console.log(arrayData)
|
||||
}
|
||||
|
||||
if (signal.aborted) return
|
||||
|
||||
await addIdDataToObjectData()
|
||||
await bakeArray(arrayData, rowStart, colStart, context)
|
||||
selectedHeaders ??= arrayData
|
||||
await addIdDataToObjectData(selectedHeaders)
|
||||
await bakeArray(selectedHeaders, rowStart, colStart, context)
|
||||
}
|
||||
|
||||
await context.sync()
|
||||
@@ -668,11 +668,12 @@ export async function send(savedStream, streamId, branchName, message) {
|
||||
let sheetName = savedStream.selection.split('!')[0].replace(/'/g, '')
|
||||
let rangeAddress = savedStream.selection.split('!')[1]
|
||||
let sheet = context.workbook.worksheets.getItem(sheetName)
|
||||
|
||||
let range = sheet.getRange(rangeAddress)
|
||||
range.load('values')
|
||||
await context.sync()
|
||||
let values = range.values
|
||||
|
||||
let values = await ExcelSheetDataRetriever.GetValuesAsNestedList(
|
||||
context,
|
||||
savedStream.selection
|
||||
)
|
||||
|
||||
let data = []
|
||||
// check for specific conversion
|
||||
|
||||
+58
-42
@@ -6,6 +6,8 @@ import ObjectLoader from '@speckle/objectloader'
|
||||
import streamsModule from './streams'
|
||||
import userModule from './user'
|
||||
import router from '../router'
|
||||
import { BaseObjectSerializer } from '../plugins/BaseObjectSerializer'
|
||||
import { ServerTransport } from '../plugins/ServerTransport'
|
||||
|
||||
const xml2js = require('xml2js')
|
||||
|
||||
@@ -100,7 +102,8 @@ const vuexExcel = new VuexPersistence({
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
snackbar: {}
|
||||
snackbar: {},
|
||||
isFE2: false
|
||||
},
|
||||
plugins: [vuexLocal.plugin, vuexExcel.plugin],
|
||||
getters: {
|
||||
@@ -109,9 +112,16 @@ export default new Vuex.Store({
|
||||
mutations: {
|
||||
SET_SNACKBAR(state, value) {
|
||||
state.snackbar = value
|
||||
},
|
||||
UPDATE_IS_FE2(state, value) {
|
||||
localStorage.setItem('frontend2', value)
|
||||
state.isFE2 = value
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
updateIsFE2({ commit }, value) {
|
||||
commit('UPDATE_IS_FE2', value)
|
||||
},
|
||||
async redirect(_, data) {
|
||||
//go to login and refresh token
|
||||
window.location = `${data.serverUrl}/authn/verify/${process.env.VUE_APP_SPECKLE_ID}/${data.challenge}`
|
||||
@@ -140,11 +150,13 @@ export default new Vuex.Store({
|
||||
dialog.close()
|
||||
await dispatch('exchangeAccessCode', args.message)
|
||||
await dispatch('hasValidToken')
|
||||
await dispatch('getServerInfo')
|
||||
router.push('/')
|
||||
})
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
async hasValidToken({ state, dispatch }) {
|
||||
if (localStorage.getItem(TOKEN) === null) return false
|
||||
await dispatch('getUser')
|
||||
@@ -161,6 +173,7 @@ export default new Vuex.Store({
|
||||
localStorage.removeItem('serverUrl')
|
||||
localStorage.removeItem(REFRESH_TOKEN)
|
||||
localStorage.removeItem('uuid')
|
||||
localStorage.removeItem('frontend2')
|
||||
|
||||
window.location = window.location.origin
|
||||
},
|
||||
@@ -193,51 +206,14 @@ export default new Vuex.Store({
|
||||
}
|
||||
},
|
||||
async createCommit(context, { streamId, branchName, message, object }) {
|
||||
let query = `mutation objectCreate ($object: ObjectCreateInput!) {objectCreate(objectInput: $object)}`
|
||||
|
||||
let serverUrl = localStorage.getItem('serverUrl')
|
||||
let token = localStorage.getItem(TOKEN)
|
||||
|
||||
let response = await fetch(`${serverUrl}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: {
|
||||
object: {
|
||||
streamId: streamId,
|
||||
objects: [object]
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
let data = await response.json()
|
||||
let objectId = data.data.objectCreate[0]
|
||||
const serverTransport = new ServerTransport(serverUrl, token, streamId)
|
||||
const serializer = new BaseObjectSerializer([serverTransport])
|
||||
const serialized = await serializer.SerializeBase(object)
|
||||
|
||||
query = `mutation commitCreate($myCommit: CommitCreateInput!){ commitCreate(commit: $myCommit)}`
|
||||
|
||||
response = await fetch(`${serverUrl}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: {
|
||||
myCommit: {
|
||||
streamId: streamId,
|
||||
branchName: branchName,
|
||||
objectId: objectId,
|
||||
message: message ? message : 'Data from Excel',
|
||||
sourceApplication: 'excel'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
await serverTransport.CreateCommit(branchName, serialized.id, message)
|
||||
},
|
||||
async receiveCommit(context, { sourceApplication, streamId, commitId, message }) {
|
||||
let query = `mutation objectReceive ($myInput:CommitReceivedInput!) {commitReceive(input:$myInput)}`
|
||||
@@ -264,6 +240,46 @@ export default new Vuex.Store({
|
||||
})
|
||||
})
|
||||
},
|
||||
async getServerInfo({ dispatch }) {
|
||||
let serverUrl = localStorage.getItem('serverUrl')
|
||||
|
||||
// Now, to check for a specific header
|
||||
const isFrontend2Server = (headers) => {
|
||||
const HEADER = 'x-speckle-frontend-2'
|
||||
const headerValue = headers.get(HEADER)
|
||||
|
||||
if (headerValue === null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const value = headerValue.toLowerCase() === 'true'
|
||||
if (headerValue !== 'true' && headerValue !== 'false') {
|
||||
throw new Error(
|
||||
`Headers contained ${HEADER} header, but value ${headerValue} could not be parsed to a bool`
|
||||
)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// Use the function to check the header
|
||||
try {
|
||||
let response = await fetch(serverUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
let isFE2Server = isFrontend2Server(response.headers)
|
||||
await dispatch('updateIsFE2', isFE2Server)
|
||||
console.log('Is Frontend2 Server:', isFE2Server)
|
||||
} catch (error) {
|
||||
console.warn(error.message)
|
||||
// TODO: fallback is FE1, this should be changed later
|
||||
await dispatch('updateIsFE2', false)
|
||||
}
|
||||
},
|
||||
async getUser(context) {
|
||||
try {
|
||||
let query = `query {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
require('url')
|
||||
|
||||
export class StreamWrapper {
|
||||
constructor(streamIdOrUrl, accountId, serverUrl) {
|
||||
constructor(streamIdOrUrl, accountId, serverUrl, isFE2) {
|
||||
this.isFE2 = isFE2
|
||||
this.streamsKey = this.isFE2 ? 'projects/' : 'streams/'
|
||||
this.branchesKey = this.isFE2 ? 'models/' : 'branches/'
|
||||
this.commitsKey = this.isFE2 ? 'versions/' : 'commits/'
|
||||
this.originalOutput = streamIdOrUrl
|
||||
try {
|
||||
this.streamWrapperFromUrl(streamIdOrUrl)
|
||||
@@ -12,12 +16,17 @@ export class StreamWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
matchUrl(streamUrl) {
|
||||
const fe2UrlRegex = /\/projects\/(?<projectId>[\w\d]+)(?:\/models\/(?<model>[\w\d]+(?:@[\w\d]+)?)(?:,(?<additionalModels>[\w\d]+(?:@[\w\d]+)?))*)?/
|
||||
return fe2UrlRegex.exec(streamUrl)
|
||||
}
|
||||
|
||||
streamWrapperFromUrl(streamUrl) {
|
||||
this.url = new URL(streamUrl)
|
||||
this.segments = this.url.pathname.split('/').map((segment) => segment + '/')
|
||||
this.serverUrl = this.url.origin
|
||||
|
||||
if (this.segments.length >= 4 && this.segments[3]?.toLowerCase() === 'branches/') {
|
||||
if (this.segments.length >= 4 && this.segments[3]?.toLowerCase() === this.branchesKey) {
|
||||
this.streamId = this.segments[2].replace('/', '')
|
||||
if (this.segments.length > 5) {
|
||||
let branchSegments = this.segments.slice(4, this.segments.length - 1)
|
||||
@@ -28,7 +37,7 @@ export class StreamWrapper {
|
||||
} else {
|
||||
switch (this.segments.length) {
|
||||
case 3: // ie http://speckle.server/streams/8fecc9aa6d
|
||||
if (this.segments[1].toLowerCase() === 'streams/')
|
||||
if (this.segments[1].toLowerCase() === this.streamsKey)
|
||||
this.streamId = this.segments[2].replace('/', '')
|
||||
else throw new Error(`Cannot parse ${this.originalOutput} into a stream wrapper class`)
|
||||
break
|
||||
@@ -40,7 +49,7 @@ export class StreamWrapper {
|
||||
break
|
||||
case 5: // ie http://speckle.server/streams/8fecc9aa6d/commits/76a23d7179
|
||||
switch (this.segments[3].toLowerCase()) {
|
||||
case 'commits/':
|
||||
case this.commitsKey:
|
||||
this.streamId = this.segments[2].replace('/', '')
|
||||
this.commitId = this.segments[4].replace('/', '')
|
||||
break
|
||||
@@ -49,7 +58,7 @@ export class StreamWrapper {
|
||||
this.branchName = this.segments[3].replace('/', '')
|
||||
this.commitId = this.segments[4].replace('/', '')
|
||||
break
|
||||
case 'branches/':
|
||||
case this.branchesKey:
|
||||
this.streamId = this.segments[2].replace('/', '')
|
||||
this.branchName = this.segments[4].replace('/', '')
|
||||
break
|
||||
|
||||
+3
-3
@@ -43,7 +43,9 @@ export default {
|
||||
name: 'Login',
|
||||
data: () => ({
|
||||
serverUrl:
|
||||
process.env.NODE_ENV === 'development' ? 'https://latest.speckle.dev' : 'https://speckle.xyz',
|
||||
process.env.NODE_ENV === 'development'
|
||||
? 'https://latest.speckle.systems'
|
||||
: 'https://app.speckle.systems',
|
||||
validForm: true,
|
||||
serverError: '',
|
||||
serverUrlRules: [
|
||||
@@ -53,8 +55,6 @@ export default {
|
||||
'URL must be valid, with no trailing slash'
|
||||
]
|
||||
}),
|
||||
mounted() {},
|
||||
|
||||
methods: {
|
||||
async login() {
|
||||
//when for is not visible (coming from web) don't validate
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
small
|
||||
icon
|
||||
color="primary"
|
||||
:href="`${serverUrl}/streams/${savedStream.id}`"
|
||||
:href="`${serverUrl}/${$store.state.isFE2 ? 'projects' : 'streams'}/${savedStream.id}`"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon small>mdi-open-in-new</v-icon>
|
||||
@@ -127,13 +127,15 @@ export default {
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
$client: createClient(),
|
||||
stream: {
|
||||
prefetch: true,
|
||||
query: streamQuery,
|
||||
fetchPolicy: 'network-only',
|
||||
variables() {
|
||||
return {
|
||||
id: this.streamId
|
||||
id: this.streamId,
|
||||
limit: 100
|
||||
}
|
||||
},
|
||||
result() {
|
||||
@@ -178,7 +180,6 @@ export default {
|
||||
console.log(this.error)
|
||||
}
|
||||
},
|
||||
$client: createClient(),
|
||||
$subscribe: {
|
||||
streamUpdated: {
|
||||
query: gql`
|
||||
@@ -423,7 +424,7 @@ export default {
|
||||
speckleIdRange.load('text')
|
||||
await context.sync()
|
||||
|
||||
let idsInViewer = new Array()
|
||||
let idsInViewer = []
|
||||
for (let i = 0; i < speckleIdRange.text?.length; i++) {
|
||||
for (let j = 0; j < speckleIdRange.text[i].length; j++) {
|
||||
if (speckleIdRange.text[i][j].length < 32) continue
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-container class="pa-0">
|
||||
<v-row align="center">
|
||||
<v-col cols="12" align="center" class="mt-5">
|
||||
<v-col cols="12" align="center" class="mt-3">
|
||||
<p v-if="search" class="subtitle">No streams found 🧐</p>
|
||||
<div v-else-if="!$apollo.loading && filteredStreams && filteredStreams.length == 0">
|
||||
<p class="subtitle">
|
||||
@@ -122,7 +122,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
isAuthenticated() {
|
||||
console.log(this.user)
|
||||
return this.$store.getters.isAuthenticated
|
||||
},
|
||||
user() {
|
||||
@@ -132,7 +131,6 @@ export default {
|
||||
return this.$store.getters.serverUrl
|
||||
},
|
||||
filteredStreams() {
|
||||
console.log('user', this.$store.state.user.user)
|
||||
if (!this.streams.items) return null
|
||||
|
||||
let savedStreams = this.streams.items.filter(
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */,
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user