Release catalyst
3
ui/.browserslistrc
Normal file
@@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
30
ui/.eslintrc.js
Normal file
@@ -0,0 +1,30 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended",
|
||||
"@vue/typescript/recommended",
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
rules: {
|
||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
'vue/valid-v-slot': ['error', {
|
||||
allowModifiers: true,
|
||||
}],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["**/__tests__/*.{j,t}s?(x)", "**/tests/unit/**/*.spec.{j,t}s?(x)"],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
ignorePatterns: ["src/suggestions/grammar/*.js", "src/views/playbook/vue-blocks/"],
|
||||
};
|
||||
27
ui/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
## Project setup
|
||||
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
|
||||
```
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
5
ui/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
3
ui/jest.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
preset: "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
|
||||
};
|
||||
82
ui/package.json
Normal file
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "catalyst",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test": "vue-cli-service test:unit",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@koumoul/vjsf": "2.0.3",
|
||||
"@mdi/font": "5.9.55",
|
||||
"@mdi/util": "^0.3.2",
|
||||
"@types/luxon": "^1.27.0",
|
||||
"@types/prismjs": "^1.16.5",
|
||||
"@uppy/core": "^1.18.0",
|
||||
"@uppy/tus": "^1.8.7",
|
||||
"@uppy/vue": "^0.2.1",
|
||||
"ajv": "^8.6.3",
|
||||
"ant-design-vue": "^1.7.8",
|
||||
"antlr4": "^4.9.2",
|
||||
"axios": "^0.21.1",
|
||||
"chart.js": "2",
|
||||
"core-js": "^3.15.2",
|
||||
"graphlib": "^2.1.8",
|
||||
"json-schema-editor-vue": "^1.2.5",
|
||||
"just-kebab-case": "^1.1.0",
|
||||
"less": "3.0.4",
|
||||
"less-loader": "5.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^1.27.0",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"swagger-ui": "^3.50.0",
|
||||
"vue": "2.6.14",
|
||||
"vue-axios": "^3.2.4",
|
||||
"vue-chartjs": "^3.5.1",
|
||||
"vue-class-component": "^7.2.6",
|
||||
"vue-cropperjs": "^4.2.0",
|
||||
"vue-d3-network": "^0.1.28",
|
||||
"vue-lodash": "^2.1.2",
|
||||
"vue-luxon": "^0.10.0",
|
||||
"vue-markdown": "^2.2.4",
|
||||
"vue-native-websocket": "^2.0.14",
|
||||
"vue-pipeline": "^1.0.12",
|
||||
"vue-prism-editor": "^1.2.2",
|
||||
"vue-property-decorator": "^9.1.2",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "2.4.6",
|
||||
"vuex": "^3.6.2",
|
||||
"yaml": "^1.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/vue": "^5.6.2",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/vue-markdown": "^2.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.1",
|
||||
"@typescript-eslint/parser": "^4.22.1",
|
||||
"@vue/cli-plugin-babel": "^4.5.12",
|
||||
"@vue/cli-plugin-eslint": "^4.5.12",
|
||||
"@vue/cli-plugin-pwa": "^4.5.12",
|
||||
"@vue/cli-plugin-router": "^4.5.12",
|
||||
"@vue/cli-plugin-typescript": "^4.5.12",
|
||||
"@vue/cli-plugin-unit-jest": "^4.5.12",
|
||||
"@vue/cli-plugin-vuex": "^4.5.12",
|
||||
"@vue/cli-service": "^4.5.12",
|
||||
"@vue/compiler-sfc": "^3.1.2",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"@vue/test-utils": "^1.2.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint-plugin-jest": "^24.3.6",
|
||||
"eslint-plugin-vue": "^7.9.0",
|
||||
"sass": "1.32.12",
|
||||
"sass-loader": "^10",
|
||||
"typescript": "^4.2.4",
|
||||
"vue-cli-plugin-vuetify": "~2.3.1",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuetify-loader": "1.7.2"
|
||||
}
|
||||
}
|
||||
BIN
ui/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 32 KiB |
125
ui/public/flask.svg
Normal file
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4f, 2020-05-01)"
|
||||
sodipodi:docname="flask.svg"
|
||||
id="svg867"
|
||||
xml:space="preserve"
|
||||
viewBox="0 0 85.36 85.36"
|
||||
version="1.1"
|
||||
fill="#333333"
|
||||
enable-background="new 0 0 100 100"
|
||||
height="256.08"
|
||||
width="256.08"><defs
|
||||
id="defs871" /><sodipodi:namedview
|
||||
inkscape:current-layer="svg867"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="69"
|
||||
inkscape:window-x="3192"
|
||||
inkscape:cy="140.74801"
|
||||
inkscape:cx="128.03999"
|
||||
inkscape:zoom="3.1476184"
|
||||
showgrid="false"
|
||||
id="namedview869"
|
||||
inkscape:window-height="1003"
|
||||
inkscape:window-width="1615"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<metadata
|
||||
id="metadata833">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
id="path835"
|
||||
d="m27.345-37.335-17.33-30.02v-10.079h0.772c2.118 0 3.842-1.724 3.842-3.842 0-2.119-1.724-3.843-3.842-3.843h-15.182c-2.119 0-3.842 1.724-3.842 3.843s1.724 3.842 3.842 3.842h0.927v9.811l-17.487 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.902 3.827 6.626 3.827h35.048c2.726 0 5.265-1.467 6.625-3.827 1.365-2.359 1.365-5.292 1e-3 -7.651zm-31.74-42.656c-0.708 0-1.285-0.576-1.285-1.285s0.576-1.285 1.285-1.285h15.183c0.708 0 1.283 0.577 1.283 1.285s-0.575 1.285-1.283 1.285h-2.052c-0.706 0-1.279 0.573-1.279 1.279v11.7c0 0.225 0.06 0.445 0.172 0.639l10.577 18.324c-0.034 5e-3 -0.069 3e-3 -0.104 9e-3 -0.345 0.055-0.651 0.102-0.889 0.102-0.916 0-1.835-0.238-2.731-0.708-0.43-0.228-0.889-0.335-1.344-0.335-0.969 0-1.91 0.488-2.456 1.361-1.131 1.813-3.039 2.894-5.104 2.894-2.854 0-5.286-2.003-5.914-4.87-0.203-0.932-0.851-1.702-1.732-2.061-0.351-0.145-0.723-0.215-1.092-0.215-0.554 0-1.107 0.16-1.584 0.474-0.987 0.646-2.112 0.987-3.25 0.987-0.517 0-1.074-0.097-1.753-0.307-0.155-0.049-0.311-0.081-0.467-0.103l2.373-4.109h11.535c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-10.058l1.872-3.241h7.688c0.707 0 1.279-0.573 1.279-1.279s-0.572-1.279-1.279-1.279h-6.21l1.808-3.13c0.026-0.036 0.051-0.074 0.076-0.112h4.825c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.606v-3.242h4.604c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.604v-3.824c0-0.706-0.573-1.279-1.279-1.279h-2.205z" />
|
||||
<path
|
||||
id="path837"
|
||||
d="m-4.538-97.293c3.839 0 6.962-3.123 6.962-6.962s-3.124-6.962-6.962-6.962-6.962 3.123-6.962 6.962 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404s-1.976 4.404-4.405 4.404-4.405-1.976-4.405-4.404 1.977-4.404 4.405-4.404z" />
|
||||
<path
|
||||
id="path839"
|
||||
d="m1.003-91.752c0 2.272 1.849 4.121 4.121 4.121s4.121-1.849 4.121-4.121-1.849-4.121-4.121-4.121-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z" />
|
||||
<path
|
||||
id="path841"
|
||||
stroke-width=".8631"
|
||||
fill="#fc0"
|
||||
d="m24.048-38.2-5.3303-9.2335c-3.1435-7.7748-21.883-13.817-29.584-2.4987l-6.7736 11.732c-1.1756 2.0369-1.1756 4.5667 0 6.6036 1.1764 2.0369 3.3678 3.3031 5.7189 3.3031h30.25c2.3528 0 4.5442-1.2662 5.7181-3.3031 1.1781-2.0361 1.1781-4.5676 8.63e-4 -6.6036z" />
|
||||
<path
|
||||
id="path843"
|
||||
fill="#ffc107"
|
||||
d="m143.85-25.061c-0.554 0-1.107 0.16061-1.584 0.47461-0.987 0.646-2.112 0.98698-3.25 0.98698-0.517 0-1.0743-0.09729-1.7533-0.30729-0.39216 0.03998-0.72173 0.07672-1.1191 0.78581l-6.7734 11.732c-1.1756 2.0369-1.1756 4.5666 0 6.6035 1.1764 2.0369 3.3676 3.3027 5.7188 3.3027h30.25c2.3528 0 4.5443-1.2658 5.7181-3.3027 1.1781-2.0361 1.1786-4.5675 1e-3 -6.6035l-5.3307-9.2337c-0.45242-0.78245-0.70174-0.56556-1.5046-0.50452-0.916 0-1.8351-0.23768-2.7311-0.70768-0.43-0.228-0.88941-0.33529-1.3444-0.33529-0.969 0-1.9097 0.48833-2.4557 1.3613-1.131 1.813-3.0392 2.8939-5.1042 2.8939-2.854 0-5.2861-2.0034-5.9141-4.8704-0.203-0.932-0.85077-1.7015-1.7318-2.0605-0.351-0.145-0.7228-0.21549-1.0918-0.21549z" />
|
||||
<path
|
||||
id="path845"
|
||||
fill="#ffc107"
|
||||
d="m94.563-31.292-17.33-30.02v-10.079h0.772c2.118 0 3.842-1.724 3.842-3.842 0-2.119-1.724-3.843-3.842-3.843h-15.182c-2.119 0-3.842 1.724-3.842 3.843s1.724 3.842 3.842 3.842h0.927v9.811l-17.487 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.902 3.827 6.626 3.827h35.048c2.726 0 5.265-1.467 6.625-3.827 1.365-2.359 1.365-5.292 1e-3 -7.651zm-31.74-42.656c-0.708 0-1.285-0.576-1.285-1.285s0.576-1.285 1.285-1.285h15.183c0.708 0 1.283 0.577 1.283 1.285s-0.575 1.285-1.283 1.285h-2.052c-0.706 0-1.279 0.573-1.279 1.279v11.7c0 0.225 0.06 0.445 0.172 0.639l10.577 18.324c-0.034 5e-3 -0.069 3e-3 -0.104 9e-3 -0.345 0.055-0.651 0.102-0.889 0.102-0.916 0-1.835-0.238-2.731-0.708-0.43-0.228-0.889-0.335-1.344-0.335-0.969 0-1.91 0.488-2.456 1.361-1.131 1.813-3.039 2.894-5.104 2.894-2.854 0-5.286-2.003-5.914-4.87-0.203-0.932-0.851-1.702-1.732-2.061-0.351-0.145-0.723-0.215-1.092-0.215-0.554 0-1.107 0.16-1.584 0.474-0.987 0.646-2.112 0.987-3.25 0.987-0.517 0-1.074-0.097-1.753-0.307-0.155-0.049-0.311-0.081-0.467-0.103l2.373-4.109h11.535c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-10.058l1.872-3.241h7.688c0.707 0 1.279-0.573 1.279-1.279s-0.572-1.279-1.279-1.279h-6.21l1.808-3.13c0.026-0.036 0.051-0.074 0.076-0.112h4.825c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.606v-3.242h4.604c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.604v-3.824c0-0.706-0.573-1.279-1.279-1.279h-2.205z" />
|
||||
<path
|
||||
id="path847"
|
||||
d="m62.68-91.25c3.839 0 6.962-3.123 6.962-6.962 0-3.839-3.124-6.962-6.962-6.962s-6.962 3.123-6.962 6.962c0 3.839 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404 0 2.428-1.976 4.404-4.405 4.404s-4.405-1.976-4.405-4.404c0-2.428 1.977-4.404 4.405-4.404z" />
|
||||
<path
|
||||
id="path849"
|
||||
d="m68.221-85.709c0 2.272 1.849 4.121 4.121 4.121 2.272 0 4.121-1.849 4.121-4.121s-1.849-4.121-4.121-4.121c-2.272 0-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z" />
|
||||
<path
|
||||
id="path851"
|
||||
d="m62.824-79.076c-2.119 0-3.8424 1.7241-3.8424 3.8431s1.7244 3.8418 3.8424 3.8418h0.92709v9.8112l-17.488 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.9023 3.8268 6.6263 3.8268h35.048c2.726 0 5.265-1.4668 6.625-3.8268 1.365-2.359 1.3647-5.292 6.7e-4 -7.651l-17.33-30.02v-10.079h0.77213c2.118 0 3.8418-1.7238 3.8418-3.8418 0-2.119-1.7238-3.8431-3.8418-3.8431zm0 2.5579h15.183c0.708 0 1.2826 0.57716 1.2826 1.2852s-0.57455 1.2852-1.2826 1.2852h-2.0521c-0.706 0-1.2793 0.57265-1.2793 1.2786v11.7c0 0.225 0.0599 0.44533 0.17188 0.63933 5.4876 9.5256 10.979 18.748 16.42 28.173 1.1773 2.0361 1.1768 4.5675-1e-3 6.6035-1.1738 2.0369-3.3653 3.3027-5.7181 3.3027h-30.25c-2.3511 0-4.5423-1.2658-5.7188-3.3027-1.1756-2.0369-1.1756-4.5666 0-6.6035 3.1075-5.7233 6.5841-11.164 9.7988-16.73h11.534c0.706 0 1.2793-0.57265 1.2793-1.2786s-0.5733-1.2793-1.2793-1.2793h-10.058l1.8724-3.2409h7.6875c0.707 0 1.2793-0.57265 1.2793-1.2786s-0.57229-1.2793-1.2793-1.2793h-6.2096l1.8079-3.1302c0.026-0.036 0.0512-0.07398 0.0762-0.11198h4.8249c0.706 0 1.2786-0.57265 1.2786-1.2786s-0.57264-1.2793-1.2786-1.2793h-4.6061v-3.2422h4.6042c0.706 0 1.2786-0.57265 1.2786-1.2786 0-0.706-0.57265-1.2793-1.2786-1.2793h-4.6042v-3.8236c0-0.706-0.57265-1.2793-1.2786-1.2793h-2.2051v-6.33e-4c-0.708 0-1.2852-0.57616-1.2852-1.2852s0.57615-1.2852 1.2852-1.2852z" />
|
||||
<path
|
||||
id="path853"
|
||||
d="m142.31-70.382c3.839 0 6.962-3.123 6.962-6.962s-3.124-6.962-6.962-6.962-6.962 3.123-6.962 6.962 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404s-1.976 4.404-4.405 4.404-4.405-1.976-4.405-4.404 1.977-4.404 4.405-4.404z" />
|
||||
<path
|
||||
id="path855"
|
||||
d="m147.85-64.841c0 2.272 1.849 4.121 4.121 4.121s4.121-1.849 4.121-4.121-1.849-4.121-4.121-4.121-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z" />
|
||||
<path
|
||||
id="path857"
|
||||
d="m142.46-58.208c-2.119 0-3.8424 1.7241-3.8424 3.8431s1.7244 3.8418 3.8424 3.8418h0.92709v9.8112l-17.488 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.9023 3.8268 6.6263 3.8268h35.048c2.726 0 5.265-1.4668 6.625-3.8268 1.365-2.359 1.3647-5.292 6.7e-4 -7.651l-17.33-30.02v-10.079h0.77213c2.118 0 3.8418-1.7238 3.8418-3.8418 0-2.119-1.7238-3.8431-3.8418-3.8431zm0 2.5579h15.183c0.708 0 1.2826 0.57716 1.2826 1.2852s-0.57455 1.2852-1.2826 1.2852h-2.0521c-0.706 0-1.2793 0.57265-1.2793 1.2786v11.7c0 0.225 0.0599 0.44533 0.17188 0.63933 5.4876 9.5256 10.979 18.748 16.42 28.173 1.1773 2.0361 1.1768 4.5675-1e-3 6.6035-1.1738 2.0369-3.3653 3.3027-5.7181 3.3027h-30.25c-2.3511 0-4.5423-1.2658-5.7188-3.3027-1.1756-2.0369-1.1756-4.5666 0-6.6035 3.1075-5.7233 6.5841-11.164 9.7988-16.73h11.534c0.706 0 1.2793-0.57265 1.2793-1.2786s-0.5733-1.2793-1.2793-1.2793h-10.058l1.8724-3.2409h7.6875c0.707 0 1.2793-0.57265 1.2793-1.2786s-0.57229-1.2793-1.2793-1.2793h-6.2096l1.8079-3.1302c0.026-0.036 0.0512-0.07398 0.0762-0.11198h4.8249c0.706 0 1.2786-0.57265 1.2786-1.2786s-0.57264-1.2793-1.2786-1.2793h-4.6061v-3.2422h4.6042c0.706 0 1.2786-0.57265 1.2786-1.2786 0-0.706-0.57265-1.2793-1.2786-1.2793h-4.6042v-3.8236c0-0.706-0.57265-1.2793-1.2786-1.2793h-2.2051v-6.33e-4c-0.708 0-1.2852-0.57616-1.2852-1.2852s0.57615-1.2852 1.2852-1.2852z" />
|
||||
<path
|
||||
sodipodi:nodetypes="asccssccsaa"
|
||||
id="path859"
|
||||
stroke-width="1.085"
|
||||
fill="#ffc107"
|
||||
d="m 37.058802,58.744 c -2.211238,-0.326623 -2.304431,1.967133 -6.515502,1.58573 -5.604733,-0.507629 -8.112707,8.708553 -10.4653,13.24817 -1.2754,2.21 -1.2754,4.9546 0,7.1646 1.2764,2.21 3.6538,3.5833 6.2046,3.5833 h 32.82 c 2.5527,0 4.9304,-1.3733 6.2039,-3.5833 1.2782,-2.2091 1.2787,-4.9555 0.001,-7.1646 C 61.09397,67.092458 60.812829,60.786799 55.987302,61.821109 52.840114,62.495681 48.904068,64.285395 45.3734,63.638435 42.209999,63.058773 40.240353,59.213948 37.058802,58.744 Z" />
|
||||
<path
|
||||
id="path861"
|
||||
stroke-width="1.0003"
|
||||
fill="#212121"
|
||||
d="m 52.101829,13.924 c 3.839,0 6.962,-3.123 6.962,-6.962 0,-3.839 -3.124,-6.962 -6.962,-6.962 -3.838,0 -6.962,3.123 -6.962,6.962 0,3.839 3.124,6.962 6.962,6.962 z m 0,-11.367 c 2.429,0 4.405,1.976 4.405,4.404 0,2.428 -1.976,4.404 -4.405,4.404 -2.429,0 -4.405,-1.976 -4.405,-4.404 0,-2.428 1.977,-4.404 4.405,-4.404 z" />
|
||||
<path
|
||||
id="path863"
|
||||
fill="#212121"
|
||||
d="m 36.145092,12.263787 c 0,2.272 1.849,4.121 4.121,4.121 2.272,0 4.121,-1.849 4.121,-4.121 0,-2.2720002 -1.849,-4.1210002 -4.121,-4.1210002 -2.272,0 -4.121,1.849 -4.121,4.1210002 z m 4.121,-1.563 c 0.862,0 1.563,0.701 1.563,1.563 0,0.862 -0.7,1.563 -1.563,1.563 -0.863,0 -1.563,-0.701 -1.563,-1.563 0,-0.862 0.701,-1.563 1.563,-1.563 z" />
|
||||
<path
|
||||
transform="scale(0.33333335)"
|
||||
d="M 170.52344 185.13477 C 169.71895 185.16191 168.86572 185.26896 167.96094 185.46289 C 166.48482 185.77928 164.93554 186.18969 163.35742 186.62891 C 167.89152 193.29507 171.23644 204.69326 178.76758 216.28516 C 182.60068 222.91246 182.59827 231.152 178.76367 237.7793 C 174.94317 244.4093 167.73492 247.45646 160.15234 248.5293 L 128.72266 252.97656 L 177.30859 252.97656 C 184.96669 252.97656 192.09942 248.85656 195.91992 242.22656 C 199.75452 235.59926 199.75497 227.36167 195.92188 220.73438 C 184.07132 202.49407 182.59072 184.72756 170.52344 185.13477 z "
|
||||
style="fill:#dea806;fill-opacity:1"
|
||||
id="path877" /><path
|
||||
sodipodi:nodetypes="cssccccssccccsscccsssssscccsscccssscccsssccssscssccscc"
|
||||
id="path865"
|
||||
fill="#212121"
|
||||
d="m 33.09,26.098 c -2.119,0 -3.8424,1.7241 -3.8424,3.8431 0,2.119 1.7244,3.8418 3.8424,3.8418 h 0.92709 v 9.8112 l -15.488,28.288 c -1.362,2.36 -1.362,5.957667 0,8.317667 1.363,2.36 3.9023,5.160133 6.6263,5.160133 h 35.048 c 2.726,0 5.265,-2.800133 6.625,-5.160133 1.365,-2.359 1.3647,-5.958667 6.7e-4,-8.317667 l -15.33,-28.02 v -10.079 h 0.77213 c 2.118,0 3.8418,-1.7238 3.8418,-3.8418 0,-2.119 -1.7238,-3.8431 -3.8418,-3.8431 z m 0,2.5579 h 19.183 c 0.708,0 1.2826,0.57716 1.2826,1.2852 0,0.70804 -0.57455,1.2852 -1.2826,1.2852 h -2.0521 c -0.706,0 -1.2793,0.57265 -1.2793,1.2786 v 11.7 c 0,0.225 0.0599,0.44533 0.17188,0.63933 5.4876,9.5256 8.979,16.748 14.42,26.173 1.1773,2.0361 1.1768,5.234167 -10e-4,7.270167 -1.1738,2.0369 -3.3653,4.636033 -5.7181,4.636033 h -30.25 c -2.3511,0 -4.5423,-2.599133 -5.7188,-4.636033 -1.1756,-2.0369 -1.1756,-5.233267 0,-7.270167 l 11.1472,-20.5288 h 7.020833 c 0.707,0 1.2793,-0.57265 1.2793,-1.2786 0,-0.70595 -0.57229,-1.2793 -1.2793,-1.2793 H 34.47068 l 1.8079,-3.1302 c 0.026,-0.036 0.0512,-0.07398 0.0762,-0.11198 h 4.158233 c 0.706,0 1.2786,-0.57265 1.2786,-1.2786 0,-0.70595 -0.57264,-1.2793 -1.2786,-1.2793 H 36.57358 v -3.2422 h 3.937533 c 0.706,0 1.2786,-0.57265 1.2786,-1.2786 0,-0.706 -0.57265,-1.2793 -1.2786,-1.2793 H 36.57358 v -3.8236 c 0,-0.706 -0.57265,-1.2793 -1.2786,-1.2793 h -2.2051 v -6.33e-4 c -0.708,0 -1.2852,-0.57616 -1.2852,-1.2852 0,-0.70904 0.57615,-1.2852 1.2852,-1.2852 z" />
|
||||
<path
|
||||
d="m 45.676109,19.570901 c 0,2.272 1.849,4.121 4.121,4.121 2.272,0 4.121,-1.849 4.121,-4.121 0,-2.272 -1.849,-4.121 -4.121,-4.121 -2.272,0 -4.121,1.849 -4.121,4.121 z m 4.121,-1.563 c 0.862,0 1.563,0.701 1.563,1.563 0,0.862 -0.7,1.563 -1.563,1.563 -0.863,0 -1.563,-0.701 -1.563,-1.563 0,-0.862 0.701,-1.563 1.563,-1.563 z"
|
||||
fill="#212121"
|
||||
id="path873" /><ellipse
|
||||
ry="1.2093649"
|
||||
rx="1.209365"
|
||||
cy="23.405575"
|
||||
cx="42.891182"
|
||||
id="path875"
|
||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.914604;stroke-linecap:round;stroke-linejoin:round" /></svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
130
ui/public/flask_white.svg
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="256.08"
|
||||
height="256.08"
|
||||
enable-background="new 0 0 100 100"
|
||||
fill="#333333"
|
||||
version="1.1"
|
||||
viewBox="0 0 85.36 85.36"
|
||||
xml:space="preserve"
|
||||
id="svg867"
|
||||
sodipodi:docname="flask_white.svg"
|
||||
inkscape:version="1.0 (4035a4f, 2020-05-01)"><defs
|
||||
id="defs871" /><sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1615"
|
||||
inkscape:window-height="1254"
|
||||
id="namedview869"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.9033873"
|
||||
inkscape:cx="128.03999"
|
||||
inkscape:cy="103.03585"
|
||||
inkscape:window-x="3192"
|
||||
inkscape:window-y="41"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg867" />
|
||||
<metadata
|
||||
id="metadata833">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
d="m27.345-37.335-17.33-30.02v-10.079h0.772c2.118 0 3.842-1.724 3.842-3.842 0-2.119-1.724-3.843-3.842-3.843h-15.182c-2.119 0-3.842 1.724-3.842 3.843s1.724 3.842 3.842 3.842h0.927v9.811l-17.487 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.902 3.827 6.626 3.827h35.048c2.726 0 5.265-1.467 6.625-3.827 1.365-2.359 1.365-5.292 1e-3 -7.651zm-31.74-42.656c-0.708 0-1.285-0.576-1.285-1.285s0.576-1.285 1.285-1.285h15.183c0.708 0 1.283 0.577 1.283 1.285s-0.575 1.285-1.283 1.285h-2.052c-0.706 0-1.279 0.573-1.279 1.279v11.7c0 0.225 0.06 0.445 0.172 0.639l10.577 18.324c-0.034 5e-3 -0.069 3e-3 -0.104 9e-3 -0.345 0.055-0.651 0.102-0.889 0.102-0.916 0-1.835-0.238-2.731-0.708-0.43-0.228-0.889-0.335-1.344-0.335-0.969 0-1.91 0.488-2.456 1.361-1.131 1.813-3.039 2.894-5.104 2.894-2.854 0-5.286-2.003-5.914-4.87-0.203-0.932-0.851-1.702-1.732-2.061-0.351-0.145-0.723-0.215-1.092-0.215-0.554 0-1.107 0.16-1.584 0.474-0.987 0.646-2.112 0.987-3.25 0.987-0.517 0-1.074-0.097-1.753-0.307-0.155-0.049-0.311-0.081-0.467-0.103l2.373-4.109h11.535c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-10.058l1.872-3.241h7.688c0.707 0 1.279-0.573 1.279-1.279s-0.572-1.279-1.279-1.279h-6.21l1.808-3.13c0.026-0.036 0.051-0.074 0.076-0.112h4.825c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.606v-3.242h4.604c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.604v-3.824c0-0.706-0.573-1.279-1.279-1.279h-2.205z"
|
||||
id="path835" />
|
||||
<path
|
||||
d="m-4.538-97.293c3.839 0 6.962-3.123 6.962-6.962s-3.124-6.962-6.962-6.962-6.962 3.123-6.962 6.962 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404s-1.976 4.404-4.405 4.404-4.405-1.976-4.405-4.404 1.977-4.404 4.405-4.404z"
|
||||
id="path837" />
|
||||
<path
|
||||
d="m1.003-91.752c0 2.272 1.849 4.121 4.121 4.121s4.121-1.849 4.121-4.121-1.849-4.121-4.121-4.121-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z"
|
||||
id="path839" />
|
||||
<path
|
||||
d="m24.048-38.2-5.3303-9.2335c-3.1435-7.7748-21.883-13.817-29.584-2.4987l-6.7736 11.732c-1.1756 2.0369-1.1756 4.5667 0 6.6036 1.1764 2.0369 3.3678 3.3031 5.7189 3.3031h30.25c2.3528 0 4.5442-1.2662 5.7181-3.3031 1.1781-2.0361 1.1781-4.5676 8.63e-4 -6.6036z"
|
||||
fill="#fc0"
|
||||
stroke-width=".8631"
|
||||
id="path841" />
|
||||
<path
|
||||
d="m143.85-25.061c-0.554 0-1.107 0.16061-1.584 0.47461-0.987 0.646-2.112 0.98698-3.25 0.98698-0.517 0-1.0743-0.09729-1.7533-0.30729-0.39216 0.03998-0.72173 0.07672-1.1191 0.78581l-6.7734 11.732c-1.1756 2.0369-1.1756 4.5666 0 6.6035 1.1764 2.0369 3.3676 3.3027 5.7188 3.3027h30.25c2.3528 0 4.5443-1.2658 5.7181-3.3027 1.1781-2.0361 1.1786-4.5675 1e-3 -6.6035l-5.3307-9.2337c-0.45242-0.78245-0.70174-0.56556-1.5046-0.50452-0.916 0-1.8351-0.23768-2.7311-0.70768-0.43-0.228-0.88941-0.33529-1.3444-0.33529-0.969 0-1.9097 0.48833-2.4557 1.3613-1.131 1.813-3.0392 2.8939-5.1042 2.8939-2.854 0-5.2861-2.0034-5.9141-4.8704-0.203-0.932-0.85077-1.7015-1.7318-2.0605-0.351-0.145-0.7228-0.21549-1.0918-0.21549z"
|
||||
fill="#ffc107"
|
||||
id="path843" />
|
||||
<path
|
||||
d="m94.563-31.292-17.33-30.02v-10.079h0.772c2.118 0 3.842-1.724 3.842-3.842 0-2.119-1.724-3.843-3.842-3.843h-15.182c-2.119 0-3.842 1.724-3.842 3.843s1.724 3.842 3.842 3.842h0.927v9.811l-17.487 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.902 3.827 6.626 3.827h35.048c2.726 0 5.265-1.467 6.625-3.827 1.365-2.359 1.365-5.292 1e-3 -7.651zm-31.74-42.656c-0.708 0-1.285-0.576-1.285-1.285s0.576-1.285 1.285-1.285h15.183c0.708 0 1.283 0.577 1.283 1.285s-0.575 1.285-1.283 1.285h-2.052c-0.706 0-1.279 0.573-1.279 1.279v11.7c0 0.225 0.06 0.445 0.172 0.639l10.577 18.324c-0.034 5e-3 -0.069 3e-3 -0.104 9e-3 -0.345 0.055-0.651 0.102-0.889 0.102-0.916 0-1.835-0.238-2.731-0.708-0.43-0.228-0.889-0.335-1.344-0.335-0.969 0-1.91 0.488-2.456 1.361-1.131 1.813-3.039 2.894-5.104 2.894-2.854 0-5.286-2.003-5.914-4.87-0.203-0.932-0.851-1.702-1.732-2.061-0.351-0.145-0.723-0.215-1.092-0.215-0.554 0-1.107 0.16-1.584 0.474-0.987 0.646-2.112 0.987-3.25 0.987-0.517 0-1.074-0.097-1.753-0.307-0.155-0.049-0.311-0.081-0.467-0.103l2.373-4.109h11.535c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-10.058l1.872-3.241h7.688c0.707 0 1.279-0.573 1.279-1.279s-0.572-1.279-1.279-1.279h-6.21l1.808-3.13c0.026-0.036 0.051-0.074 0.076-0.112h4.825c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.606v-3.242h4.604c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.604v-3.824c0-0.706-0.573-1.279-1.279-1.279h-2.205z"
|
||||
fill="#ffc107"
|
||||
id="path845" />
|
||||
<path
|
||||
d="m62.68-91.25c3.839 0 6.962-3.123 6.962-6.962 0-3.839-3.124-6.962-6.962-6.962s-6.962 3.123-6.962 6.962c0 3.839 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404 0 2.428-1.976 4.404-4.405 4.404s-4.405-1.976-4.405-4.404c0-2.428 1.977-4.404 4.405-4.404z"
|
||||
id="path847" />
|
||||
<path
|
||||
d="m68.221-85.709c0 2.272 1.849 4.121 4.121 4.121 2.272 0 4.121-1.849 4.121-4.121s-1.849-4.121-4.121-4.121c-2.272 0-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z"
|
||||
id="path849" />
|
||||
<path
|
||||
d="m62.824-79.076c-2.119 0-3.8424 1.7241-3.8424 3.8431s1.7244 3.8418 3.8424 3.8418h0.92709v9.8112l-17.488 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.9023 3.8268 6.6263 3.8268h35.048c2.726 0 5.265-1.4668 6.625-3.8268 1.365-2.359 1.3647-5.292 6.7e-4 -7.651l-17.33-30.02v-10.079h0.77213c2.118 0 3.8418-1.7238 3.8418-3.8418 0-2.119-1.7238-3.8431-3.8418-3.8431zm0 2.5579h15.183c0.708 0 1.2826 0.57716 1.2826 1.2852s-0.57455 1.2852-1.2826 1.2852h-2.0521c-0.706 0-1.2793 0.57265-1.2793 1.2786v11.7c0 0.225 0.0599 0.44533 0.17188 0.63933 5.4876 9.5256 10.979 18.748 16.42 28.173 1.1773 2.0361 1.1768 4.5675-1e-3 6.6035-1.1738 2.0369-3.3653 3.3027-5.7181 3.3027h-30.25c-2.3511 0-4.5423-1.2658-5.7188-3.3027-1.1756-2.0369-1.1756-4.5666 0-6.6035 3.1075-5.7233 6.5841-11.164 9.7988-16.73h11.534c0.706 0 1.2793-0.57265 1.2793-1.2786s-0.5733-1.2793-1.2793-1.2793h-10.058l1.8724-3.2409h7.6875c0.707 0 1.2793-0.57265 1.2793-1.2786s-0.57229-1.2793-1.2793-1.2793h-6.2096l1.8079-3.1302c0.026-0.036 0.0512-0.07398 0.0762-0.11198h4.8249c0.706 0 1.2786-0.57265 1.2786-1.2786s-0.57264-1.2793-1.2786-1.2793h-4.6061v-3.2422h4.6042c0.706 0 1.2786-0.57265 1.2786-1.2786 0-0.706-0.57265-1.2793-1.2786-1.2793h-4.6042v-3.8236c0-0.706-0.57265-1.2793-1.2786-1.2793h-2.2051v-6.33e-4c-0.708 0-1.2852-0.57616-1.2852-1.2852s0.57615-1.2852 1.2852-1.2852z"
|
||||
id="path851" />
|
||||
<path
|
||||
d="m142.31-70.382c3.839 0 6.962-3.123 6.962-6.962s-3.124-6.962-6.962-6.962-6.962 3.123-6.962 6.962 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404s-1.976 4.404-4.405 4.404-4.405-1.976-4.405-4.404 1.977-4.404 4.405-4.404z"
|
||||
id="path853" />
|
||||
<path
|
||||
d="m147.85-64.841c0 2.272 1.849 4.121 4.121 4.121s4.121-1.849 4.121-4.121-1.849-4.121-4.121-4.121-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z"
|
||||
id="path855" />
|
||||
<path
|
||||
d="m142.46-58.208c-2.119 0-3.8424 1.7241-3.8424 3.8431s1.7244 3.8418 3.8424 3.8418h0.92709v9.8112l-17.488 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.9023 3.8268 6.6263 3.8268h35.048c2.726 0 5.265-1.4668 6.625-3.8268 1.365-2.359 1.3647-5.292 6.7e-4 -7.651l-17.33-30.02v-10.079h0.77213c2.118 0 3.8418-1.7238 3.8418-3.8418 0-2.119-1.7238-3.8431-3.8418-3.8431zm0 2.5579h15.183c0.708 0 1.2826 0.57716 1.2826 1.2852s-0.57455 1.2852-1.2826 1.2852h-2.0521c-0.706 0-1.2793 0.57265-1.2793 1.2786v11.7c0 0.225 0.0599 0.44533 0.17188 0.63933 5.4876 9.5256 10.979 18.748 16.42 28.173 1.1773 2.0361 1.1768 4.5675-1e-3 6.6035-1.1738 2.0369-3.3653 3.3027-5.7181 3.3027h-30.25c-2.3511 0-4.5423-1.2658-5.7188-3.3027-1.1756-2.0369-1.1756-4.5666 0-6.6035 3.1075-5.7233 6.5841-11.164 9.7988-16.73h11.534c0.706 0 1.2793-0.57265 1.2793-1.2786s-0.5733-1.2793-1.2793-1.2793h-10.058l1.8724-3.2409h7.6875c0.707 0 1.2793-0.57265 1.2793-1.2786s-0.57229-1.2793-1.2793-1.2793h-6.2096l1.8079-3.1302c0.026-0.036 0.0512-0.07398 0.0762-0.11198h4.8249c0.706 0 1.2786-0.57265 1.2786-1.2786s-0.57264-1.2793-1.2786-1.2793h-4.6061v-3.2422h4.6042c0.706 0 1.2786-0.57265 1.2786-1.2786 0-0.706-0.57265-1.2793-1.2786-1.2793h-4.6042v-3.8236c0-0.706-0.57265-1.2793-1.2786-1.2793h-2.2051v-6.33e-4c-0.708 0-1.2852-0.57616-1.2852-1.2852s0.57615-1.2852 1.2852-1.2852z"
|
||||
id="path857" />
|
||||
<path
|
||||
d="m 37.058802,58.744 c -2.211238,-0.326623 -2.304431,1.967133 -6.515502,1.58573 -5.604733,-0.507629 -8.112707,8.708553 -10.4653,13.24817 -1.2754,2.21 -1.2754,4.9546 0,7.1646 1.2764,2.21 3.6538,3.5833 6.2046,3.5833 h 32.82 c 2.5527,0 4.9304,-1.3733 6.2039,-3.5833 1.2782,-2.2091 1.2787,-4.9555 0.001,-7.1646 C 61.09397,67.092458 60.812829,60.786799 55.987302,61.821109 52.840114,62.495681 48.904068,64.285395 45.3734,63.638435 42.209999,63.058773 40.240353,59.213948 37.058802,58.744 Z"
|
||||
fill="#ffc107"
|
||||
stroke-width="1.085"
|
||||
id="path859"
|
||||
sodipodi:nodetypes="asccssccsaa" />
|
||||
<path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
d="m 52.101829,13.924 c 3.839,0 6.962,-3.123 6.962,-6.962 0,-3.839 -3.124,-6.962 -6.962,-6.962 -3.838,0 -6.962,3.123 -6.962,6.962 0,3.839 3.124,6.962 6.962,6.962 z m 0,-11.367 c 2.429,0 4.405,1.976 4.405,4.404 0,2.428 -1.976,4.404 -4.405,4.404 -2.429,0 -4.405,-1.976 -4.405,-4.404 0,-2.428 1.977,-4.404 4.405,-4.404 z"
|
||||
fill="#212121"
|
||||
stroke-width="1.0003"
|
||||
id="path861" />
|
||||
<path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
d="m 36.145092,12.263787 c 0,2.272 1.849,4.121 4.121,4.121 2.272,0 4.121,-1.849 4.121,-4.121 0,-2.2720002 -1.849,-4.1210002 -4.121,-4.1210002 -2.272,0 -4.121,1.849 -4.121,4.1210002 z m 4.121,-1.563 c 0.862,0 1.563,0.701 1.563,1.563 0,0.862 -0.7,1.563 -1.563,1.563 -0.863,0 -1.563,-0.701 -1.563,-1.563 0,-0.862 0.701,-1.563 1.563,-1.563 z"
|
||||
fill="#212121"
|
||||
id="path863" />
|
||||
<path
|
||||
id="path877"
|
||||
style="fill:#dea806;fill-opacity:1"
|
||||
d="M 170.52344 185.13477 C 169.71895 185.16191 168.86572 185.26896 167.96094 185.46289 C 166.48482 185.77928 164.93554 186.18969 163.35742 186.62891 C 167.89152 193.29507 171.23644 204.69326 178.76758 216.28516 C 182.60068 222.91246 182.59827 231.152 178.76367 237.7793 C 174.94317 244.4093 167.73492 247.45646 160.15234 248.5293 L 128.72266 252.97656 L 177.30859 252.97656 C 184.96669 252.97656 192.09942 248.85656 195.91992 242.22656 C 199.75452 235.59926 199.75497 227.36167 195.92188 220.73438 C 184.07132 202.49407 182.59072 184.72756 170.52344 185.13477 z "
|
||||
transform="scale(0.33333335)" /><path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
d="m 33.09,26.098 c -2.119,0 -3.8424,1.7241 -3.8424,3.8431 0,2.119 1.7244,3.8418 3.8424,3.8418 h 0.92709 v 9.8112 l -15.488,28.288 c -1.362,2.36 -1.362,5.957667 0,8.317667 1.363,2.36 3.9023,5.160133 6.6263,5.160133 h 35.048 c 2.726,0 5.265,-2.800133 6.625,-5.160133 1.365,-2.359 1.3647,-5.958667 6.7e-4,-8.317667 l -15.33,-28.02 v -10.079 h 0.77213 c 2.118,0 3.8418,-1.7238 3.8418,-3.8418 0,-2.119 -1.7238,-3.8431 -3.8418,-3.8431 z m 0,2.5579 h 19.183 c 0.708,0 1.2826,0.57716 1.2826,1.2852 0,0.70804 -0.57455,1.2852 -1.2826,1.2852 h -2.0521 c -0.706,0 -1.2793,0.57265 -1.2793,1.2786 v 11.7 c 0,0.225 0.0599,0.44533 0.17188,0.63933 5.4876,9.5256 8.979,16.748 14.42,26.173 1.1773,2.0361 1.1768,5.234167 -10e-4,7.270167 -1.1738,2.0369 -3.3653,4.636033 -5.7181,4.636033 h -30.25 c -2.3511,0 -4.5423,-2.599133 -5.7188,-4.636033 -1.1756,-2.0369 -1.1756,-5.233267 0,-7.270167 l 11.1472,-20.5288 h 7.020833 c 0.707,0 1.2793,-0.57265 1.2793,-1.2786 0,-0.70595 -0.57229,-1.2793 -1.2793,-1.2793 H 34.47068 l 1.8079,-3.1302 c 0.026,-0.036 0.0512,-0.07398 0.0762,-0.11198 h 4.158233 c 0.706,0 1.2786,-0.57265 1.2786,-1.2786 0,-0.70595 -0.57264,-1.2793 -1.2786,-1.2793 H 36.57358 v -3.2422 h 3.937533 c 0.706,0 1.2786,-0.57265 1.2786,-1.2786 0,-0.706 -0.57265,-1.2793 -1.2786,-1.2793 H 36.57358 v -3.8236 c 0,-0.706 -0.57265,-1.2793 -1.2786,-1.2793 h -2.2051 v -6.33e-4 c -0.708,0 -1.2852,-0.57616 -1.2852,-1.2852 0,-0.70904 0.57615,-1.2852 1.2852,-1.2852 z"
|
||||
fill="#212121"
|
||||
id="path865"
|
||||
sodipodi:nodetypes="cssccccssccccsscccsssssscccsscccssscccsssccssscssccscc" />
|
||||
<path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
id="path873"
|
||||
fill="#212121"
|
||||
d="m 45.676109,19.570901 c 0,2.272 1.849,4.121 4.121,4.121 2.272,0 4.121,-1.849 4.121,-4.121 0,-2.272 -1.849,-4.121 -4.121,-4.121 -2.272,0 -4.121,1.849 -4.121,4.121 z m 4.121,-1.563 c 0.862,0 1.563,0.701 1.563,1.563 0,0.862 -0.7,1.563 -1.563,1.563 -0.863,0 -1.563,-0.701 -1.563,-1.563 0,-0.862 0.701,-1.563 1.563,-1.563 z" /><ellipse
|
||||
style="fill:#fcfcfc;fill-opacity:1;stroke:#fcfcfc;stroke-width:0.914604;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path875"
|
||||
cx="42.891182"
|
||||
cy="23.405575"
|
||||
rx="1.209365"
|
||||
ry="1.2093649" /></svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
BIN
ui/public/img/icons/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
ui/public/img/icons/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
ui/public/img/icons/android-chrome-maskable-192x192.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
ui/public/img/icons/android-chrome-maskable-512x512.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
ui/public/img/icons/apple-touch-icon-120x120.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
ui/public/img/icons/apple-touch-icon-152x152.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
ui/public/img/icons/apple-touch-icon-180x180.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
ui/public/img/icons/apple-touch-icon-60x60.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
ui/public/img/icons/apple-touch-icon-76x76.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
ui/public/img/icons/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
ui/public/img/icons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 601 B |
BIN
ui/public/img/icons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ui/public/img/icons/msapplication-icon-144x144.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
ui/public/img/icons/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
130
ui/public/img/icons/safari-pinned-tab.svg
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="256.08"
|
||||
height="256.08"
|
||||
enable-background="new 0 0 100 100"
|
||||
fill="#333333"
|
||||
version="1.1"
|
||||
viewBox="0 0 85.36 85.36"
|
||||
xml:space="preserve"
|
||||
id="svg867"
|
||||
sodipodi:docname="flask_white.svg"
|
||||
inkscape:version="1.0 (4035a4f, 2020-05-01)"><defs
|
||||
id="defs871" /><sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1615"
|
||||
inkscape:window-height="1254"
|
||||
id="namedview869"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.9033873"
|
||||
inkscape:cx="128.03999"
|
||||
inkscape:cy="103.03585"
|
||||
inkscape:window-x="3192"
|
||||
inkscape:window-y="41"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg867" />
|
||||
<metadata
|
||||
id="metadata833">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
d="m27.345-37.335-17.33-30.02v-10.079h0.772c2.118 0 3.842-1.724 3.842-3.842 0-2.119-1.724-3.843-3.842-3.843h-15.182c-2.119 0-3.842 1.724-3.842 3.843s1.724 3.842 3.842 3.842h0.927v9.811l-17.487 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.902 3.827 6.626 3.827h35.048c2.726 0 5.265-1.467 6.625-3.827 1.365-2.359 1.365-5.292 1e-3 -7.651zm-31.74-42.656c-0.708 0-1.285-0.576-1.285-1.285s0.576-1.285 1.285-1.285h15.183c0.708 0 1.283 0.577 1.283 1.285s-0.575 1.285-1.283 1.285h-2.052c-0.706 0-1.279 0.573-1.279 1.279v11.7c0 0.225 0.06 0.445 0.172 0.639l10.577 18.324c-0.034 5e-3 -0.069 3e-3 -0.104 9e-3 -0.345 0.055-0.651 0.102-0.889 0.102-0.916 0-1.835-0.238-2.731-0.708-0.43-0.228-0.889-0.335-1.344-0.335-0.969 0-1.91 0.488-2.456 1.361-1.131 1.813-3.039 2.894-5.104 2.894-2.854 0-5.286-2.003-5.914-4.87-0.203-0.932-0.851-1.702-1.732-2.061-0.351-0.145-0.723-0.215-1.092-0.215-0.554 0-1.107 0.16-1.584 0.474-0.987 0.646-2.112 0.987-3.25 0.987-0.517 0-1.074-0.097-1.753-0.307-0.155-0.049-0.311-0.081-0.467-0.103l2.373-4.109h11.535c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-10.058l1.872-3.241h7.688c0.707 0 1.279-0.573 1.279-1.279s-0.572-1.279-1.279-1.279h-6.21l1.808-3.13c0.026-0.036 0.051-0.074 0.076-0.112h4.825c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.606v-3.242h4.604c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.604v-3.824c0-0.706-0.573-1.279-1.279-1.279h-2.205z"
|
||||
id="path835" />
|
||||
<path
|
||||
d="m-4.538-97.293c3.839 0 6.962-3.123 6.962-6.962s-3.124-6.962-6.962-6.962-6.962 3.123-6.962 6.962 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404s-1.976 4.404-4.405 4.404-4.405-1.976-4.405-4.404 1.977-4.404 4.405-4.404z"
|
||||
id="path837" />
|
||||
<path
|
||||
d="m1.003-91.752c0 2.272 1.849 4.121 4.121 4.121s4.121-1.849 4.121-4.121-1.849-4.121-4.121-4.121-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z"
|
||||
id="path839" />
|
||||
<path
|
||||
d="m24.048-38.2-5.3303-9.2335c-3.1435-7.7748-21.883-13.817-29.584-2.4987l-6.7736 11.732c-1.1756 2.0369-1.1756 4.5667 0 6.6036 1.1764 2.0369 3.3678 3.3031 5.7189 3.3031h30.25c2.3528 0 4.5442-1.2662 5.7181-3.3031 1.1781-2.0361 1.1781-4.5676 8.63e-4 -6.6036z"
|
||||
fill="#fc0"
|
||||
stroke-width=".8631"
|
||||
id="path841" />
|
||||
<path
|
||||
d="m143.85-25.061c-0.554 0-1.107 0.16061-1.584 0.47461-0.987 0.646-2.112 0.98698-3.25 0.98698-0.517 0-1.0743-0.09729-1.7533-0.30729-0.39216 0.03998-0.72173 0.07672-1.1191 0.78581l-6.7734 11.732c-1.1756 2.0369-1.1756 4.5666 0 6.6035 1.1764 2.0369 3.3676 3.3027 5.7188 3.3027h30.25c2.3528 0 4.5443-1.2658 5.7181-3.3027 1.1781-2.0361 1.1786-4.5675 1e-3 -6.6035l-5.3307-9.2337c-0.45242-0.78245-0.70174-0.56556-1.5046-0.50452-0.916 0-1.8351-0.23768-2.7311-0.70768-0.43-0.228-0.88941-0.33529-1.3444-0.33529-0.969 0-1.9097 0.48833-2.4557 1.3613-1.131 1.813-3.0392 2.8939-5.1042 2.8939-2.854 0-5.2861-2.0034-5.9141-4.8704-0.203-0.932-0.85077-1.7015-1.7318-2.0605-0.351-0.145-0.7228-0.21549-1.0918-0.21549z"
|
||||
fill="#ffc107"
|
||||
id="path843" />
|
||||
<path
|
||||
d="m94.563-31.292-17.33-30.02v-10.079h0.772c2.118 0 3.842-1.724 3.842-3.842 0-2.119-1.724-3.843-3.842-3.843h-15.182c-2.119 0-3.842 1.724-3.842 3.843s1.724 3.842 3.842 3.842h0.927v9.811l-17.487 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.902 3.827 6.626 3.827h35.048c2.726 0 5.265-1.467 6.625-3.827 1.365-2.359 1.365-5.292 1e-3 -7.651zm-31.74-42.656c-0.708 0-1.285-0.576-1.285-1.285s0.576-1.285 1.285-1.285h15.183c0.708 0 1.283 0.577 1.283 1.285s-0.575 1.285-1.283 1.285h-2.052c-0.706 0-1.279 0.573-1.279 1.279v11.7c0 0.225 0.06 0.445 0.172 0.639l10.577 18.324c-0.034 5e-3 -0.069 3e-3 -0.104 9e-3 -0.345 0.055-0.651 0.102-0.889 0.102-0.916 0-1.835-0.238-2.731-0.708-0.43-0.228-0.889-0.335-1.344-0.335-0.969 0-1.91 0.488-2.456 1.361-1.131 1.813-3.039 2.894-5.104 2.894-2.854 0-5.286-2.003-5.914-4.87-0.203-0.932-0.851-1.702-1.732-2.061-0.351-0.145-0.723-0.215-1.092-0.215-0.554 0-1.107 0.16-1.584 0.474-0.987 0.646-2.112 0.987-3.25 0.987-0.517 0-1.074-0.097-1.753-0.307-0.155-0.049-0.311-0.081-0.467-0.103l2.373-4.109h11.535c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-10.058l1.872-3.241h7.688c0.707 0 1.279-0.573 1.279-1.279s-0.572-1.279-1.279-1.279h-6.21l1.808-3.13c0.026-0.036 0.051-0.074 0.076-0.112h4.825c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.606v-3.242h4.604c0.706 0 1.279-0.573 1.279-1.279s-0.573-1.279-1.279-1.279h-4.604v-3.824c0-0.706-0.573-1.279-1.279-1.279h-2.205z"
|
||||
fill="#ffc107"
|
||||
id="path845" />
|
||||
<path
|
||||
d="m62.68-91.25c3.839 0 6.962-3.123 6.962-6.962 0-3.839-3.124-6.962-6.962-6.962s-6.962 3.123-6.962 6.962c0 3.839 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404 0 2.428-1.976 4.404-4.405 4.404s-4.405-1.976-4.405-4.404c0-2.428 1.977-4.404 4.405-4.404z"
|
||||
id="path847" />
|
||||
<path
|
||||
d="m68.221-85.709c0 2.272 1.849 4.121 4.121 4.121 2.272 0 4.121-1.849 4.121-4.121s-1.849-4.121-4.121-4.121c-2.272 0-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z"
|
||||
id="path849" />
|
||||
<path
|
||||
d="m62.824-79.076c-2.119 0-3.8424 1.7241-3.8424 3.8431s1.7244 3.8418 3.8424 3.8418h0.92709v9.8112l-17.488 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.9023 3.8268 6.6263 3.8268h35.048c2.726 0 5.265-1.4668 6.625-3.8268 1.365-2.359 1.3647-5.292 6.7e-4 -7.651l-17.33-30.02v-10.079h0.77213c2.118 0 3.8418-1.7238 3.8418-3.8418 0-2.119-1.7238-3.8431-3.8418-3.8431zm0 2.5579h15.183c0.708 0 1.2826 0.57716 1.2826 1.2852s-0.57455 1.2852-1.2826 1.2852h-2.0521c-0.706 0-1.2793 0.57265-1.2793 1.2786v11.7c0 0.225 0.0599 0.44533 0.17188 0.63933 5.4876 9.5256 10.979 18.748 16.42 28.173 1.1773 2.0361 1.1768 4.5675-1e-3 6.6035-1.1738 2.0369-3.3653 3.3027-5.7181 3.3027h-30.25c-2.3511 0-4.5423-1.2658-5.7188-3.3027-1.1756-2.0369-1.1756-4.5666 0-6.6035 3.1075-5.7233 6.5841-11.164 9.7988-16.73h11.534c0.706 0 1.2793-0.57265 1.2793-1.2786s-0.5733-1.2793-1.2793-1.2793h-10.058l1.8724-3.2409h7.6875c0.707 0 1.2793-0.57265 1.2793-1.2786s-0.57229-1.2793-1.2793-1.2793h-6.2096l1.8079-3.1302c0.026-0.036 0.0512-0.07398 0.0762-0.11198h4.8249c0.706 0 1.2786-0.57265 1.2786-1.2786s-0.57264-1.2793-1.2786-1.2793h-4.6061v-3.2422h4.6042c0.706 0 1.2786-0.57265 1.2786-1.2786 0-0.706-0.57265-1.2793-1.2786-1.2793h-4.6042v-3.8236c0-0.706-0.57265-1.2793-1.2786-1.2793h-2.2051v-6.33e-4c-0.708 0-1.2852-0.57616-1.2852-1.2852s0.57615-1.2852 1.2852-1.2852z"
|
||||
id="path851" />
|
||||
<path
|
||||
d="m142.31-70.382c3.839 0 6.962-3.123 6.962-6.962s-3.124-6.962-6.962-6.962-6.962 3.123-6.962 6.962 3.124 6.962 6.962 6.962zm0-11.367c2.429 0 4.405 1.976 4.405 4.404s-1.976 4.404-4.405 4.404-4.405-1.976-4.405-4.404 1.977-4.404 4.405-4.404z"
|
||||
id="path853" />
|
||||
<path
|
||||
d="m147.85-64.841c0 2.272 1.849 4.121 4.121 4.121s4.121-1.849 4.121-4.121-1.849-4.121-4.121-4.121-4.121 1.849-4.121 4.121zm4.121-1.563c0.862 0 1.563 0.701 1.563 1.563s-0.7 1.563-1.563 1.563-1.563-0.701-1.563-1.563 0.701-1.563 1.563-1.563z"
|
||||
id="path855" />
|
||||
<path
|
||||
d="m142.46-58.208c-2.119 0-3.8424 1.7241-3.8424 3.8431s1.7244 3.8418 3.8424 3.8418h0.92709v9.8112l-17.488 30.288c-1.362 2.36-1.362 5.291 0 7.651 1.363 2.36 3.9023 3.8268 6.6263 3.8268h35.048c2.726 0 5.265-1.4668 6.625-3.8268 1.365-2.359 1.3647-5.292 6.7e-4 -7.651l-17.33-30.02v-10.079h0.77213c2.118 0 3.8418-1.7238 3.8418-3.8418 0-2.119-1.7238-3.8431-3.8418-3.8431zm0 2.5579h15.183c0.708 0 1.2826 0.57716 1.2826 1.2852s-0.57455 1.2852-1.2826 1.2852h-2.0521c-0.706 0-1.2793 0.57265-1.2793 1.2786v11.7c0 0.225 0.0599 0.44533 0.17188 0.63933 5.4876 9.5256 10.979 18.748 16.42 28.173 1.1773 2.0361 1.1768 4.5675-1e-3 6.6035-1.1738 2.0369-3.3653 3.3027-5.7181 3.3027h-30.25c-2.3511 0-4.5423-1.2658-5.7188-3.3027-1.1756-2.0369-1.1756-4.5666 0-6.6035 3.1075-5.7233 6.5841-11.164 9.7988-16.73h11.534c0.706 0 1.2793-0.57265 1.2793-1.2786s-0.5733-1.2793-1.2793-1.2793h-10.058l1.8724-3.2409h7.6875c0.707 0 1.2793-0.57265 1.2793-1.2786s-0.57229-1.2793-1.2793-1.2793h-6.2096l1.8079-3.1302c0.026-0.036 0.0512-0.07398 0.0762-0.11198h4.8249c0.706 0 1.2786-0.57265 1.2786-1.2786s-0.57264-1.2793-1.2786-1.2793h-4.6061v-3.2422h4.6042c0.706 0 1.2786-0.57265 1.2786-1.2786 0-0.706-0.57265-1.2793-1.2786-1.2793h-4.6042v-3.8236c0-0.706-0.57265-1.2793-1.2786-1.2793h-2.2051v-6.33e-4c-0.708 0-1.2852-0.57616-1.2852-1.2852s0.57615-1.2852 1.2852-1.2852z"
|
||||
id="path857" />
|
||||
<path
|
||||
d="m 37.058802,58.744 c -2.211238,-0.326623 -2.304431,1.967133 -6.515502,1.58573 -5.604733,-0.507629 -8.112707,8.708553 -10.4653,13.24817 -1.2754,2.21 -1.2754,4.9546 0,7.1646 1.2764,2.21 3.6538,3.5833 6.2046,3.5833 h 32.82 c 2.5527,0 4.9304,-1.3733 6.2039,-3.5833 1.2782,-2.2091 1.2787,-4.9555 0.001,-7.1646 C 61.09397,67.092458 60.812829,60.786799 55.987302,61.821109 52.840114,62.495681 48.904068,64.285395 45.3734,63.638435 42.209999,63.058773 40.240353,59.213948 37.058802,58.744 Z"
|
||||
fill="#ffc107"
|
||||
stroke-width="1.085"
|
||||
id="path859"
|
||||
sodipodi:nodetypes="asccssccsaa" />
|
||||
<path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
d="m 52.101829,13.924 c 3.839,0 6.962,-3.123 6.962,-6.962 0,-3.839 -3.124,-6.962 -6.962,-6.962 -3.838,0 -6.962,3.123 -6.962,6.962 0,3.839 3.124,6.962 6.962,6.962 z m 0,-11.367 c 2.429,0 4.405,1.976 4.405,4.404 0,2.428 -1.976,4.404 -4.405,4.404 -2.429,0 -4.405,-1.976 -4.405,-4.404 0,-2.428 1.977,-4.404 4.405,-4.404 z"
|
||||
fill="#212121"
|
||||
stroke-width="1.0003"
|
||||
id="path861" />
|
||||
<path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
d="m 36.145092,12.263787 c 0,2.272 1.849,4.121 4.121,4.121 2.272,0 4.121,-1.849 4.121,-4.121 0,-2.2720002 -1.849,-4.1210002 -4.121,-4.1210002 -2.272,0 -4.121,1.849 -4.121,4.1210002 z m 4.121,-1.563 c 0.862,0 1.563,0.701 1.563,1.563 0,0.862 -0.7,1.563 -1.563,1.563 -0.863,0 -1.563,-0.701 -1.563,-1.563 0,-0.862 0.701,-1.563 1.563,-1.563 z"
|
||||
fill="#212121"
|
||||
id="path863" />
|
||||
<path
|
||||
id="path877"
|
||||
style="fill:#dea806;fill-opacity:1"
|
||||
d="M 170.52344 185.13477 C 169.71895 185.16191 168.86572 185.26896 167.96094 185.46289 C 166.48482 185.77928 164.93554 186.18969 163.35742 186.62891 C 167.89152 193.29507 171.23644 204.69326 178.76758 216.28516 C 182.60068 222.91246 182.59827 231.152 178.76367 237.7793 C 174.94317 244.4093 167.73492 247.45646 160.15234 248.5293 L 128.72266 252.97656 L 177.30859 252.97656 C 184.96669 252.97656 192.09942 248.85656 195.91992 242.22656 C 199.75452 235.59926 199.75497 227.36167 195.92188 220.73438 C 184.07132 202.49407 182.59072 184.72756 170.52344 185.13477 z "
|
||||
transform="scale(0.33333335)" /><path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
d="m 33.09,26.098 c -2.119,0 -3.8424,1.7241 -3.8424,3.8431 0,2.119 1.7244,3.8418 3.8424,3.8418 h 0.92709 v 9.8112 l -15.488,28.288 c -1.362,2.36 -1.362,5.957667 0,8.317667 1.363,2.36 3.9023,5.160133 6.6263,5.160133 h 35.048 c 2.726,0 5.265,-2.800133 6.625,-5.160133 1.365,-2.359 1.3647,-5.958667 6.7e-4,-8.317667 l -15.33,-28.02 v -10.079 h 0.77213 c 2.118,0 3.8418,-1.7238 3.8418,-3.8418 0,-2.119 -1.7238,-3.8431 -3.8418,-3.8431 z m 0,2.5579 h 19.183 c 0.708,0 1.2826,0.57716 1.2826,1.2852 0,0.70804 -0.57455,1.2852 -1.2826,1.2852 h -2.0521 c -0.706,0 -1.2793,0.57265 -1.2793,1.2786 v 11.7 c 0,0.225 0.0599,0.44533 0.17188,0.63933 5.4876,9.5256 8.979,16.748 14.42,26.173 1.1773,2.0361 1.1768,5.234167 -10e-4,7.270167 -1.1738,2.0369 -3.3653,4.636033 -5.7181,4.636033 h -30.25 c -2.3511,0 -4.5423,-2.599133 -5.7188,-4.636033 -1.1756,-2.0369 -1.1756,-5.233267 0,-7.270167 l 11.1472,-20.5288 h 7.020833 c 0.707,0 1.2793,-0.57265 1.2793,-1.2786 0,-0.70595 -0.57229,-1.2793 -1.2793,-1.2793 H 34.47068 l 1.8079,-3.1302 c 0.026,-0.036 0.0512,-0.07398 0.0762,-0.11198 h 4.158233 c 0.706,0 1.2786,-0.57265 1.2786,-1.2786 0,-0.70595 -0.57264,-1.2793 -1.2786,-1.2793 H 36.57358 v -3.2422 h 3.937533 c 0.706,0 1.2786,-0.57265 1.2786,-1.2786 0,-0.706 -0.57265,-1.2793 -1.2786,-1.2793 H 36.57358 v -3.8236 c 0,-0.706 -0.57265,-1.2793 -1.2786,-1.2793 h -2.2051 v -6.33e-4 c -0.708,0 -1.2852,-0.57616 -1.2852,-1.2852 0,-0.70904 0.57615,-1.2852 1.2852,-1.2852 z"
|
||||
fill="#212121"
|
||||
id="path865"
|
||||
sodipodi:nodetypes="cssccccssccccsscccsssssscccsscccssscccsssccssscssccscc" />
|
||||
<path
|
||||
style="fill:#fcfcfc;fill-opacity:1"
|
||||
id="path873"
|
||||
fill="#212121"
|
||||
d="m 45.676109,19.570901 c 0,2.272 1.849,4.121 4.121,4.121 2.272,0 4.121,-1.849 4.121,-4.121 0,-2.272 -1.849,-4.121 -4.121,-4.121 -2.272,0 -4.121,1.849 -4.121,4.121 z m 4.121,-1.563 c 0.862,0 1.563,0.701 1.563,1.563 0,0.862 -0.7,1.563 -1.563,1.563 -0.863,0 -1.563,-0.701 -1.563,-1.563 0,-0.862 0.701,-1.563 1.563,-1.563 z" /><ellipse
|
||||
style="fill:#fcfcfc;fill-opacity:1;stroke:#fcfcfc;stroke-width:0.914604;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path875"
|
||||
cx="42.891182"
|
||||
cy="23.405575"
|
||||
rx="1.209365"
|
||||
ry="1.2093649" /></svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
19
ui/public/index.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="/flask.png?v=1">
|
||||
<title>Catalyst</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<script>let global = globalThis;</script>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
76
ui/public/manifest.json
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"icons": [
|
||||
{
|
||||
"src": "./img/icons/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/android-chrome-maskable-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/android-chrome-maskable-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/apple-touch-icon-60x60.png",
|
||||
"sizes": "60x60",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/apple-touch-icon-76x76.png",
|
||||
"sizes": "76x76",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/apple-touch-icon-120x120.png",
|
||||
"sizes": "120x120",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/apple-touch-icon-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/apple-touch-icon-180x180.png",
|
||||
"sizes": "180x180",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/apple-touch-icon.png",
|
||||
"sizes": "180x180",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/favicon-16x16.png",
|
||||
"sizes": "16x16",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/favicon-32x32.png",
|
||||
"sizes": "32x32",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/msapplication-icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/mstile-150x150.png",
|
||||
"sizes": "150x150",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
ui/public/silent-renew-oidc.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
248
ui/src/App.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<v-app class="background">
|
||||
<v-navigation-drawer dark permanent :mini-variant="mini" :expand-on-hover="mini" app color="statusbar">
|
||||
<v-list>
|
||||
<v-list-item class="px-2" :to="{ name: 'Dashboard' }">
|
||||
<v-list-item-avatar rounded="0">
|
||||
<v-img src="/flask_white.svg" :width="40"></v-img>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="title">
|
||||
Catalyst
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<!--v-list dense nav>
|
||||
<v-list-item class="px-0" dense :to="{ name: 'Profile' }">
|
||||
<v-list-item-avatar>
|
||||
<v-img v-if="$store.state.userdata.image" :src="$store.state.userdata.image"></v-img>
|
||||
<v-icon v-else>mdi-account-circle</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<div v-if="$store.state.user">
|
||||
{{ $store.state.userdata.name }}
|
||||
</div>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider></v-divider-->
|
||||
|
||||
<v-list nav dense>
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon class="my-1">mdi-arrow-right-bold</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>
|
||||
<v-text-field
|
||||
placeholder="Goto"
|
||||
outlined
|
||||
dense
|
||||
hide-details
|
||||
v-on:keyup.enter="enter"
|
||||
clearable
|
||||
color="#fff"
|
||||
v-model="goto"></v-text-field>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider></v-divider>
|
||||
|
||||
<AppLink :links="internal"></AppLink>
|
||||
|
||||
<v-list nav dense v-if="$store.state.settings.ticketTypes">
|
||||
<v-list-item
|
||||
v-for="customType in $store.state.settings.ticketTypes"
|
||||
:key="customType.id"
|
||||
link
|
||||
:class="{ 'v-list-item--active': ($route.params.type === customType.id) }"
|
||||
@click="openTicketList(customType.id)">
|
||||
<v-list-item-icon>
|
||||
<v-badge
|
||||
v-if="customType.id in counts && counts[customType.id] > 0"
|
||||
:content="counts[customType.id]"
|
||||
color="red"
|
||||
left
|
||||
offset-x="35"
|
||||
offset-y="8"
|
||||
bottom>
|
||||
<v-icon>{{ customType.icon }}</v-icon>
|
||||
</v-badge>
|
||||
<v-icon v-else>{{ customType.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>{{ customType.name }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
<AppLink :links="settings"></AppLink>
|
||||
|
||||
<template v-slot:append>
|
||||
|
||||
<v-list nav dense>
|
||||
<v-list-item class="version" dense style="min-height: 20px">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title style="text-align: center; opacity: 0.5;">
|
||||
{{ $store.state.settings.tier }} v{{ $store.state.settings.version }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider></v-divider>
|
||||
<v-list nav dense>
|
||||
|
||||
<v-list-item :to="{ name: 'API' }">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-share-variant</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>API Documentation</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
|
||||
<v-app-bar app dense flat absolute color="transparent">
|
||||
<v-btn icon @click="mini = !mini">
|
||||
<v-icon color="primary">mdi-menu</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-btn :to="{ name: 'Profile' }" icon>
|
||||
<v-avatar v-if="$store.state.userdata.image" size="32">
|
||||
<v-img :src="$store.state.userdata.image"></v-img>
|
||||
</v-avatar>
|
||||
<v-icon v-else>mdi-account-circle</v-icon>
|
||||
</v-btn>
|
||||
|
||||
</v-app-bar>
|
||||
<div>
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
<v-snackbar v-model="snackbar" :color="$store.state.alert.type" :timeout="$store.state.alert.type === 'error' ? -1 : 5000" outlined>
|
||||
<b style="display: block">{{ $store.state.alert.name | capitalize }}</b>
|
||||
{{ $store.state.alert.detail }}
|
||||
<template v-slot:action="{ attrs }">
|
||||
<v-btn text v-bind="attrs" @click="snackbar = false">Close</v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import AppLink from "./components/AppLink.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "App",
|
||||
components: {AppLink},
|
||||
data: () => ({
|
||||
settings: [
|
||||
{ icon: "mdi-format-list-bulleted-type", name: "Ticket Types", to: "TicketTypeList", role: "engineer:tickettype:write" },
|
||||
{ icon: "mdi-file-hidden", name: "Templates", to: "TemplateList", role: "analyst:template:read" },
|
||||
{ icon: "mdi-file-cog-outline", name: "Playbooks", to: "PlaybookList", role: "analyst:playbook:read" },
|
||||
{ icon: "mdi-flash", name: "Automations", to: "AutomationList", role: "analyst:automation:read" },
|
||||
{ icon: "mdi-filter", name: "Ingestion Rules", to: "RuleList", role: "analyst:rule:read", tier: "enterprise" },
|
||||
{ icon: "mdi-account", name: "Users & API Keys", to: "UserList", role: "admin:user:write" },
|
||||
{ icon: "mdi-account-group", name: "Groups", to: "GroupList", role: "admin:group:write", tier: "enterprise" },
|
||||
{ icon: "mdi-cogs", name: "User Data", to: "UserDataList", role: "admin:userdata:write" },
|
||||
{ icon: "mdi-format-list-checks", name: "Jobs", to: "JobList", role: "admin:job:write" },
|
||||
],
|
||||
mini: false,
|
||||
goto: "",
|
||||
|
||||
snackbar: false,
|
||||
}),
|
||||
watch: {
|
||||
showAlert: function () {
|
||||
this.snackbar = true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
counts: function (): number {
|
||||
return this.$store.state.counts
|
||||
},
|
||||
internal: function (): Array<any> {
|
||||
return [
|
||||
{ icon: "mdi-check-bold", name: "Open Tasks", to: "TaskList", count: this.$store.state.task_count },
|
||||
]
|
||||
},
|
||||
showAlert: function (): boolean {
|
||||
return this.$store.state.showAlert
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
enter: function () {
|
||||
if (!this.goto) {
|
||||
return
|
||||
}
|
||||
this.$router.push({
|
||||
name: "Ticket",
|
||||
params: { id: this.goto.toString() }
|
||||
});
|
||||
},
|
||||
openTicketList: function (type: string) {
|
||||
this.$router.push({ name: "TicketList", params: { type: type } })
|
||||
},
|
||||
hasRole: function (s: string) {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch("getUser");
|
||||
this.$store.dispatch("getUserData");
|
||||
this.$store.dispatch("getSettings");
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.background {
|
||||
background-color: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
.v-app-bar.v-toolbar--dense .v-toolbar__content {
|
||||
border-bottom: 1px solid #e0e0e0 !important;
|
||||
}
|
||||
|
||||
.theme--dark.background {
|
||||
background-color: #303030 !important;
|
||||
}
|
||||
|
||||
.theme--dark h1,
|
||||
.theme--dark h2,
|
||||
.theme--dark h3,
|
||||
.theme--dark h4 {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.theme--dark.v-btn:hover::before {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.theme--dark .v-application .primary--text {
|
||||
text-shadow: 0 0 3px #FFC107; /* #00bcd4;/* 0 0 3px #ffff00; */
|
||||
}
|
||||
|
||||
.theme--dark .glow,
|
||||
.theme--dark .v-list .v-list-item--active,
|
||||
.theme--dark.v-btn:hover,
|
||||
.theme--dark a:hover {
|
||||
color: #FFC107 !important; /* #00bcd4 !important;/* #ffff00 !important; */
|
||||
text-shadow: 0 0 3px #FFC107 !important; /* #00bcd4 !important;/* 0 0 3px #ffff00 !important; */
|
||||
}
|
||||
|
||||
/* box-shadow: 0 0 8px rgba(255, 255, 0, 0.2) !important; */
|
||||
|
||||
.v-navigation-drawer--mini-variant .version {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
}
|
||||
</style>
|
||||
1
ui/src/client/.npmignore
Normal file
@@ -0,0 +1 @@
|
||||
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
|
||||
8104
ui/src/client/api.ts
Normal file
71
ui/src/client/base.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
*
|
||||
* API for the catalyst incident response platform.
|
||||
*
|
||||
* The version of the OpenAPI document:
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import { Configuration } from "./configuration";
|
||||
// Some imports not used depending on template conditions
|
||||
// @ts-ignore
|
||||
import globalAxios, { AxiosPromise, AxiosInstance } from 'axios';
|
||||
|
||||
export const BASE_PATH = "http://./api".replace(/\/+$/, "");
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const COLLECTION_FORMATS = {
|
||||
csv: ",",
|
||||
ssv: " ",
|
||||
tsv: "\t",
|
||||
pipes: "|",
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface RequestArgs
|
||||
*/
|
||||
export interface RequestArgs {
|
||||
url: string;
|
||||
options: any;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @class BaseAPI
|
||||
*/
|
||||
export class BaseAPI {
|
||||
protected configuration: Configuration | undefined;
|
||||
|
||||
constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) {
|
||||
if (configuration) {
|
||||
this.configuration = configuration;
|
||||
this.basePath = configuration.basePath || this.basePath;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @class RequiredError
|
||||
* @extends {Error}
|
||||
*/
|
||||
export class RequiredError extends Error {
|
||||
name: "RequiredError" = "RequiredError";
|
||||
constructor(public field: string, msg?: string) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
138
ui/src/client/common.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
*
|
||||
* API for the catalyst incident response platform.
|
||||
*
|
||||
* The version of the OpenAPI document:
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
import { Configuration } from "./configuration";
|
||||
import { RequiredError, RequestArgs } from "./base";
|
||||
import { AxiosInstance } from 'axios';
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const DUMMY_BASE_URL = 'https://example.com'
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws {RequiredError}
|
||||
* @export
|
||||
*/
|
||||
export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) {
|
||||
if (paramValue === null || paramValue === undefined) {
|
||||
throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) {
|
||||
if (configuration && configuration.apiKey) {
|
||||
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
|
||||
? await configuration.apiKey(keyParamName)
|
||||
: await configuration.apiKey;
|
||||
object[keyParamName] = localVarApiKeyValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setBasicAuthToObject = function (object: any, configuration?: Configuration) {
|
||||
if (configuration && (configuration.username || configuration.password)) {
|
||||
object["auth"] = { username: configuration.username, password: configuration.password };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) {
|
||||
if (configuration && configuration.accessToken) {
|
||||
const accessToken = typeof configuration.accessToken === 'function'
|
||||
? await configuration.accessToken()
|
||||
: await configuration.accessToken;
|
||||
object["Authorization"] = "Bearer " + accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) {
|
||||
if (configuration && configuration.accessToken) {
|
||||
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
|
||||
? await configuration.accessToken(name, scopes)
|
||||
: await configuration.accessToken;
|
||||
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const setSearchParams = function (url: URL, ...objects: any[]) {
|
||||
const searchParams = new URLSearchParams(url.search);
|
||||
for (const object of objects) {
|
||||
for (const key in object) {
|
||||
if (Array.isArray(object[key])) {
|
||||
searchParams.delete(key);
|
||||
for (const item of object[key]) {
|
||||
searchParams.append(key, item);
|
||||
}
|
||||
} else {
|
||||
searchParams.set(key, object[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
url.search = searchParams.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
|
||||
const nonString = typeof value !== 'string';
|
||||
const needsSerialization = nonString && configuration && configuration.isJsonMime
|
||||
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
|
||||
: nonString;
|
||||
return needsSerialization
|
||||
? JSON.stringify(value !== undefined ? value : {})
|
||||
: (value || "");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const toPathString = function (url: URL) {
|
||||
return url.pathname + url.search + url.hash
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) {
|
||||
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||
const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url};
|
||||
return axios.request(axiosRequestArgs);
|
||||
};
|
||||
}
|
||||
101
ui/src/client/configuration.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
*
|
||||
* API for the catalyst incident response platform.
|
||||
*
|
||||
* The version of the OpenAPI document:
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
export interface ConfigurationParameters {
|
||||
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
||||
username?: string;
|
||||
password?: string;
|
||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
||||
basePath?: string;
|
||||
baseOptions?: any;
|
||||
formDataCtor?: new () => any;
|
||||
}
|
||||
|
||||
export class Configuration {
|
||||
/**
|
||||
* parameter for apiKey security
|
||||
* @param name security name
|
||||
* @memberof Configuration
|
||||
*/
|
||||
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
||||
/**
|
||||
* parameter for basic security
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
username?: string;
|
||||
/**
|
||||
* parameter for basic security
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
password?: string;
|
||||
/**
|
||||
* parameter for oauth2 security
|
||||
* @param name security name
|
||||
* @param scopes oauth2 scope
|
||||
* @memberof Configuration
|
||||
*/
|
||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
||||
/**
|
||||
* override base path
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
basePath?: string;
|
||||
/**
|
||||
* base options for axios calls
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof Configuration
|
||||
*/
|
||||
baseOptions?: any;
|
||||
/**
|
||||
* The FormData constructor that will be used to create multipart form data
|
||||
* requests. You can inject this here so that execution environments that
|
||||
* do not support the FormData class can still run the generated client.
|
||||
*
|
||||
* @type {new () => FormData}
|
||||
*/
|
||||
formDataCtor?: new () => any;
|
||||
|
||||
constructor(param: ConfigurationParameters = {}) {
|
||||
this.apiKey = param.apiKey;
|
||||
this.username = param.username;
|
||||
this.password = param.password;
|
||||
this.accessToken = param.accessToken;
|
||||
this.basePath = param.basePath;
|
||||
this.baseOptions = param.baseOptions;
|
||||
this.formDataCtor = param.formDataCtor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given MIME is a JSON MIME.
|
||||
* JSON MIME examples:
|
||||
* application/json
|
||||
* application/json; charset=UTF8
|
||||
* APPLICATION/JSON
|
||||
* application/vnd.company+json
|
||||
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
||||
* @return True if the given MIME is JSON, false otherwise.
|
||||
*/
|
||||
public isJsonMime(mime: string): boolean {
|
||||
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
|
||||
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
|
||||
}
|
||||
}
|
||||
18
ui/src/client/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
*
|
||||
* API for the catalyst incident response platform.
|
||||
*
|
||||
* The version of the OpenAPI document:
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
export * from "./api";
|
||||
export * from "./configuration";
|
||||
|
||||
195
ui/src/components/AdvancedJSONSchemaEditor.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex" >
|
||||
<v-spacer></v-spacer>
|
||||
<v-switch
|
||||
v-model="advanced"
|
||||
label="Advanced"
|
||||
class="float-right mt-0"
|
||||
></v-switch>
|
||||
</div>
|
||||
<div class="d-flex" >
|
||||
<v-spacer></v-spacer>
|
||||
<span v-if="advanced" class="float-right">
|
||||
See
|
||||
<a target="_blank" href="https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/">
|
||||
vuetify-jsonschema documentation
|
||||
</a>
|
||||
for styling.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<v-row class="flex-grow-0 flex-shrink-0">
|
||||
<v-col :cols="hidepreview ? 12 : 7">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
|
||||
Schema
|
||||
</v-subheader>
|
||||
<div v-if="!advanced">
|
||||
<json-schema-editor :disabled="readonly" :value="{ root: internalSchema }" lang="en_US" style="border: 1px solid #393a3f" class="mb-3 rounded" />
|
||||
</div>
|
||||
<div v-else class="flex-grow-1 flex-shrink-1 overflow-scroll">
|
||||
<Editor v-model="schemaString" lang="json" :readonly="readonly"></Editor>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col v-if="!hidepreview" cols="5">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
|
||||
Form output preview
|
||||
</v-subheader>
|
||||
<v-form v-model="valid">
|
||||
<v-jsf
|
||||
v-model="details"
|
||||
:schema="advanced ? parsedSchemaString : internalSchema"
|
||||
:options="{ readonly: true, formats: { time: timeformat, date: dateformat, 'date-time': datetimeformat } }"
|
||||
/>
|
||||
</v-form>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-if="!readonly" class="px-3 my-6 flex-grow-0 flex-shrink-0">
|
||||
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
|
||||
<v-icon>mdi-plus-thick</v-icon>
|
||||
Create
|
||||
</v-btn>
|
||||
<v-btn v-else color="success" @click="save" outlined>
|
||||
<v-icon>mdi-content-save</v-icon>
|
||||
Save
|
||||
</v-btn>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Editor from "./Editor.vue";
|
||||
import Vue from "vue";
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
interface State {
|
||||
advanced: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
internalSchema: any;
|
||||
schemaString: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
details: any;
|
||||
valid: boolean;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "AdvancedJSONSchemaEditor",
|
||||
components: { Editor },
|
||||
props: {
|
||||
schema: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
hidepreview: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data: (): State => ({
|
||||
details: {},
|
||||
advanced: false,
|
||||
internalSchema: {},
|
||||
schemaString: "{}",
|
||||
valid: true,
|
||||
}),
|
||||
watch: {
|
||||
schema: function () {
|
||||
this.internalSchema = this.schema;
|
||||
this.schemaString = JSON.stringify(this.internalSchema, null, 2);
|
||||
},
|
||||
advanced: function (advanced) {
|
||||
if (advanced) {
|
||||
this.schemaString = JSON.stringify(this.internalSchema, null, 2);
|
||||
} else {
|
||||
this.internalSchema = JSON.parse(this.schemaString);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
parsedSchemaString: function() {
|
||||
try {
|
||||
return JSON.parse(this.schemaString);
|
||||
}
|
||||
catch (e) {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
save: function () {
|
||||
let schema = this.schemaString;
|
||||
if (!this.advanced) {
|
||||
schema = JSON.stringify(this.internalSchema);
|
||||
}
|
||||
this.$emit("save", schema);
|
||||
},
|
||||
timeformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
dateformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
datetimeformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.internalSchema = this.schema;
|
||||
this.schemaString = JSON.stringify(this.internalSchema, null, 2);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.theme--dark .ant-btn,
|
||||
.theme--dark .ant-select-selection,
|
||||
.theme--dark .ant-input,
|
||||
.theme--dark .ant-input-number,
|
||||
.theme--dark .ant-modal-header,
|
||||
.theme--dark .ant-modal-title,
|
||||
.theme--dark .ant-form-item,
|
||||
.theme--dark .ant-modal-close-x,
|
||||
.theme--dark .ant-select-dropdown,
|
||||
.theme--dark .ant-checkbox-inner {
|
||||
color: white !important;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.theme--dark .ant-select-selection,
|
||||
.theme--dark .ant-input,
|
||||
.theme--dark .ant-input-number,
|
||||
.theme--dark .ant-modal-header,
|
||||
.theme--dark .ant-modal-footer,
|
||||
.theme--dark .ant-checkbox-inner {
|
||||
border-color: #424242 !important;
|
||||
}
|
||||
|
||||
.theme--dark .ant-modal-content,
|
||||
.theme--dark .ant-select-dropdown {
|
||||
color: white !important;
|
||||
background: #303030 !important;
|
||||
}
|
||||
</style>
|
||||
64
ui/src/components/AppLink.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-list nav dense>
|
||||
<v-list-item v-for="link in userLinks" :key="link.to" link :to="{ name: link.to }">
|
||||
<v-list-item-icon>
|
||||
<v-badge
|
||||
v-if="'count' in link && link.count"
|
||||
:content="link.count"
|
||||
color="red"
|
||||
left
|
||||
offset-x="35"
|
||||
offset-y="8"
|
||||
bottom>
|
||||
<v-icon>{{ link.icon }}</v-icon>
|
||||
</v-badge>
|
||||
<v-icon v-else>{{ link.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>{{ link.name }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider v-if="userLinks.length > 0"></v-divider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "AppLink",
|
||||
props: ["links"],
|
||||
computed: {
|
||||
userLinks: function (): Array<any> {
|
||||
return this.lodash.filter(this.links, link => {
|
||||
return this.hasRole(link) && this.hasTier(link)
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasRole: function (link: any) {
|
||||
if (!("role" in link)) {
|
||||
return true;
|
||||
}
|
||||
let has = false;
|
||||
if (this.$store.state.user.roles) {
|
||||
this.lodash.forEach(this.$store.state.user.roles, (userRole) => {
|
||||
if (link.role === userRole || this.lodash.startsWith(link.role, userRole + ":")) {
|
||||
has = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
return has;
|
||||
},
|
||||
hasTier: function (link: any): boolean {
|
||||
if ("tier" in link) {
|
||||
if (this.$store.state.settings.tier) {
|
||||
return this.$store.state.settings.tier == link.tier;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
115
ui/src/components/Editor.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<prism-editor
|
||||
v-if="showEditor"
|
||||
class="my-editor"
|
||||
v-model="code"
|
||||
:highlight="highlighter"
|
||||
line-numbers
|
||||
:readonly="readonly">
|
||||
</prism-editor>
|
||||
|
||||
<!--MonacoEditor
|
||||
v-if="showEditor"
|
||||
ref="editor"
|
||||
class="editor"
|
||||
style="height: 100%"
|
||||
v-model="code"
|
||||
:language="this.lang"
|
||||
:options="{ scrollBeyondLastLine: false }"
|
||||
:theme="$vuetify.theme.dark ? 'vs-dark' : 'vs'"
|
||||
/-->
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
// import MonacoEditor from "vue-monaco";
|
||||
|
||||
import { PrismEditor } from 'vue-prism-editor';
|
||||
import 'vue-prism-editor/dist/prismeditor.min.css'; // import the styles somewhere
|
||||
|
||||
import { highlight, languages } from 'prismjs/components/prism-core';
|
||||
// import 'prismjs/components/prism-javascript';
|
||||
import 'prismjs/components/prism-json';
|
||||
import 'prismjs/components/prism-python';
|
||||
import 'prismjs/components/prism-yaml';
|
||||
import 'prismjs/components/prism-markup';
|
||||
import 'prismjs/components/prism-log';
|
||||
import 'prismjs/themes/prism-tomorrow.css'; // import syntax highlighting styles
|
||||
|
||||
interface State {
|
||||
showEditor: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
resize?: any;
|
||||
code: string,
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Editor",
|
||||
props: ["value", "lang", "readonly"],
|
||||
components: {PrismEditor},
|
||||
data: (): State => ({
|
||||
showEditor: true,
|
||||
resize: undefined,
|
||||
code: "",
|
||||
}),
|
||||
watch: {
|
||||
code: function () {
|
||||
this.$emit('input', this.code);
|
||||
},
|
||||
value: function () {
|
||||
this.code = this.value;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// resizeEditor() {
|
||||
// this.showEditor = false;
|
||||
// this.$nextTick(() => {
|
||||
// this.showEditor = true;
|
||||
// });
|
||||
// },
|
||||
highlighter(code: string) {
|
||||
switch (this.lang) {
|
||||
case "python":
|
||||
return highlight(code, languages.python);
|
||||
case "log":
|
||||
return highlight(code, languages.log);
|
||||
case "yaml":
|
||||
return highlight(code, languages.yaml);
|
||||
case "json":
|
||||
return highlight(code, languages.json);
|
||||
case "html":
|
||||
return highlight(code, languages.html);
|
||||
}
|
||||
return highlight(code, languages.json);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.code = this.value;
|
||||
// this.resize = this.lodash.debounce(this.resizeEditor, 200);
|
||||
// window.addTicketListener("resize", this.resize);
|
||||
},
|
||||
destroyed() {
|
||||
// window.removeticketListener("resize", this.resize);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* required class */
|
||||
.my-editor {
|
||||
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
|
||||
background: #2d2d2d;
|
||||
color: #ccc;
|
||||
|
||||
/* you must provide font-family font-size line-height. Example: */
|
||||
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* optional class for removing the outline */
|
||||
.prism-editor__textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
20
ui/src/components/JSONHTML.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="(value, key) in json" :key="key">
|
||||
<dl v-if="typeof(value) == 'object'">
|
||||
<dt>{{ key }}</dt>
|
||||
<dd><JSONHTML :json="value"></JSONHTML></dd>
|
||||
</dl>
|
||||
<span v-else>
|
||||
<b>{{ key }}</b>: {{ value }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "JSONHTML",
|
||||
props: ["json"]
|
||||
}
|
||||
</script>
|
||||
153
ui/src/components/List.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<v-row class="fill-height ma-0">
|
||||
<v-col cols="3" class="listnav" style="">
|
||||
<v-list nav color="background">
|
||||
<v-list-item
|
||||
v-if="showNew && canWrite"
|
||||
:to="{ name: routername, params: { id: 'new' } }"
|
||||
class="mt-4 mx-4 text-center newbutton"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
<v-icon small>mdi-plus</v-icon> New {{ singular }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-subheader class="pl-4">{{ plural }}</v-subheader>
|
||||
<v-list-item
|
||||
v-for="item in (items ? items : [])"
|
||||
:key="item[itemid]"
|
||||
link
|
||||
:to="{ name: routername, params: { id: item[itemid] } }"
|
||||
class="mx-2"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ item[itemname] }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-action v-if="deletable && canWrite">
|
||||
<v-icon @click="askDelete(item[itemid])" class="fader">
|
||||
mdi-close
|
||||
</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-col>
|
||||
<v-col cols="9">
|
||||
<router-view></router-view>
|
||||
</v-col>
|
||||
<v-dialog v-model="dialog" persistent max-width="400">
|
||||
<v-card>
|
||||
<v-card-title> Delete {{ singular }} {{ deleteName }} ? </v-card-title>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="error" text @click="dialog = false">Cancel</v-btn>
|
||||
<v-btn color="success" outlined @click="deleteItem(deleteName)">Delete</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
interface State {
|
||||
dialog: boolean;
|
||||
deleteName?: string;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "List",
|
||||
components: { },
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
routername: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
itemid: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
itemname: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
singular: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
plural: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
showNew: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
deletable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
writepermission: {
|
||||
type: String,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data: (): State => ({
|
||||
dialog: false,
|
||||
deleteName: undefined,
|
||||
}),
|
||||
computed: {
|
||||
canWrite: function (): boolean {
|
||||
return this.hasRole(this.writepermission);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
askDelete(name: string) {
|
||||
this.deleteName = name;
|
||||
this.dialog = true;
|
||||
},
|
||||
deleteItem(deleteName: string) {
|
||||
this.$emit('delete', deleteName);
|
||||
this.dialog = false;
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.listnav {
|
||||
border-right: 1px solid #e0e0e0;
|
||||
}
|
||||
.theme--dark .listnav {
|
||||
border-right: 1px solid #393a3f;
|
||||
}
|
||||
|
||||
.newbutton {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
.theme--dark .newbutton {
|
||||
background: #424242;
|
||||
}
|
||||
|
||||
.v-list-item .fader {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.v-list-item:hover .fader {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
</style>
|
||||
325
ui/src/components/TicketList.vue
Normal file
@@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row v-if="type">
|
||||
<v-col cols="12">
|
||||
<v-btn elevation="0" rounded class="float-right" :to="{ name: 'TicketNew', params: { type: type } }">
|
||||
<v-icon class="mr-1">mdi-plus</v-icon>
|
||||
New {{ type | capitalize }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-toolbar
|
||||
rounded
|
||||
filled
|
||||
dense
|
||||
flat
|
||||
elevation="0"
|
||||
style="border-radius: 40px !important;"
|
||||
>
|
||||
<v-btn-toggle dense v-model="defaultcaql">
|
||||
<v-btn
|
||||
text
|
||||
color="primary"
|
||||
@click="caql = !caql"
|
||||
rounded
|
||||
style="border-radius: 40px !important;">
|
||||
CAQL
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
|
||||
<v-text-field
|
||||
placeholder="Search term or query (e.g. name == 'malware' AND 'wannacry')"
|
||||
v-model="term"
|
||||
dense
|
||||
solo
|
||||
flat
|
||||
hide-details
|
||||
clearable
|
||||
append-icon="mdi-magnify"
|
||||
@click:clear="clear"
|
||||
@click:append="loadTickets"
|
||||
@keydown.enter="loadTickets"
|
||||
:rules="[validate]"
|
||||
@focus="focus = true"
|
||||
@blur="blur"
|
||||
></v-text-field>
|
||||
</v-toolbar>
|
||||
|
||||
<span v-if="focus && caql">CAQL Query Suggestions</span>
|
||||
<v-list class="mb-2" v-if="focus && caql">
|
||||
<v-list-item v-for="example in examples" :key="example.q" dense link @click="term = example.q; caql = true; defaultcaql = 0; loadTickets()">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
<v-row>
|
||||
<span class="col-6">{{ example.q }}</span> <span class="text--disabled col-6">{{ example.desc }}</span>
|
||||
</v-row>
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-list-item-content>
|
||||
Fields: {{ lodash.join(fields, ", ") }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="tickets"
|
||||
item-key="name"
|
||||
multi-sort
|
||||
class="elevation-0 cards clickable mt-2"
|
||||
:options.sync="options"
|
||||
:server-items-length="totalTickets"
|
||||
:loading="loading"
|
||||
:footer-props="{ 'items-per-page-options': [10, 25, 50, 100] }"
|
||||
>
|
||||
<template v-slot:item="{ item }">
|
||||
<tr @click="open(item)">
|
||||
<td colspan="5">
|
||||
<ticketSnippet :ticket="item" class="pa-0"></ticketSnippet>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { Ticket } from "@/client";
|
||||
import { API } from "@/services/api";
|
||||
import TicketSnippet from "../components/snippets/TicketSnippet.vue";
|
||||
import {validateCAQL} from "@/suggestions/suggestions";
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
interface State {
|
||||
term: string;
|
||||
loading: boolean;
|
||||
tickets: Array<Ticket>;
|
||||
totalTickets: number;
|
||||
options: {
|
||||
page?: number;
|
||||
itemsPerPage?: number;
|
||||
sortBy?: string[];
|
||||
sortDesc?: boolean[];
|
||||
groupBy?: string[];
|
||||
groupDesc?: boolean[];
|
||||
multiSort?: boolean;
|
||||
mustSort?: boolean;
|
||||
};
|
||||
focus: boolean;
|
||||
caql: boolean;
|
||||
defaultcaql?: number;
|
||||
}
|
||||
|
||||
interface QuerySuggestion {
|
||||
q: string;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "TicketList",
|
||||
components: {
|
||||
TicketSnippet,
|
||||
},
|
||||
props: ["type", "query"],
|
||||
data: (): State => ({
|
||||
term: "status == 'open'",
|
||||
loading: true,
|
||||
tickets: [],
|
||||
totalTickets: 0,
|
||||
options: {
|
||||
itemsPerPage: 10,
|
||||
},
|
||||
focus: false,
|
||||
caql: true,
|
||||
defaultcaql: 0,
|
||||
}),
|
||||
computed: {
|
||||
fields(): Array<string> {
|
||||
return [
|
||||
"type", "id", "name",
|
||||
"status" , "owner",
|
||||
"created", "modified",
|
||||
"details", "details.description", "details.…",
|
||||
"schema",
|
||||
"comments", "comments.#.created", "comments.#.creator", "comments.#.message",
|
||||
"playbooks", "playbooks.#.name", "playbooks.#.tasks",
|
||||
"references", "references.#.href", "references.#.name",
|
||||
"artifacts", "artifacts.#.name", "artifacts.#.status", "artifacts.#.type",
|
||||
"files", "files.#.name"
|
||||
];
|
||||
},
|
||||
user(): string {
|
||||
return this.$store.state.user.id
|
||||
},
|
||||
headers() {
|
||||
return [
|
||||
{
|
||||
text: "Name",
|
||||
align: "start",
|
||||
value: "name",
|
||||
},
|
||||
{
|
||||
text: "Status",
|
||||
align: "start",
|
||||
value: "status",
|
||||
},
|
||||
{
|
||||
text: "Owner",
|
||||
align: "start",
|
||||
value: "owner",
|
||||
},
|
||||
{
|
||||
text: "Creation",
|
||||
align: "start",
|
||||
value: "created",
|
||||
},
|
||||
{
|
||||
text: "Last Modification",
|
||||
align: "start",
|
||||
value: "modified",
|
||||
},
|
||||
];
|
||||
},
|
||||
examples (): Array<QuerySuggestion> {
|
||||
let twoWeeksAgo = DateTime.utc().minus({weeks: 2}).toFormat("yyyy-MM-dd");
|
||||
|
||||
let ex: Array<QuerySuggestion> = [];
|
||||
|
||||
if (this.user) {
|
||||
ex.push({q: "status == 'open' AND (owner == '" + this.user + "' OR !owner)", desc: "Select all open tickets by you and unassigned"})
|
||||
ex.push({q: "status == 'closed' AND owner == '" + this.user + "'", desc: "Select completed tickets by you"})
|
||||
} else {
|
||||
ex.push({q: "status == 'open'", desc: "Select all open tickets"})
|
||||
ex.push({q: "status == 'closed'", desc: "Select completed tickets"})
|
||||
}
|
||||
|
||||
ex.push({q: "created > \""+twoWeeksAgo+"\"", desc: "Select tickets created in the last two weeks"})
|
||||
|
||||
if (this.term && this.term.match(/^[A-Za-z ]+$/)) {
|
||||
ex.unshift({q: "'" + this.term + "'", desc: "Full text search for '" + this.term + "'"})
|
||||
}
|
||||
return ex;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
handler() {
|
||||
this.loadTickets();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
$route: function () {
|
||||
this.loadTickets();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
blur: function () {
|
||||
setTimeout(()=>{this.focus = false}, 200)
|
||||
},
|
||||
clear: function () {
|
||||
this.caql = false;
|
||||
this.defaultcaql = undefined;
|
||||
this.term = "";
|
||||
this.loadTickets();
|
||||
},
|
||||
open: function (ticket: Ticket) {
|
||||
this.$emit("click", ticket);
|
||||
},
|
||||
select: function (e: string) {
|
||||
this.loadTerm(e);
|
||||
},
|
||||
loadTickets() {
|
||||
let term = this.term;
|
||||
if (!term) {
|
||||
term = "";
|
||||
}
|
||||
this.loadTerm(term);
|
||||
},
|
||||
loadTerm(term: string) {
|
||||
this.loading = true;
|
||||
let offset = 0;
|
||||
let count = 25;
|
||||
let sortBy: Array<string> = [];
|
||||
let sortDesc: Array<boolean> = [];
|
||||
if (this.options.itemsPerPage !== undefined) {
|
||||
count = this.options.itemsPerPage;
|
||||
if (this.options.page !== undefined) {
|
||||
offset = (this.options.page - 1) * this.options.itemsPerPage;
|
||||
}
|
||||
}
|
||||
if (this.options.sortBy !== undefined) {
|
||||
sortBy = this.options.sortBy;
|
||||
}
|
||||
if (this.options.sortDesc !== undefined) {
|
||||
sortDesc = this.options.sortDesc;
|
||||
}
|
||||
|
||||
let t = this.type;
|
||||
if (!t) {
|
||||
t = "";
|
||||
}
|
||||
|
||||
if (!this.caql && this.term.length > 0) {
|
||||
term = "'" + this.lodash.join(this.lodash.split(term, " "), "'&&'") + "'"
|
||||
}
|
||||
|
||||
API.listTickets(t, offset, count, sortBy, sortDesc, term)
|
||||
.then((response) => {
|
||||
if (response.data.tickets) {
|
||||
this.tickets = response.data.tickets;
|
||||
} else {
|
||||
this.tickets = [];
|
||||
}
|
||||
this.totalTickets = response.data.count;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
|
||||
},
|
||||
validate: function () {
|
||||
if (!this.term) {
|
||||
return true
|
||||
}
|
||||
let err = validateCAQL(this.term);
|
||||
if (err !== null) {
|
||||
return err.message;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.user) {
|
||||
this.term = "status == 'open' AND (owner == '" + this.user + "' OR !owner)";
|
||||
} else {
|
||||
this.term = "status == 'open'";
|
||||
}
|
||||
|
||||
if (this.query) {
|
||||
this.term = this.query;
|
||||
}
|
||||
|
||||
this.loadTickets();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.clickable td {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
.vue-simple-suggest.designed .input-wrapper input {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
color: #fff;
|
||||
}
|
||||
.vue-simple-suggest.designed .suggestions {
|
||||
background-color: #333 !important;
|
||||
top: 60px !important;
|
||||
border: 1px solid #ddd !important;
|
||||
}
|
||||
</style>
|
||||
139
ui/src/components/Timeline.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-textarea
|
||||
v-model="comment"
|
||||
hide-details
|
||||
flat
|
||||
label="Add a comment..."
|
||||
solo
|
||||
auto-grow
|
||||
rows="2"
|
||||
class="py-2"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-btn class="mx-0 mt-n1" text @click="addTicketLog">
|
||||
<v-icon>mdi-send</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-textarea>
|
||||
<div
|
||||
v-for="(log, id) in internalLogs"
|
||||
:key="id"
|
||||
:icon="icon(log.type)"
|
||||
:small="small(log.type)"
|
||||
class="pb-2"
|
||||
>
|
||||
<v-card v-if="log.type === 'comment'" elevation="0" color="cards">
|
||||
<v-card-subtitle class="pb-0">
|
||||
<strong> {{ log.creator }}</strong>
|
||||
<span class="text--disabled ml-3" :title="log.created">
|
||||
{{ relDate(log.created) }}
|
||||
</span>
|
||||
</v-card-subtitle>
|
||||
<v-card-text class="mb-0 mt-2">
|
||||
<!--{{ log.message }}-->
|
||||
<vue-markdown v-if="show">{{ log.message }}</vue-markdown>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<div v-else style="line-height: 24px" class="d-flex flex-row">
|
||||
<v-divider class="mt-3 mr-3"></v-divider>
|
||||
{{ log.message }}
|
||||
<span class="text--disabled ml-1" :title="log.created">
|
||||
·
|
||||
{{ log.creator }} ·
|
||||
{{ relDate(log.created) }}
|
||||
</span>
|
||||
<v-divider class="mt-3 ml-3"></v-divider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { LogEntry } from "@/client";
|
||||
import VueMarkdown from "vue-markdown";
|
||||
import { API } from "@/services/api";
|
||||
|
||||
interface State {
|
||||
comment: string
|
||||
internalLogs: Array<LogEntry>
|
||||
show: boolean
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Timeline",
|
||||
components: {
|
||||
"vue-markdown": VueMarkdown
|
||||
},
|
||||
props: ["id", "logs"],
|
||||
data: (): State => ({
|
||||
comment: "",
|
||||
internalLogs: [],
|
||||
show: true
|
||||
}),
|
||||
watch: {
|
||||
logs: function () {
|
||||
// this.internalLogs = this.logs;
|
||||
this.reload(this.logs);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reload: function(newlogs: Array<LogEntry>) {
|
||||
if (newlogs === undefined) {
|
||||
return
|
||||
}
|
||||
this.show = false;
|
||||
Vue.nextTick(() => {
|
||||
this.internalLogs = newlogs;
|
||||
this.show = true;
|
||||
})
|
||||
},
|
||||
icon: function(s: string) {
|
||||
switch (s) {
|
||||
case "comment":
|
||||
return "mdi-comment";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
small: function(s: string) {
|
||||
switch (s) {
|
||||
case "comment":
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
relDate: function(date: string) {
|
||||
let rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
let deltaDays =
|
||||
(new Date(date).getTime() - new Date().getTime()) / (1000 * 3600 * 24);
|
||||
let relDate = rtf.format(Math.round(deltaDays), "days");
|
||||
if (deltaDays > -3) {
|
||||
relDate +=
|
||||
", " +
|
||||
new Date(date).toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
});
|
||||
}
|
||||
return relDate;
|
||||
},
|
||||
addTicketLog() {
|
||||
// API.addLog({ id: this.id, message: this.comment }).then(
|
||||
// response => {
|
||||
// this.$store.dispatch("alertSuccess", { name: "Log saved", type: "success" });
|
||||
// if (this.internalLogs === undefined) {
|
||||
// this.reload([response.data]);
|
||||
// } else {
|
||||
// this.internalLogs.unshift(response.data);
|
||||
// this.reload(this.internalLogs);
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.internalLogs = this.logs;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
173
ui/src/components/UserDataEditor.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="editoruserdata === undefined" class="text-sm-center py-16">
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
color="primary"
|
||||
:size="70"
|
||||
:width="7"
|
||||
class="align-center"
|
||||
>
|
||||
</v-progress-circular>
|
||||
</div>
|
||||
<div v-else class="pa-8">
|
||||
<v-form>
|
||||
<v-row>
|
||||
<v-col cols="4" class="d-flex flex-column align-center">
|
||||
<v-avatar v-if="editoruserdata.image" size="128" class="mt-1">
|
||||
<img :src="editoruserdata.image" alt="userdata avatar" />
|
||||
</v-avatar>
|
||||
|
||||
<v-file-input
|
||||
v-model="file"
|
||||
type="file"
|
||||
class="pt-2 flex-grow-0"
|
||||
style="width: 100%"
|
||||
accept="image/png, image/jpeg"
|
||||
label="Select Image"
|
||||
@change="change"
|
||||
:clearable="false"
|
||||
>
|
||||
<template v-slot:append-outer>
|
||||
<v-btn
|
||||
v-if="showCrop"
|
||||
rounded
|
||||
small
|
||||
color="accent"
|
||||
@click="validate"
|
||||
>
|
||||
<v-icon>
|
||||
mdi-check
|
||||
</v-icon>
|
||||
Set
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="!!editoruserdata.image"
|
||||
small
|
||||
rounded
|
||||
color="error"
|
||||
@click="
|
||||
file = null;
|
||||
editoruserdata.image = '';
|
||||
showCrop = false;
|
||||
"
|
||||
class="ml-2"
|
||||
>
|
||||
<v-icon>
|
||||
mdi-close
|
||||
</v-icon>
|
||||
Clear
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-file-input>
|
||||
|
||||
<vue-cropper
|
||||
v-if="showCrop"
|
||||
ref="cropper"
|
||||
v-bind="{ aspectRatio: 1, autoCrop: true }"
|
||||
:src="imgSrc"
|
||||
alt="Avatar"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="8">
|
||||
<v-text-field
|
||||
prepend-icon="mdi-account"
|
||||
label="Name"
|
||||
v-model="editoruserdata.name"
|
||||
></v-text-field>
|
||||
<v-text-field
|
||||
prepend-icon="mdi-email"
|
||||
label="Email"
|
||||
v-model="editoruserdata.email"
|
||||
></v-text-field>
|
||||
|
||||
<v-btn
|
||||
color="success"
|
||||
outlined
|
||||
@click="saveUserData"
|
||||
class="mt-6"
|
||||
>
|
||||
<v-icon>mdi-content-save</v-icon>
|
||||
Save
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { UserData } from "@/client";
|
||||
import VueCropper from "vue-cropperjs";
|
||||
import "cropperjs/dist/cropper.css";
|
||||
|
||||
interface State {
|
||||
tab: number;
|
||||
editoruserdata?: UserData;
|
||||
file: File | null;
|
||||
imgSrc: string | ArrayBuffer | null;
|
||||
showCrop: boolean;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "UserDataEditor",
|
||||
data: (): State => ({
|
||||
tab: 0,
|
||||
editoruserdata: undefined,
|
||||
file: null,
|
||||
imgSrc: null,
|
||||
showCrop: false
|
||||
}),
|
||||
props: ['userdata'],
|
||||
components: {
|
||||
VueCropper
|
||||
},
|
||||
methods: {
|
||||
saveUserData: function() {
|
||||
this.$emit("save", this.editoruserdata);
|
||||
},
|
||||
change: function() {
|
||||
if (!this.file) {
|
||||
this.imgSrc = null;
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = ticket => {
|
||||
if (ticket.target && this.$refs.cropper) {
|
||||
this.imgSrc = ticket.target.result;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let cropper: any = this.$refs.cropper;
|
||||
cropper.replace(this.imgSrc);
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(this.file);
|
||||
this.showCrop = true;
|
||||
},
|
||||
validate: function() {
|
||||
if (this.$refs.cropper && this.editoruserdata) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let cropper: any = this.$refs.cropper;
|
||||
this.editoruserdata.image = cropper
|
||||
.getCroppedCanvas({width: 128, height: 128})
|
||||
.toDataURL("image/png");
|
||||
// this.on.input(croppedImg)
|
||||
this.showCrop = false;
|
||||
// this.file = null
|
||||
// this.imgSrc = null
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.editoruserdata = this.userdata;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.theme--dark.v-tabs-items,
|
||||
.theme--dark.v-tabs > .v-tabs-bar {
|
||||
background: none;
|
||||
}
|
||||
</style>
|
||||
85
ui/src/components/VJsfCropImg.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<v-input :value="value" class="vjsf-crop-img">
|
||||
<v-row class="mt-0 mx-0" align="center">
|
||||
<v-avatar v-if="value" size="128" class="mt-1">
|
||||
<img :src="value">
|
||||
</v-avatar>
|
||||
<v-file-input
|
||||
v-model="file"
|
||||
type="file"
|
||||
class="pt-2"
|
||||
accept="image/png, image/jpeg"
|
||||
placeholder="User Avatar"
|
||||
@change="change"
|
||||
:clearable="false"
|
||||
>
|
||||
<template v-slot:append-outer>
|
||||
<v-btn v-if="imgSrc" fab x-small color="accent" @click="validate">
|
||||
<v-icon>
|
||||
mdi-check
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-file-input>
|
||||
<v-icon v-if="!!value" @click="on.input(null)">
|
||||
mdi-close
|
||||
</v-icon>
|
||||
</v-row>
|
||||
<vue-cropper
|
||||
v-if="file"
|
||||
ref="cropper"
|
||||
v-bind="cropperOptions"
|
||||
:src="imgSrc"
|
||||
alt="Avatar"
|
||||
/>
|
||||
</v-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueCropper from 'vue-cropperjs'
|
||||
import 'cropperjs/dist/cropper.css'
|
||||
|
||||
export default {
|
||||
components: { VueCropper },
|
||||
props: {
|
||||
value: { type: String, default: '' },
|
||||
on: { type: Object, required: true },
|
||||
cropperOptions: { type: Object, default: () => ({ aspectRatio: 1, autoCrop: true }) },
|
||||
size: { type: Number, default: 128 } // same as default v-avatar size
|
||||
},
|
||||
data: () => ({
|
||||
file: null,
|
||||
imgSrc: null
|
||||
}),
|
||||
computed: {},
|
||||
methods: {
|
||||
change() {
|
||||
if (!this.file) {
|
||||
this.imgSrc = null
|
||||
return
|
||||
}
|
||||
const reader = new FileReader()
|
||||
reader.onload = (ticket) => {
|
||||
this.imgSrc = ticket.target.result
|
||||
this.dialog = true
|
||||
this.$refs.cropper.replace(this.imgSrc)
|
||||
}
|
||||
reader.readAsDataURL(this.file)
|
||||
},
|
||||
async validate() {
|
||||
const croppedImg = this.$refs.cropper
|
||||
.getCroppedCanvas({ width: this.size, height: this.size })
|
||||
.toDataURL('image/png')
|
||||
this.on.input(croppedImg)
|
||||
this.file = null
|
||||
this.imgSrc = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css">
|
||||
.vjsf-crop-img>.v-input__control>.v-input__slot {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
20
ui/src/components/charts/Bar.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Component, Mixins } from 'vue-property-decorator'
|
||||
import {HorizontalBar, mixins} from 'vue-chartjs';
|
||||
import ChartOptions from "chart.js";
|
||||
|
||||
@Component({
|
||||
extends: HorizontalBar,
|
||||
mixins: [mixins.reactiveProp],
|
||||
props: {
|
||||
chartOptions: {
|
||||
type: ChartOptions,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
})
|
||||
export default class BarChart extends Mixins(mixins.reactiveProp, HorizontalBar) {
|
||||
mounted () {
|
||||
// @ts-expect-error chartOptions are not expected
|
||||
this.renderChart(this.chartData, this.chartOptions);
|
||||
}
|
||||
}
|
||||
20
ui/src/components/charts/Doughnut.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Component, Mixins } from "vue-property-decorator";
|
||||
import { mixins, Pie } from "vue-chartjs";
|
||||
import ChartOptions from "chart.js";
|
||||
|
||||
@Component({
|
||||
extends: Pie,
|
||||
mixins: [mixins.reactiveProp],
|
||||
props: {
|
||||
chartOptions: {
|
||||
type: ChartOptions,
|
||||
default: null
|
||||
}
|
||||
}
|
||||
})
|
||||
export default class DoughnutChart extends Mixins(mixins.reactiveProp, Pie) {
|
||||
mounted() {
|
||||
// @ts-expect-error chartOptions are not expected
|
||||
this.renderChart(this.chartData, this.chartOptions);
|
||||
}
|
||||
}
|
||||
20
ui/src/components/charts/Line.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Component, Mixins } from 'vue-property-decorator'
|
||||
import {Line, mixins} from 'vue-chartjs';
|
||||
import ChartOptions from "chart.js";
|
||||
|
||||
@Component({
|
||||
extends: Line,
|
||||
mixins: [mixins.reactiveProp],
|
||||
props: {
|
||||
chartOptions: {
|
||||
type: ChartOptions,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
})
|
||||
export default class LineChart extends Mixins(mixins.reactiveProp, Line) {
|
||||
mounted () {
|
||||
// @ts-expect-error chartOptions are not expected
|
||||
this.renderChart(this.chartData, this.chartOptions);
|
||||
}
|
||||
}
|
||||
34
ui/src/components/icons/ArangoIcon.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<svg
|
||||
width="64"
|
||||
viewBox="74.499 105.376 55.861 54.285"
|
||||
height="64"
|
||||
>
|
||||
<path
|
||||
style="fill: #ffffff"
|
||||
id="path1566"
|
||||
fill="#577138"
|
||||
d="m128.867 130.714c-1.045-3.482-3.378-6.163-5.467-9.02-3.97-5.362-9.123-8.322-13.86-8.357-9.088-.174-15.495 3.97-18.246 10.48-.348.836-.8 1.184-1.637 1.358-3.03.696-6.06 1.393-8.88 2.82-1.915.975-3.865 1.88-5.084 3.76-1.532 2.368-1.358 4.875-.766 7.487 1.532 6.476 5.467 10.48 11.978 11.943 4.005.87 7.904.766 11.56-1.323 2.298-1.288 4.144-3.133 5.955-5.015.453-.487.8-.592 1.393-.313l3.343 1.637c3.552 1.776 7.173 3.238 11.247 2.994 6.477-.383 10.342-4.736 9.924-11.073-.14-2.507-.73-4.944-1.463-7.382zm-23.992 8.8c-3.9 2.6-7.94 4.875-12.605 5.815-1.497.314-2.995.418-4.005.348-3.76 0-6.93-.382-9.715-2.298-3.273-2.3-4.666-7.313-2.786-10.83.592-1.15 1.602-1.985 2.716-2.647 3.865-2.403 8.183-3.517 12.57-4.422 4.56-.975 9.192-2.02 13.963-1.985 2.298 0 4.352.905 5.815 2.75 1.288 1.67.906 3.552.28 5.328-1.22 3.343-3.308 6-6.233 7.94zm23.713 2.856c-1.463 3.656-4.562 4.875-8.078 5.397-3.76.557-6.86-1.22-10.063-2.716-1.045-.487-2.055-1.114-3.134-1.532-.94-.348-1.08-.697-.313-1.358 1.184-1.497 2.368-2.995 3.308-4.667 1.15-2.472 1.846-5.084 1.846-7.834 0-4.248-2.264-6.13-6.546-6.616-.836-.104-1.706-.035-2.577-.035-2.9.2-5.78.662-8.636 1.184-.592-.035-1.323.662-1.706.035-.278-.453.418-1 .73-1.497 2.1-3.62 5.223-5.85 9.158-7.104 3.447-1.08 6.86-1.323 10.4-.383 2.925.766 5.014 2.542 6.93 4.666 2.368 2.6 4.527 5.328 6.268 8.357 1.706 2.96 2.577 6.128 2.82 9.506.07 1.566.2 3.1-.418 4.597z"
|
||||
/>
|
||||
<path
|
||||
style="fill: #ffffff"
|
||||
id="path1570"
|
||||
fill="#a2b24f"
|
||||
d="m126.185 128.277c-1.776-3.03-3.935-5.78-6.268-8.357-1.915-2.124-4.005-3.9-6.93-4.666-3.55-.94-6.964-.697-10.4.383-3.935 1.22-7.07 3.482-9.158 7.104-.278.487-1 1.045-.73 1.497.383.592 1.114-.07 1.706-.035.696-2.263 2.228-3.935 4.144-5.153 3.378-2.194 7.138-3.1 11.178-3.03 3.9.104 6.964 1.8 9.54 4.63 1.88 2.054 3.517 4.353 5.12 6.616 2.542 3.587 3.935 7.556 3.656 12.013-.2 3.17-1.67 5.537-4.77 6.686-2.542.94-5.12 1.15-7.695.035-1.497-.627-3.065-1.08-4.527-1.8-1.358-.66-2.925-.836-4.04-1.95-.8.66-.627 1 .313 1.358 1.08.417 2.1 1.045 3.134 1.532 3.204 1.497 6.337 3.273 10.063 2.716 3.517-.522 6.616-1.775 8.078-5.397.592-1.497.488-3.03.383-4.56-.2-3.482-1.08-6.65-2.786-9.6zm-15.112 3.308c.627-1.776 1-3.656-.28-5.328-1.462-1.88-3.482-2.75-5.815-2.75-4.736-.035-9.367 1-13.998 1.985-4.387.94-8.705 2.02-12.57 4.422-1.114.697-2.124 1.532-2.716 2.647-1.845 3.517-.487 8.53 2.786 10.83 2.786 1.95 5.954 2.298 9.715 2.298 1 .07 2.542-.07 4.004-.348 4.666-.94 8.705-3.204 12.605-5.815 2.994-1.95 5.084-4.596 6.268-7.94zm-8.044 8.183c-3.308 1.985-6.65 3.9-10.516 4.596-3.134.557-6.338.732-9.47-.07-3.656-.87-6.477-4.18-6.616-7.94-.07-2.055.94-3.726 2.507-5.05 2.438-2.054 5.328-3.134 8.392-3.796.07 0 .174.104.278.174 2.577-1.985 5.502-2.368 8.636-2.124.278-.66.94-.453 1.428-.592 2.68-.662 5.397-.94 8.078-.383 5.05 1 5.676 3.83 4.04 7.94-1.288 3.308-3.83 5.467-6.755 7.243zm8.6-2.508c3.308.2 5.64-2.9 5.64-5.57 0-3.726-1.985-6.407-4.84-8.53-1.358-.975-2.9-1.636-4.562-1.045-1.428.487-2.82.8-4.318.697-.174 0-.348.14-.522.174.87 0 1.706-.07 2.577.034 4.283.488 6.546 2.368 6.546 6.616 0 2.75-.696 5.362-1.846 7.835.383-.245.836-.245 1.323-.2z"
|
||||
/>
|
||||
<path
|
||||
style="fill: #ffffff"
|
||||
id="path1574"
|
||||
fill="#5e3108"
|
||||
d="m83.564 134.823c-.105.905.14 1.636 1 2.16 3.134 1.915 6.477 3.03 10.203 2.6 2.75-.313 5.327-1.184 7.452-3.03 1.985-1.706 2.368-3.83 1.044-6.024-1.637-2.68-3.97-4.353-7.034-4.944-3.1-.244-6.06.14-8.636 2.124-2.228 1.88-3.726 4.18-4.04 7.104z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ArangoIcon",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
31
ui/src/components/icons/EmitterIcon.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<svg viewBox="0 0 205.18876 205.19" height="205.19" width="205.18875" id="svg4136">
|
||||
<g transform="matrix(1.25,0,0,-1.25,0,205.19)" id="g4144">
|
||||
<g transform="scale(0.1)" style="fill: #ff0000" clip-path="url(#clipPath4152)" id="g4150">
|
||||
<path
|
||||
id="path4156"
|
||||
style="fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none"
|
||||
d="m 820.992,276.18 c -295.238,0 -535.441,240.211 -535.441,535.465 0,295.245 240.203,535.445 535.441,535.445 295.258,0 535.468,-240.2 535.468,-535.445 0,-58.926 -47.77,-106.696 -106.71,-106.696 -58.92,0 -106.69,47.77 -106.69,106.696 0,177.574 -144.482,322.055 -322.068,322.055 -177.574,0 -322.047,-144.481 -322.047,-322.055 0,-177.575 144.473,-322.075 322.047,-322.075 58.93,0 106.703,-47.769 106.703,-106.691 0,-58.93 -47.773,-106.699 -106.703,-106.699"
|
||||
/>
|
||||
<path
|
||||
id="path4158"
|
||||
style="fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none"
|
||||
d="m 1009.77,811.645 c 0,-104.254 -84.516,-188.774 -188.778,-188.774 -104.258,0 -188.769,84.52 -188.769,188.774 0,104.257 84.511,188.775 188.769,188.775 104.262,0 188.778,-84.518 188.778,-188.775"
|
||||
/>
|
||||
<path
|
||||
id="path4160"
|
||||
style="fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none"
|
||||
d="m 820.758,0 c -45.328,0 -82.074,36.7617 -82.074,82.0781 0,45.3319 36.746,82.0629 82.074,82.0629 362.052,0 656.592,294.57 656.592,656.625 0,362.054 -294.54,656.604 -656.592,656.604 -362.059,0 -656.602,-294.55 -656.602,-656.604 0,-45.325 -36.758,-82.075 -82.0857,-82.075 C 36.7461,738.691 0,775.441 0,820.766 c 0,452.564 368.18,820.754 820.758,820.754 452.562,0 820.752,-368.19 820.752,-820.754 C 1641.51,368.191 1273.32,0 820.758,0"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "EmitterIcon",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
22
ui/src/components/icons/MinioIcon.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<svg
|
||||
viewBox="-0.231 -10.008 1143.859 1147.992"
|
||||
width="2500"
|
||||
height="2500"
|
||||
>
|
||||
<path
|
||||
style="fill: #ffffff"
|
||||
id="path887"
|
||||
fill="#f8e6ea"
|
||||
d="m 649.50958,1130.9299 c -1.375,-0.74 -16.788,-15.67 -34.25,-33.18 l -31.75,-31.834 V 858.86783 c 0,-113.876 -0.289,-207.336 -0.641,-207.69 -0.649,-0.647 -52.692,25.508 -205.773,103.415 -46.152,23.488 -84.548,42.462 -85.324,42.164 -0.906,-0.347 -1.206,-1.359 -0.837,-2.827 0.315,-1.257 1.018,-6.483 1.562,-11.614 2.754,-25.985 23.256,-87.028 45.006,-134 59.272,-128.003 155.174,-234.087 277.19,-306.617 19.913,-11.837 36.64,-20.494 38.337,-19.843 1.294,0.497 1.48,13.97 1.48,107.1 0,76.287 0.31,106.531 1.091,106.531 0.6,0 5.174,-2.109 10.165,-4.686 35.003,-18.079 60.409,-51.848 68.9,-91.58 2.871,-13.436 3.13,-37.923 0.537,-50.916 -4.763,-23.874 -15.756,-46.334 -31.252,-63.852 -7.652,-8.65 -33.057,-35.365 -77.946,-81.966 -67.875,-70.462 -80.303,-83.931 -88.255,-95.65 -5.834,-8.6 -10.87,-19.113 -13.922,-29.062 -2.447,-7.979 -2.7,-10.307 -2.754,-25.288003 -0.065,-18.287 0.974,-23.978 6.985,-38.248 11.6,-27.537 41.822,-53.2229997 66.951,-56.9029997 17.627,-2.58 39.898,-2.083 54.386,1.217 11.81,2.69 30.942,14.2249997 44.057,26.5619997 15.396,14.484 23.147,26.045 81.04,120.872003 68.315,111.898 76.461,125.692 77.628,131.443 1.155,5.692 0.319,8.097 -2.79,8.027 -2.589,-0.058 -1.805,0.745 -124.8,-127.97 -10.774,-11.275 -29.537,-31.075 -41.694,-44 -31.729,-33.731003 -44.894,-46.440003 -50.863,-49.098003 -7.641,-3.404 -18.242,-3.248 -25.625,0.378 -14.476,7.109 -21.328,23.505 -15.867,37.970003 2.708,7.171 -1.064,3.061 87.873,95.75 39.844,41.525 75.834,79.55 79.979,84.5 66.885,79.884 61.447,198.583 -12.46,271.993 -16.97,16.855 -33.934,28.403 -65.364,44.493 -10.725,5.49 -20.962,10.883 -22.75,11.984 l -3.25,2 v 257.934 c 0,141.86307 -0.273,258.64407 -0.607,259.51407 -0.703,1.833 -1.03,1.835 -4.393,0.024 z m -177.63,-500.38507 c 87.548,-44.936 105.617,-54.442 108.183,-56.912 1.61,-1.548 2.312,-3.78 2.792,-8.857 0.969,-10.263 0.782,-118.091 -0.206,-118.702 -2.176,-1.345 -38.95,31.338 -63.639,56.56 -42.682,43.6 -78.365,92.834 -107.7,148.595 -3.836,7.292 -6.656,13.259 -6.267,13.259 0.389,0 30.467,-15.274 66.838,-33.943 z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MinioIcon",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
43
ui/src/components/icons/NodeRedIcon.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
width="512"
|
||||
height="512"
|
||||
>
|
||||
<g id="g861" transform="translate(0 -540.36)">
|
||||
<g style="fill: #ffffff" id="g841" transform="matrix(6.1195921,0,0,6.1195921,-464.85522,-1122.4443)">
|
||||
<path
|
||||
id="path839"
|
||||
fill="#ffffff"
|
||||
d="m 120.6731,296.55103 c -2.3846,0 -4.3789,2.0376 -4.3789,4.4222 v 0.77344 c -2.2304,0.10995 -4.0388,0.5467 -5.3281,1.4316 -1.5951,1.0948 -2.4675,2.582 -3.1816,3.877 -0.71415,1.295 -1.2996,2.4093 -2.1504,3.1894 -0.72545,0.66525 -1.7997,1.1216 -3.4512,1.3301 -0.21359,-2.192 -2.0615,-3.9512 -4.305197,-3.9512 h -17.167 c -2.3846,0 -4.4165,1.965 -4.4165,4.3496 v 4.2422 c 0,2.3846 2.0319,4.3516 4.4165,4.3516 h 17.167 c 2.384597,0 4.387197,-1.9669 4.387197,-4.3516 v -1.6133 c 9.7257,0.15307 12.467,2.6032 15.594,5.3379 3.0006,2.6241 6.6658,5.3789 15.436,5.4948 v 0.73633 c 0,2.3846 2.0695,4.3799 4.4541,4.3799 h 17.092 c 2.3846,0 4.4541,-1.9952 4.4541,-4.3799 v -4.2422 c 0,-2.3846 -2.0695,-4.3779 -4.4541,-4.3779 h -17.092 c -2.3846,0 -4.4541,1.9933 -4.4541,4.3779 v 0.58594 c -8.0984,-0.0599 -10.486,-2.1557 -13.498,-4.7897 -2.5035,-2.1893 -5.6398,-4.5852 -11.947,-5.5859 1.176,-1.1795 1.8834,-2.5192 2.5137,-3.6621 0.67724,-1.228 1.2899,-2.2006 2.2695,-2.873 0.76303,-0.52371 1.9757,-0.83922 3.6621,-0.93945 v 0.55078 c 0,2.3846 1.9943,4.3356 4.3789,4.3356 h 17.242 c 2.3846,0 4.3789,-1.951 4.3789,-4.3356 v -4.2422 c 0,-2.3846 -1.9943,-4.4222 -4.3789,-4.4222 z m 0,3 h 17.242 c 0.80513,0 1.3789,0.6171 1.3789,1.4222 v 4.2422 c 0,0.80514 -0.57378,1.3356 -1.3789,1.3356 h -17.242 c -0.80513,0 -1.3789,-0.53045 -1.3789,-1.3356 v -4.2422 c 0,-0.80513 0.57378,-1.4222 1.3789,-1.4222 z m -39.961997,11.016 h 17.167 c 0.80513,0 1.4165,0.60112 1.4165,1.4062 v 4.2422 c 0,0.80513 -0.61138,1.4082 -1.4165,1.4082 h -17.167 c -0.80513,0 -1.4165,-0.60307 -1.4165,-1.4082 v -4.2422 c 0,-0.80513 0.61137,-1.4062 1.4165,-1.4062 z m 57.037997,9.984 h 17.092 c 0.80513,0 1.4541,0.5728 1.4541,1.3779 v 4.168 c 0,0.80513 -0.64898,1.4541 -1.4541,1.4541 h -17.092 c -0.80513,0 -1.4541,-0.64897 -1.4541,-1.4541 v -4.168 c 0,-0.80513 0.64897,-1.3779 1.4541,-1.3779 z"
|
||||
style="
|
||||
color: #000000;
|
||||
text-indent: 0;
|
||||
text-decoration: none;
|
||||
text-decoration-line: none;
|
||||
text-decoration-style: solid;
|
||||
text-decoration-color: #000000;
|
||||
text-transform: none;
|
||||
white-space: normal;
|
||||
isolation: auto;
|
||||
mix-blend-mode: normal;
|
||||
solid-color: #000000;
|
||||
fill: #ffffff;
|
||||
color-rendering: auto;
|
||||
image-rendering: auto;
|
||||
shape-rendering: auto;
|
||||
"
|
||||
/>
|
||||
</g>
|
||||
<g id="g859" fill="#8f0000" transform="matrix(1.0024 0 0 1.0024 .26914 -2.6855)" />
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "NodeRedIcon",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
64
ui/src/components/snippets/ArtifactSnippet.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<v-list-item link dense>
|
||||
<v-list-item-content @click="goto">
|
||||
<v-list-item-title class="d-flex">
|
||||
<v-icon small class="mr-1">mdi-gauge</v-icon>
|
||||
<span class="text-truncate">{{ artifact.name }}</span>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="d-flex">
|
||||
<v-icon small class="mr-1" :color="statusColor">{{ statusIcon }}</v-icon>
|
||||
<span :class="statusColor + '--text'">{{ artifact.status | capitalize }}</span>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-icon small class="mr-1">mdi-information</v-icon>
|
||||
<span class="mr-1">{{ artifact.enrichments ? lodash.size(artifact.enrichments) : 0 }}</span>
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action v-if="action !== ''">
|
||||
<v-btn icon small>
|
||||
<v-icon small @click="actionClick">{{ action }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {Type, TypeColorEnum} from "../../client";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "ArtifactSnippet",
|
||||
props: ["artifact", "to", "action"],
|
||||
computed: {
|
||||
statusIcon: function () {
|
||||
let icon = "mdi-help";
|
||||
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
|
||||
if (this.artifact.status === state.id) {
|
||||
icon = state.icon;
|
||||
}
|
||||
})
|
||||
return icon;
|
||||
},
|
||||
statusColor: function () {
|
||||
let color = TypeColorEnum.Info;
|
||||
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
|
||||
if (this.artifact.status === state.id && state.color) {
|
||||
color = state.color
|
||||
}
|
||||
})
|
||||
return color;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
actionClick: function () {
|
||||
this.$emit("actionClick", this.artifact)
|
||||
},
|
||||
goto: function () {
|
||||
this.$emit("click", this.artifact)
|
||||
if (this.to) {
|
||||
this.$router.push(this.to);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
60
ui/src/components/snippets/IDSnippet.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div>
|
||||
<TicketSnippet v-if="ticket !== undefined" :ticket="ticket" :to="{ name: 'Ticket', params: { type: ticket.type, id: ticket.id } }"></TicketSnippet>
|
||||
<ArtifactSnippet v-if="artifact !== undefined" :artifact="artifact" :to="{ name: 'Artifact', params: { artifact: artifact.name } }"></ArtifactSnippet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {Artifact, TicketResponse} from "../../client";
|
||||
import {API} from "@/services/api";
|
||||
import TicketSnippet from "./TicketSnippet.vue";
|
||||
import ArtifactSnippet from "./ArtifactSnippet.vue";
|
||||
|
||||
interface State {
|
||||
ticket?: TicketResponse;
|
||||
artifact?: Artifact;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "IDSnippet",
|
||||
props: ["id"],
|
||||
data: (): State => ({
|
||||
ticket: undefined,
|
||||
artifact: undefined,
|
||||
}),
|
||||
components: {
|
||||
ArtifactSnippet,
|
||||
TicketSnippet
|
||||
},
|
||||
methods: {
|
||||
loadSnippet() {
|
||||
if (this.id.startsWith("tickets/")) {
|
||||
this.artifact = undefined;
|
||||
let ticketID = this.id.replace("tickets/", "")
|
||||
API.getTicket(ticketID).then(response => {
|
||||
this.ticket = response.data;
|
||||
});
|
||||
}
|
||||
if (this.id.startsWith("artifacts/")) {
|
||||
this.ticket = undefined;
|
||||
// TODO
|
||||
// let artifactID = this.id.replace("artifacts/", "")
|
||||
// API.getArtifact(artifactID).then(response => {
|
||||
// this.artifact = response.data;
|
||||
// });
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"id": "loadSnippet",
|
||||
$route: "loadSnippet"
|
||||
},
|
||||
mounted() {
|
||||
this.loadSnippet();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
91
ui/src/components/snippets/TicketSnippet.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<v-list-item link dense>
|
||||
<v-list-item-content @click="goto">
|
||||
<v-list-item-title class="d-flex">
|
||||
<v-icon small class="mr-1">{{ typeIcon }}</v-icon>
|
||||
<span class="text-truncate">{{ ticket.type | capitalize }} #{{ ticket.id }}: {{ ticket.name }}</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-icon small class="mr-1">mdi-calendar-plus</v-icon>
|
||||
{{ ticket.created | formatdate($store.state.settings.timeformat) }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="d-flex">
|
||||
<v-icon small class="mr-1" :color="statusColor">{{ statusIcon }}</v-icon>
|
||||
<span :class="statusColor + '--text'">{{ ticket.status | capitalize }}</span>
|
||||
|
||||
<v-icon small class="mx-1">mdi-account</v-icon>
|
||||
{{ ticket.owner ? ticket.owner : 'unassigned' }}
|
||||
<v-spacer></v-spacer>
|
||||
<v-icon small class="mr-1">mdi-source-branch</v-icon>
|
||||
<span class="mr-1">{{ ticket.playbooks ? lodash.size(ticket.playbooks) : 0 }}</span>
|
||||
<v-icon small class="mr-1">mdi-checkbox-multiple-marked-outline</v-icon>
|
||||
<span class="mr-1">{{ opentaskcount }}</span>
|
||||
<v-icon small class="mr-1">mdi-comment</v-icon>
|
||||
<span class="mr-1">{{ ticket.comments ? ticket.comments.length : 0 }}</span>
|
||||
<v-icon small class="mr-1">mdi-file</v-icon>
|
||||
<span class="mr-1">{{ ticket.files ? ticket.files.length : 0 }}</span>
|
||||
<v-icon small class="mr-1">mdi-link</v-icon>
|
||||
<span class="mr-1">{{ ticket.references ? ticket.references.length : 0 }}</span>
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action v-if="action !== ''">
|
||||
<v-btn icon small>
|
||||
<v-icon small @click="actionClick">{{ action }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {Playbook, Task, Type, TypeColorEnum} from "@/client";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "TicketSnippet",
|
||||
props: ["ticket", "to", "action"],
|
||||
computed: {
|
||||
opentaskcount: function() {
|
||||
let count = 0;
|
||||
this.lodash.forEach(this.ticket.playbooks, (playbook: Playbook) => {
|
||||
this.lodash.forEach(playbook.tasks, (task: Task) => {
|
||||
if (task.done) {
|
||||
count++;
|
||||
}
|
||||
})
|
||||
})
|
||||
return count;
|
||||
},
|
||||
typeIcon: function () {
|
||||
let icon = "mdi-help";
|
||||
this.lodash.forEach(this.$store.state.settings.ticketTypes, (ticketType: Type) => {
|
||||
if (this.ticket.type === ticketType.id) {
|
||||
icon = ticketType.icon
|
||||
}
|
||||
})
|
||||
return icon;
|
||||
},
|
||||
statusIcon: function() {
|
||||
if (this.ticket.status === 'closed') {
|
||||
return "mdi-checkbox-marked-circle-outline";
|
||||
}
|
||||
return "mdi-arrow-right-drop-circle-outline";
|
||||
},
|
||||
statusColor: function() {
|
||||
if (this.ticket.status === 'closed') {
|
||||
return TypeColorEnum.Success;
|
||||
}
|
||||
return TypeColorEnum.Info;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
actionClick: function () {
|
||||
this.$emit("actionClick", this.ticket)
|
||||
},
|
||||
goto: function () {
|
||||
if (this.to === undefined) {
|
||||
return
|
||||
}
|
||||
this.$router.push(this.to);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
86
ui/src/main.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
|
||||
import JsonSchemaEditor from "json-schema-editor-vue";
|
||||
import vuetify from "./plugins/vuetify";
|
||||
import VuePipeline from "vue-pipeline";
|
||||
import VueLodash from "vue-lodash";
|
||||
import lodash from "lodash";
|
||||
import axios from "axios";
|
||||
import { DateTime } from 'luxon';
|
||||
import VueNativeSock from 'vue-native-websocket';
|
||||
import antInputDirective from 'ant-design-vue/es/_util/antInputDirective'
|
||||
import antDirective from 'ant-design-vue/es/_util/antDirective'
|
||||
|
||||
import VueAxios from "vue-axios";
|
||||
import VueLuxon from "vue-luxon";
|
||||
|
||||
import "./registerServiceWorker";
|
||||
|
||||
import "json-schema-editor-vue/lib/json-schema-editor-vue.css";
|
||||
import "@mdi/font/css/materialdesignicons.css";
|
||||
import "vue-d3-network/dist/vue-d3-network.css";
|
||||
import '@koumoul/vjsf/dist/main.css'
|
||||
|
||||
import { Problem } from "@/types/types";
|
||||
Vue.use(VueLodash, { lodash: lodash });
|
||||
Vue.use(antDirective);
|
||||
Vue.use(antInputDirective);
|
||||
Vue.use(JsonSchemaEditor);
|
||||
Vue.use(VuePipeline);
|
||||
Vue.use(VueAxios, axios);
|
||||
Vue.use(VueLuxon);
|
||||
|
||||
// import VJsf from '@koumoul/vjsf'
|
||||
import VJsf from '@koumoul/vjsf/lib/VJsf.js';
|
||||
import '@koumoul/vjsf/lib/deps/third-party.js';
|
||||
|
||||
Vue.component('VJsf', VJsf)
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
Vue.filter("capitalize", function(value: any) {
|
||||
if (!value) return "";
|
||||
return lodash.startCase(value.toString());
|
||||
});
|
||||
|
||||
Vue.filter("formatdate", function(s: string, format: string) {
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
});
|
||||
|
||||
let protocol = "ws"
|
||||
if (location.protocol === "https:") {
|
||||
protocol = "wss"
|
||||
}
|
||||
Vue.use(VueNativeSock, protocol + '://' + location.hostname + ':'+ location.port +'/wss', { store: store, format: 'json' })
|
||||
|
||||
const v = new Vue({
|
||||
router,
|
||||
vuetify,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount("#app");
|
||||
|
||||
axios.interceptors.response.use(
|
||||
response => response,
|
||||
error => {
|
||||
console.log(error)
|
||||
if (error.response.data && 'title' in error.response.data && 'detail' in error.response.data) {
|
||||
const problem = error.response.data as Problem;
|
||||
v.$store.dispatch("alertError", { name: problem.title, detail: problem.detail });
|
||||
return Promise.reject(error);
|
||||
}
|
||||
if (error.response.data && 'error' in error.response.data) {
|
||||
v.$store.dispatch("alertError", { name: "Error", detail: error.response.data.error });
|
||||
return Promise.reject(error);
|
||||
}
|
||||
v.$store.dispatch("alertError", { name: "Error", detail: JSON.stringify(error.response.data) });
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
90
ui/src/plugins/vuetify.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import "@mdi/font/css/materialdesignicons.css";
|
||||
import Vue from "vue";
|
||||
import Vuetify from "vuetify/lib";
|
||||
import MinioIcon from "../components/icons/MinioIcon.vue";
|
||||
import NodeRedIcon from "../components/icons/NodeRedIcon.vue";
|
||||
import ArangoIcon from "../components/icons/ArangoIcon.vue";
|
||||
import EmitterIcon from "../components/icons/EmitterIcon.vue";
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
export const colors = [
|
||||
'#c62828', '#6a1b9a',
|
||||
'#283593', '#0277bd',
|
||||
'#00695c', '#558b2f',
|
||||
'#f9a825', '#ef6c00',
|
||||
'#ad1457', '#4527a0',
|
||||
'#1565c0', '#00838f',
|
||||
'#2e7d32', '#9e9d24',
|
||||
'#ff8f00', '#d84315',
|
||||
]
|
||||
|
||||
export default new Vuetify({
|
||||
theme: {
|
||||
dark: false,
|
||||
themes: {
|
||||
light: {
|
||||
statusbar: "#212121", // "#1c313a",
|
||||
appbar: "#eeeeee", //'#28282e',
|
||||
background: "#f5f5f5", //'#393a3f',
|
||||
cards: "#e0e0e0", //'#393a3f',
|
||||
|
||||
primary: "#607d8b",
|
||||
yellow: "#FFC107", // "#FFEB3B",
|
||||
error: "#C62828", // "#d32f2f",
|
||||
info: "#1565C0", // "#2196F3",
|
||||
success: "#2E7D32", // "#689f38",
|
||||
warning: "#D84315", // "#fbc02d",
|
||||
|
||||
red: "#C62828", // "#d32f2f",
|
||||
},
|
||||
dark: {
|
||||
// statusbar: "#d35400",
|
||||
// statusbar: "#f03f24", //'#18181c', 240 63 36
|
||||
// appbar: "#212121", //'#28282e',
|
||||
// background: "#303030", //'#393a3f',
|
||||
// cards: "#424242", //'#393a3f',
|
||||
|
||||
statusbar: "#121212",
|
||||
appbar: "#212121", //'#28282e',
|
||||
background: "#303030", //'#393a3f',
|
||||
cards: "#424242", //'#393a3f',
|
||||
|
||||
// alertmanager: "#ef6c00",
|
||||
// catalyst: "#ad1457",
|
||||
// blocklist: "#2e7d32",
|
||||
// uploadportal: "#283593",
|
||||
// search: "#c62828",
|
||||
|
||||
// darksteel: "#1c313a",
|
||||
// steel: "#455a64",
|
||||
// lightsteel: "#718792",
|
||||
primary: "#FFC107", // "#00bcd4", // "#FFEB3B",
|
||||
yellow: "#FFC107", // "#FFEB3B",
|
||||
// accent: "#82B1FF",
|
||||
error: "#ef9a9a", // "#d32f2f",
|
||||
info: "#90caf9", // "#2196F3",
|
||||
success: "#a5d6a7", // "#689f38",
|
||||
warning: "#ffab91", // "#fbc02d",
|
||||
|
||||
red: "#C62828", // "#d32f2f",
|
||||
},
|
||||
},
|
||||
},
|
||||
icons: {
|
||||
values: {
|
||||
minio: {
|
||||
component: MinioIcon,
|
||||
},
|
||||
nodered: {
|
||||
component: NodeRedIcon,
|
||||
},
|
||||
arango: {
|
||||
component: ArangoIcon,
|
||||
},
|
||||
emitter: {
|
||||
component: EmitterIcon,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
34
ui/src/registerServiceWorker.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from "register-service-worker";
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
"App is being served from cache by a service worker.\n" +
|
||||
"For more details, visit https://goo.gl/AFskqB"
|
||||
);
|
||||
},
|
||||
registered() {
|
||||
console.log("Service worker has been registered.");
|
||||
},
|
||||
cached() {
|
||||
console.log("Content has been cached for offline use.");
|
||||
},
|
||||
updatefound() {
|
||||
console.log("New content is downloading.");
|
||||
},
|
||||
updated() {
|
||||
console.log("New content is available; please refresh.");
|
||||
},
|
||||
offline() {
|
||||
console.log(
|
||||
"No internet connection found. App is running in offline mode."
|
||||
);
|
||||
},
|
||||
error(error) {
|
||||
console.error("Error during service worker registration:", error);
|
||||
},
|
||||
});
|
||||
}
|
||||
236
ui/src/router/index.ts
Normal file
@@ -0,0 +1,236 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter, { RouteConfig, RawLocation, Route } from "vue-router";
|
||||
import ArtifactPopup from "../views/ArtifactPopup.vue";
|
||||
import Ticket from "../views/Ticket.vue";
|
||||
import TicketNew from "../views/TicketNew.vue";
|
||||
import TicketList from "../views/TicketList.vue";
|
||||
import Graph from "../views/Graph.vue";
|
||||
import Playbook from "../views/Playbook.vue";
|
||||
import PlaybookList from "../views/PlaybookList.vue";
|
||||
import Automation from "../views/Automation.vue";
|
||||
import UserData from "../views/UserData.vue";
|
||||
import Profile from "../views/Profile.vue";
|
||||
import UserDataList from "../views/UserDataList.vue";
|
||||
import AutomationList from "../views/AutomationList.vue";
|
||||
import Rule from "../views/Rule.vue";
|
||||
import RuleList from "../views/RuleList.vue";
|
||||
import Template from "../views/Template.vue";
|
||||
import TemplateList from "../views/TemplateList.vue";
|
||||
import API from "../views/API.vue";
|
||||
import User from '../views/User.vue';
|
||||
import UserList from "@/views/UserList.vue";
|
||||
import Job from '../views/Job.vue';
|
||||
import JobList from "@/views/JobList.vue";
|
||||
import GroupList from "@/views/GroupList.vue";
|
||||
import Dashboard from "@/views/Dashboard.vue";
|
||||
import Group from "@/views/Group.vue";
|
||||
import TicketType from '../views/TicketType.vue';
|
||||
import TicketTypeList from "@/views/TicketTypeList.vue";
|
||||
import TaskList from "@/views/TaskList.vue";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const originalPush = VueRouter.prototype.push;
|
||||
VueRouter.prototype.push = function push(location: RawLocation): Promise<Route> {
|
||||
return new Promise((resolve, reject) => {
|
||||
originalPush.call(this, location, () => {
|
||||
// on complete
|
||||
|
||||
resolve(this.currentRoute);
|
||||
}, (error) => {
|
||||
// on abort
|
||||
|
||||
// only ignore NavigationDuplicated error
|
||||
if (error.name === 'NavigationDuplicated') {
|
||||
resolve(this.currentRoute);
|
||||
} else {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "Catalyst",
|
||||
redirect: { name: "Dashboard" },
|
||||
},
|
||||
|
||||
{
|
||||
path: "/dashboard",
|
||||
name: "Dashboard",
|
||||
component: Dashboard,
|
||||
},
|
||||
|
||||
{
|
||||
path: "/profile",
|
||||
name: "Profile",
|
||||
component: Profile,
|
||||
},
|
||||
|
||||
{
|
||||
path: "/tickets/:type?",
|
||||
name: "TicketList",
|
||||
component: TicketList,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "/tickets/:type?/:id",
|
||||
name: "Ticket",
|
||||
component: Ticket,
|
||||
},
|
||||
{
|
||||
path: "/tickets/:type/new",
|
||||
name: "TicketNew",
|
||||
component: TicketNew,
|
||||
},
|
||||
{
|
||||
path: "/tickets/:type?/:id/artifact/:artifact",
|
||||
name: "ArtifactPopup",
|
||||
component: ArtifactPopup,
|
||||
},
|
||||
|
||||
{
|
||||
path: "/tasks",
|
||||
name: "TaskList",
|
||||
component: TaskList,
|
||||
},
|
||||
|
||||
{
|
||||
path: "/templates",
|
||||
name: "TemplateList",
|
||||
component: TemplateList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "Template",
|
||||
component: Template,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/tickettype",
|
||||
name: "TicketTypeList",
|
||||
component: TicketTypeList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "TicketType",
|
||||
component: TicketType,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/playbooks",
|
||||
name: "PlaybookList",
|
||||
component: PlaybookList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "Playbook",
|
||||
component: Playbook,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/userdata",
|
||||
name: "UserDataList",
|
||||
component: UserDataList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "UserData",
|
||||
component: UserData,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/jobs",
|
||||
name: "JobList",
|
||||
component: JobList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "Job",
|
||||
component: Job,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/automations",
|
||||
name: "AutomationList",
|
||||
component: AutomationList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "Automation",
|
||||
component: Automation,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/rules",
|
||||
name: "RuleList",
|
||||
component: RuleList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "Rule",
|
||||
component: Rule,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/users",
|
||||
name: "UserList",
|
||||
component: UserList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "User",
|
||||
component: User,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/groups",
|
||||
name: "GroupList",
|
||||
component: GroupList,
|
||||
children: [
|
||||
{
|
||||
path: ":id",
|
||||
name: "Group",
|
||||
component: Group,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: "/apidocs",
|
||||
name: "API",
|
||||
component: API,
|
||||
},
|
||||
|
||||
{
|
||||
path: "/graph/:col/:id",
|
||||
name: "Graph",
|
||||
component: Graph,
|
||||
},
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
||||
29
ui/src/sass/variables.scss.bak
Normal file
@@ -0,0 +1,29 @@
|
||||
// Globals
|
||||
// $body-font-family: 'Work Sans', serif;
|
||||
$border-radius-root: 6px;
|
||||
$font-size-root: 14px;
|
||||
|
||||
// Variables must come before the import
|
||||
$btn-letter-spacing: 0;
|
||||
$btn-font-weight: 400;
|
||||
$list-item-title-font-size: 0.929rem;
|
||||
$list-item-dense-title-font-size: 0.929rem;
|
||||
$list-item-dense-title-font-weight: initial;
|
||||
$fab-icon-sizes: (
|
||||
'small': 20
|
||||
);
|
||||
$btn-sizes: (
|
||||
'default': 41,
|
||||
'large': 54
|
||||
);
|
||||
|
||||
$headings: (
|
||||
'h1': (
|
||||
'size': 3.3125rem,
|
||||
'line-height': 1.15em
|
||||
),
|
||||
'h2': (
|
||||
'size': 2.25rem,
|
||||
'line-height': 1.5em
|
||||
)
|
||||
);
|
||||
78
ui/src/services/api.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
UserdataApi,
|
||||
UserdataApiFactory,
|
||||
AutomationsApi,
|
||||
AutomationsApiFactory,
|
||||
Configuration,
|
||||
GraphApi,
|
||||
GraphApiFactory,
|
||||
GroupsApi,
|
||||
GroupsApiFactory,
|
||||
LogsApi,
|
||||
LogsApiFactory,
|
||||
PlaybooksApi,
|
||||
PlaybooksApiFactory,
|
||||
RulesApi,
|
||||
RulesApiFactory,
|
||||
StatisticsApi,
|
||||
StatisticsApiFactory,
|
||||
TasksApi,
|
||||
TasksApiFactory,
|
||||
TemplatesApi,
|
||||
TemplatesApiFactory,
|
||||
TicketsApi,
|
||||
TicketsApiFactory,
|
||||
TickettypesApi,
|
||||
TickettypesApiFactory,
|
||||
UsersApi,
|
||||
UsersApiFactory,
|
||||
SettingsApi,
|
||||
SettingsApiFactory,
|
||||
JobsApi,
|
||||
JobsApiFactory,
|
||||
} from "@/client";
|
||||
|
||||
const config = new Configuration({
|
||||
basePath:
|
||||
window.location.protocol +
|
||||
"//" +
|
||||
window.location.hostname +
|
||||
":" +
|
||||
window.location.port +
|
||||
"/api"
|
||||
});
|
||||
|
||||
export const API: TicketsApi &
|
||||
TemplatesApi &
|
||||
PlaybooksApi &
|
||||
RulesApi &
|
||||
AutomationsApi &
|
||||
UserdataApi &
|
||||
LogsApi &
|
||||
GraphApi &
|
||||
UsersApi &
|
||||
GroupsApi &
|
||||
StatisticsApi &
|
||||
SettingsApi &
|
||||
TickettypesApi &
|
||||
JobsApi &
|
||||
TasksApi = Object.assign(
|
||||
{},
|
||||
TicketsApiFactory(config),
|
||||
PlaybooksApiFactory(config),
|
||||
TemplatesApiFactory(config),
|
||||
RulesApiFactory(config),
|
||||
AutomationsApiFactory(config),
|
||||
SettingsApiFactory(config),
|
||||
LogsApiFactory(config),
|
||||
GraphApiFactory(config),
|
||||
UsersApiFactory(config),
|
||||
UserdataApiFactory(config),
|
||||
GroupsApiFactory(config),
|
||||
StatisticsApiFactory(config),
|
||||
SettingsApiFactory(config),
|
||||
TickettypesApiFactory(config),
|
||||
TasksApiFactory(config),
|
||||
SettingsApiFactory(config),
|
||||
JobsApiFactory(config)
|
||||
);
|
||||
13
ui/src/shims-tsx.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import Vue, { VNode } from "vue";
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {}
|
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
ui/src/shims-vue.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
declare module "*.vue" {
|
||||
import Vue from "vue";
|
||||
export default Vue;
|
||||
}
|
||||
|
||||
declare module "v-jsoneditor/src/index";
|
||||
declare module "@koumoul/vjsf";
|
||||
declare module "@koumoul/vjsf/lib/VJsf.js";
|
||||
declare module "vue-pipeline";
|
||||
declare module "json-schema-editor-vue";
|
||||
declare module "vue-json-to-html";
|
||||
declare module "vue-d3-network";
|
||||
declare module "vue-luxon";
|
||||
declare module 'swagger-ui';
|
||||
declare module 'prismjs/components/prism-core';
|
||||
declare module 'vue-native-websocket';
|
||||
declare module 'antlr4';
|
||||
declare module 'vue-cropperjs';
|
||||
declare module 'graphlib';
|
||||
declare module 'ant-design-vue/es/_util/antInputDirective';
|
||||
declare module 'flat';
|
||||
declare module 'crypto';
|
||||
104
ui/src/store/index.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import Vue from "vue";
|
||||
import Vuex, {ActionContext} from "vuex";
|
||||
import {API} from "@/services/api";
|
||||
import {UserData, TicketList, Settings, UserResponse} from "@/client";
|
||||
import {AxiosResponse} from "axios";
|
||||
import {Alert} from "@/types/types";
|
||||
import {templateStore} from "./modules/templates";
|
||||
import {socketStore} from "@/store/modules/socket";
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
templates: templateStore,
|
||||
socket: socketStore,
|
||||
},
|
||||
state: {
|
||||
user: {} as UserResponse,
|
||||
counts: {} as Record<string, number>,
|
||||
task_count: 0 as number,
|
||||
|
||||
settings: {} as Settings,
|
||||
userdata: {} as UserData,
|
||||
|
||||
alert: {} as Alert,
|
||||
showAlert: false as boolean,
|
||||
},
|
||||
getters: {
|
||||
timeformat: (state) => {
|
||||
if ('timeformat' in state.settings && state.settings.timeformat) {
|
||||
return state.settings.timeformat
|
||||
}
|
||||
return 'dd-MM-yyyy'
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setUser (state, msg) {
|
||||
state.user = msg;
|
||||
},
|
||||
setCount (state, msg) {
|
||||
Vue.set(state.counts, msg.name, msg.count);
|
||||
},
|
||||
setTaskCount (state, msg) {
|
||||
state.task_count = msg;
|
||||
},
|
||||
setUserData (state, msg: UserData) {
|
||||
state.userdata = msg
|
||||
},
|
||||
setSettings (state, msg: Settings) {
|
||||
state.settings = msg
|
||||
},
|
||||
setAlert (state, msg: Alert) {
|
||||
state.showAlert = false;
|
||||
state.showAlert = true;
|
||||
state.alert = msg;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
getUser (context: ActionContext<any, any>) {
|
||||
API.currentUser().then((response) => {
|
||||
context.commit("setUser", response.data);
|
||||
context.dispatch("fetchCount");
|
||||
})
|
||||
},
|
||||
getUserData (context: ActionContext<any, any>) {
|
||||
API.currentUserData().then((response: AxiosResponse<UserData>) => {
|
||||
context.commit("setUserData", response.data);
|
||||
})
|
||||
},
|
||||
getSettings (context: ActionContext<any, any>) {
|
||||
API.getSettings().then((response: AxiosResponse<Settings>) => {
|
||||
context.commit("setSettings", response.data);
|
||||
context.dispatch("fetchCount");
|
||||
})
|
||||
},
|
||||
fetchCount (context: ActionContext<any, any>) {
|
||||
if (!context.state.user.id || !context.state.settings.ticketTypes) {
|
||||
return
|
||||
}
|
||||
|
||||
const username = context.state.user.id;
|
||||
Vue.lodash.forEach(context.state.settings.ticketTypes, (t) => {
|
||||
|
||||
API.listTickets(t.id,0,10,[],[], "status == 'open' AND (owner == '"+username+"' OR !owner)")
|
||||
.then((response: AxiosResponse<TicketList>) => {
|
||||
context.commit("setCount", {"name": t.id, "count": response.data.count});
|
||||
});
|
||||
API.listTasks().then((response) => {
|
||||
if (response.data) {
|
||||
context.commit("setTaskCount", response.data.length );
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
alertSuccess(context: ActionContext<any, any>, msg) {
|
||||
msg.type = "success"
|
||||
context.commit("setAlert", msg)
|
||||
},
|
||||
alertError(context: ActionContext<any, any>, msg) {
|
||||
msg.type = "error"
|
||||
context.commit("setAlert", msg)
|
||||
},
|
||||
},
|
||||
});
|
||||
64
ui/src/store/modules/socket.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import Vue from "vue";
|
||||
import Vuex, {ActionContext} from "vuex";
|
||||
import lodash from "lodash";
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
interface State {
|
||||
socket: any;
|
||||
}
|
||||
|
||||
export const socketStore = {
|
||||
state: (): State => ({
|
||||
socket: {
|
||||
isConnected: false,
|
||||
message: '',
|
||||
reconnectError: false,
|
||||
}
|
||||
}),
|
||||
mutations: {
|
||||
SOCKET_ONOPEN (state: State, event: any) {
|
||||
// console.log("SOCKET_ONOPEN");
|
||||
Vue.prototype.$socket = event.currentTarget;
|
||||
state.socket.isConnected = true;
|
||||
},
|
||||
SOCKET_ONCLOSE (state: State, event: any) {
|
||||
// console.log("SOCKET_ONCLOSE");
|
||||
state.socket.isConnected = false;
|
||||
},
|
||||
SOCKET_ONERROR (state: State, event: any) {
|
||||
// console.log("SOCKET_ONERROR");
|
||||
console.error(state, event);
|
||||
},
|
||||
// default handler called for all methods
|
||||
SOCKET_ONMESSAGE (state: State, message: any) {
|
||||
// console.log("SOCKET_ONMESSAGE");
|
||||
state.socket.message = message;
|
||||
},
|
||||
// mutations for reconnect methods
|
||||
SOCKET_RECONNECT(state: State, count: any) {
|
||||
// console.log("SOCKET_RECONNECT");
|
||||
console.info(state, count);
|
||||
},
|
||||
SOCKET_RECONNECT_ERROR(state: State) {
|
||||
// console.log("SOCKET_RECONNECT_ERROR");
|
||||
state.socket.reconnectError = true;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
sendMessage: function(context: ActionContext<any, any>, msg: any) {
|
||||
Vue.prototype.$socket.send(msg);
|
||||
},
|
||||
update: function (context: ActionContext<any, any>, msg: any) {
|
||||
// console.log("update", msg);
|
||||
if (!msg || !(lodash.has(msg, "ids")) || !msg["ids"]) {
|
||||
return
|
||||
}
|
||||
Vue.lodash.forEach(msg["ids"], (id) => {
|
||||
if (lodash.startsWith(id, "settings/")) {
|
||||
context.dispatch("getSetting")
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
75
ui/src/store/modules/templates.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import Vue from "vue";
|
||||
import Vuex, {ActionContext} from "vuex";
|
||||
import {TicketTemplate} from "@/client";
|
||||
import {API} from "@/services/api";
|
||||
import {AxiosResponse} from "axios";
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
interface State {
|
||||
templates: Array<TicketTemplate>;
|
||||
}
|
||||
|
||||
export const templateStore = {
|
||||
state: (): State => ({
|
||||
templates: [],
|
||||
}),
|
||||
mutations: {
|
||||
setTemplates(state: State, msg: Array<TicketTemplate>) {
|
||||
state.templates = msg;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
listTemplates(context: ActionContext<any, any>) {
|
||||
API.listTemplates().then((response: AxiosResponse<Array<TicketTemplate>>) => {
|
||||
context.commit("setTemplates", response.data)
|
||||
});
|
||||
},
|
||||
getTemplate(context: ActionContext<any, any>, id: string) {
|
||||
return new Promise((resolve) => {
|
||||
API.getTemplate(id).then((response: AxiosResponse<TicketTemplate>) => {
|
||||
resolve(response.data);
|
||||
}).catch(error => {
|
||||
context.dispatch("alertError", {name: "Template could not be loaded", details: error});
|
||||
});
|
||||
});
|
||||
},
|
||||
addTemplate(context: ActionContext<any, any>, template: TicketTemplate) {
|
||||
return new Promise((resolve) => {
|
||||
API.createTemplate(template).then(() => {
|
||||
context.dispatch("listTemplates").then(() => {
|
||||
context.dispatch("alertSuccess", {name: "Template created"}).then(() => {
|
||||
resolve({})
|
||||
});
|
||||
}).catch(error => {
|
||||
context.dispatch("alertError", {name: "Template created, but reload failed", details: error});
|
||||
});
|
||||
}).catch(error => {
|
||||
context.dispatch("alertError", {name: "Template could not be created", details: error});
|
||||
});
|
||||
});
|
||||
},
|
||||
updateTemplate(context: ActionContext<any, any>, msg: any) {
|
||||
API.updateTemplate(msg.id, msg.template).then(() => {
|
||||
context.dispatch("alertSuccess", {name: "Template updated"});
|
||||
}).catch(error => {
|
||||
context.dispatch("alertError", {name: "Template could not be updated", details: error});
|
||||
});
|
||||
},
|
||||
deleteTemplate(context: ActionContext<any, any>, id: string) {
|
||||
return new Promise((resolve) => {
|
||||
API.deleteTemplate(id).then(() => {
|
||||
context.dispatch("listTemplates").then(() => {
|
||||
context.dispatch("alertSuccess", {name: "Template deleted"}).then(() => {
|
||||
resolve({});
|
||||
});
|
||||
}).catch(error => {
|
||||
context.dispatch("alertError", {name: "Template deleted, but reload failed", details: error});
|
||||
});
|
||||
}).catch(error => {
|
||||
context.dispatch("alertError", {name: "Template could not be deleted", details: error});
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
282
ui/src/suggestions/grammar/CAQLLexer.interp
Normal file
607
ui/src/suggestions/grammar/CAQLLexer.js
Normal file
@@ -0,0 +1,607 @@
|
||||
// Generated from CAQLLexer.g4 by ANTLR 4.9.2
|
||||
// jshint ignore: start
|
||||
import antlr4 from 'antlr4';
|
||||
|
||||
|
||||
|
||||
const serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786",
|
||||
"\u5964\u0002P\u02e3\b\u0001\u0004\u0002\t\u0002\u0004\u0003\t\u0003",
|
||||
"\u0004\u0004\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007",
|
||||
"\t\u0007\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004",
|
||||
"\f\t\f\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010",
|
||||
"\t\u0010\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013",
|
||||
"\u0004\u0014\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017",
|
||||
"\t\u0017\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a",
|
||||
"\u0004\u001b\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e",
|
||||
"\t\u001e\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#",
|
||||
"\t#\u0004$\t$\u0004%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004",
|
||||
"*\t*\u0004+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u0004",
|
||||
"1\t1\u00042\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u0004",
|
||||
"8\t8\u00049\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004",
|
||||
"?\t?\u0004@\t@\u0004A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004",
|
||||
"F\tF\u0004G\tG\u0004H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004",
|
||||
"M\tM\u0004N\tN\u0004O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004",
|
||||
"T\tT\u0004U\tU\u0004V\tV\u0004W\tW\u0004X\tX\u0004Y\tY\u0004Z\tZ\u0004",
|
||||
"[\t[\u0004\\\t\\\u0004]\t]\u0004^\t^\u0004_\t_\u0004`\t`\u0004a\ta\u0004",
|
||||
"b\tb\u0004c\tc\u0004d\td\u0004e\te\u0004f\tf\u0004g\tg\u0004h\th\u0004",
|
||||
"i\ti\u0004j\tj\u0004k\tk\u0003\u0002\u0003\u0002\u0003\u0003\u0003\u0003",
|
||||
"\u0003\u0003\u0003\u0004\u0003\u0004\u0003\u0004\u0003\u0005\u0003\u0005",
|
||||
"\u0003\u0005\u0003\u0006\u0003\u0006\u0003\u0006\u0003\u0007\u0003\u0007",
|
||||
"\u0003\b\u0003\b\u0003\t\u0003\t\u0003\t\u0003\n\u0003\n\u0003\n\u0003",
|
||||
"\u000b\u0003\u000b\u0003\f\u0003\f\u0003\r\u0003\r\u0003\u000e\u0003",
|
||||
"\u000e\u0003\u000f\u0003\u000f\u0003\u0010\u0003\u0010\u0003\u0011\u0003",
|
||||
"\u0011\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0013\u0003\u0013\u0003",
|
||||
"\u0013\u0003\u0014\u0003\u0014\u0003\u0015\u0003\u0015\u0003\u0016\u0003",
|
||||
"\u0016\u0003\u0017\u0003\u0017\u0003\u0018\u0003\u0018\u0003\u0019\u0003",
|
||||
"\u0019\u0003\u001a\u0003\u001a\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
|
||||
"\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
|
||||
"\u001b\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001d\u0003",
|
||||
"\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0005\u001d\u0126",
|
||||
"\n\u001d\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001f",
|
||||
"\u0003\u001f\u0003\u001f\u0003\u001f\u0003 \u0003 \u0003 \u0003 \u0003",
|
||||
" \u0003 \u0003 \u0003 \u0003!\u0003!\u0003!\u0003!\u0003!\u0003\"\u0003",
|
||||
"\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003#\u0003",
|
||||
"#\u0003#\u0003#\u0003#\u0003#\u0003$\u0003$\u0003$\u0003$\u0003$\u0003",
|
||||
"$\u0003$\u0003%\u0003%\u0003%\u0003%\u0003&\u0003&\u0003&\u0003&\u0003",
|
||||
"&\u0003&\u0003\'\u0003\'\u0003\'\u0003(\u0003(\u0003(\u0003(\u0003(",
|
||||
"\u0003(\u0003(\u0003(\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0003",
|
||||
")\u0003*\u0003*\u0003*\u0003*\u0003*\u0003+\u0003+\u0003+\u0003+\u0003",
|
||||
"+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003",
|
||||
"+\u0003+\u0003+\u0003,\u0003,\u0003,\u0003,\u0003-\u0003-\u0003-\u0003",
|
||||
"-\u0003-\u0003.\u0003.\u0003.\u0003.\u0003.\u0003.\u0003/\u0003/\u0003",
|
||||
"/\u0003/\u0003/\u00030\u00030\u00030\u00030\u00030\u00050\u019e\n0\u0003",
|
||||
"1\u00031\u00031\u00031\u00031\u00032\u00032\u00032\u00032\u00032\u0005",
|
||||
"2\u01aa\n2\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u0003",
|
||||
"3\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u00035\u00035\u0003",
|
||||
"5\u00035\u00035\u00035\u00035\u00035\u00036\u00036\u00036\u00036\u0003",
|
||||
"6\u00036\u00036\u00037\u00037\u00037\u00037\u00037\u00037\u00037\u0003",
|
||||
"7\u00037\u00037\u00037\u00037\u00037\u00037\u00038\u00038\u00038\u0003",
|
||||
"8\u00038\u00039\u00039\u00039\u00039\u00039\u0003:\u0003:\u0003:\u0003",
|
||||
":\u0003:\u0003:\u0003:\u0003;\u0003;\u0003;\u0003;\u0003;\u0003;\u0003",
|
||||
";\u0003<\u0003<\u0003<\u0003<\u0003<\u0003=\u0003=\u0003=\u0003=\u0003",
|
||||
"=\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003?\u0003?\u0003?\u0003",
|
||||
"?\u0003?\u0003?\u0003?\u0003?\u0003@\u0003@\u0003@\u0003@\u0003@\u0003",
|
||||
"@\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003B\u0003B\u0003",
|
||||
"B\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003D\u0003",
|
||||
"D\u0003D\u0003D\u0003E\u0003E\u0003E\u0003E\u0003F\u0003F\u0007F\u022b",
|
||||
"\nF\fF\u000eF\u022e\u000bF\u0003G\u0003G\u0007G\u0232\nG\fG\u000eG\u0235",
|
||||
"\u000bG\u0003G\u0003G\u0003G\u0003G\u0003G\u0006G\u023c\nG\rG\u000e",
|
||||
"G\u023d\u0003G\u0003G\u0003G\u0003G\u0006G\u0244\nG\rG\u000eG\u0245",
|
||||
"\u0005G\u0248\nG\u0003H\u0003H\u0007H\u024c\nH\fH\u000eH\u024f\u000b",
|
||||
"H\u0003H\u0005H\u0252\nH\u0003H\u0003H\u0006H\u0256\nH\rH\u000eH\u0257",
|
||||
"\u0003H\u0003H\u0005H\u025c\nH\u0003H\u0006H\u025f\nH\rH\u000eH\u0260",
|
||||
"\u0005H\u0263\nH\u0003I\u0003I\u0003I\u0003J\u0003J\u0003J\u0003J\u0003",
|
||||
"J\u0003J\u0007J\u026e\nJ\fJ\u000eJ\u0271\u000bJ\u0003J\u0003J\u0003",
|
||||
"J\u0003J\u0003J\u0003J\u0003J\u0007J\u027a\nJ\fJ\u000eJ\u027d\u000b",
|
||||
"J\u0003J\u0005J\u0280\nJ\u0003K\u0003K\u0003K\u0003K\u0007K\u0286\n",
|
||||
"K\fK\u000eK\u0289\u000bK\u0003K\u0005K\u028c\nK\u0003K\u0003K\u0005",
|
||||
"K\u0290\nK\u0003K\u0003K\u0003L\u0003L\u0003L\u0003L\u0007L\u0298\n",
|
||||
"L\fL\u000eL\u029b\u000bL\u0003L\u0003L\u0003L\u0003L\u0003L\u0003M\u0003",
|
||||
"M\u0003M\u0003M\u0003N\u0003N\u0003O\u0003O\u0003P\u0003P\u0003Q\u0003",
|
||||
"Q\u0003R\u0003R\u0003S\u0003S\u0003T\u0003T\u0003U\u0003U\u0003V\u0003",
|
||||
"V\u0003W\u0003W\u0003X\u0003X\u0003Y\u0003Y\u0003Z\u0003Z\u0003[\u0003",
|
||||
"[\u0003\\\u0003\\\u0003]\u0003]\u0003^\u0003^\u0003_\u0003_\u0003`\u0003",
|
||||
"`\u0003a\u0003a\u0003b\u0003b\u0003c\u0003c\u0003d\u0003d\u0003e\u0003",
|
||||
"e\u0003f\u0003f\u0003g\u0003g\u0003h\u0003h\u0003i\u0003i\u0003j\u0003",
|
||||
"j\u0003k\u0003k\u0003k\u0003k\u0003\u0299\u0002l\u0003\u0003\u0005\u0004",
|
||||
"\u0007\u0005\t\u0006\u000b\u0007\r\b\u000f\t\u0011\n\u0013\u000b\u0015",
|
||||
"\f\u0017\r\u0019\u000e\u001b\u000f\u001d\u0010\u001f\u0011!\u0012#\u0013",
|
||||
"%\u0014\'\u0015)\u0016+\u0017-\u0018/\u00191\u001a3\u001b5\u001c7\u001d",
|
||||
"9\u001e;\u001f= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o",
|
||||
"9q:s;u<w=y>{?}@\u007fA\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008d",
|
||||
"H\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d\u0002\u009f",
|
||||
"\u0002\u00a1\u0002\u00a3\u0002\u00a5\u0002\u00a7\u0002\u00a9\u0002\u00ab",
|
||||
"\u0002\u00ad\u0002\u00af\u0002\u00b1\u0002\u00b3\u0002\u00b5\u0002\u00b7",
|
||||
"\u0002\u00b9\u0002\u00bb\u0002\u00bd\u0002\u00bf\u0002\u00c1\u0002\u00c3",
|
||||
"\u0002\u00c5\u0002\u00c7\u0002\u00c9\u0002\u00cb\u0002\u00cd\u0002\u00cf",
|
||||
"\u0002\u00d1\u0002\u00d3\u0002\u00d5P\u0003\u0002\'\u0005\u0002C\\a",
|
||||
"ac|\u0006\u00022;C\\aac|\u0003\u00023;\u0003\u000223\u0004\u0002--/",
|
||||
"/\u0004\u0002))^^\u0004\u0002$$^^\u0004\u0002\f\f\u000f\u000f\u0005",
|
||||
"\u0002\u000b\r\u000f\u000f\"\"\u0005\u00022;CHch\u0003\u00022;\u0004",
|
||||
"\u0002CCcc\u0004\u0002DDdd\u0004\u0002EEee\u0004\u0002FFff\u0004\u0002",
|
||||
"GGgg\u0004\u0002HHhh\u0004\u0002IIii\u0004\u0002JJjj\u0004\u0002KKk",
|
||||
"k\u0004\u0002LLll\u0004\u0002MMmm\u0004\u0002NNnn\u0004\u0002OOoo\u0004",
|
||||
"\u0002PPpp\u0004\u0002QQqq\u0004\u0002RRrr\u0004\u0002SSss\u0004\u0002",
|
||||
"TTtt\u0004\u0002UUuu\u0004\u0002VVvv\u0004\u0002WWww\u0004\u0002XXx",
|
||||
"x\u0004\u0002YYyy\u0004\u0002ZZzz\u0004\u0002[[{{\u0004\u0002\\\\||",
|
||||
"\u0002\u02e2\u0002\u0003\u0003\u0002\u0002\u0002\u0002\u0005\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u0007\u0003\u0002\u0002\u0002\u0002\t\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u000b\u0003\u0002\u0002\u0002\u0002\r\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u000f\u0003\u0002\u0002\u0002\u0002\u0011\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u0013\u0003\u0002\u0002\u0002\u0002\u0015\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u0017\u0003\u0002\u0002\u0002\u0002\u0019\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u001b\u0003\u0002\u0002\u0002\u0002\u001d\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u001f\u0003\u0002\u0002\u0002\u0002!\u0003\u0002",
|
||||
"\u0002\u0002\u0002#\u0003\u0002\u0002\u0002\u0002%\u0003\u0002\u0002",
|
||||
"\u0002\u0002\'\u0003\u0002\u0002\u0002\u0002)\u0003\u0002\u0002\u0002",
|
||||
"\u0002+\u0003\u0002\u0002\u0002\u0002-\u0003\u0002\u0002\u0002\u0002",
|
||||
"/\u0003\u0002\u0002\u0002\u00021\u0003\u0002\u0002\u0002\u00023\u0003",
|
||||
"\u0002\u0002\u0002\u00025\u0003\u0002\u0002\u0002\u00027\u0003\u0002",
|
||||
"\u0002\u0002\u00029\u0003\u0002\u0002\u0002\u0002;\u0003\u0002\u0002",
|
||||
"\u0002\u0002=\u0003\u0002\u0002\u0002\u0002?\u0003\u0002\u0002\u0002",
|
||||
"\u0002A\u0003\u0002\u0002\u0002\u0002C\u0003\u0002\u0002\u0002\u0002",
|
||||
"E\u0003\u0002\u0002\u0002\u0002G\u0003\u0002\u0002\u0002\u0002I\u0003",
|
||||
"\u0002\u0002\u0002\u0002K\u0003\u0002\u0002\u0002\u0002M\u0003\u0002",
|
||||
"\u0002\u0002\u0002O\u0003\u0002\u0002\u0002\u0002Q\u0003\u0002\u0002",
|
||||
"\u0002\u0002S\u0003\u0002\u0002\u0002\u0002U\u0003\u0002\u0002\u0002",
|
||||
"\u0002W\u0003\u0002\u0002\u0002\u0002Y\u0003\u0002\u0002\u0002\u0002",
|
||||
"[\u0003\u0002\u0002\u0002\u0002]\u0003\u0002\u0002\u0002\u0002_\u0003",
|
||||
"\u0002\u0002\u0002\u0002a\u0003\u0002\u0002\u0002\u0002c\u0003\u0002",
|
||||
"\u0002\u0002\u0002e\u0003\u0002\u0002\u0002\u0002g\u0003\u0002\u0002",
|
||||
"\u0002\u0002i\u0003\u0002\u0002\u0002\u0002k\u0003\u0002\u0002\u0002",
|
||||
"\u0002m\u0003\u0002\u0002\u0002\u0002o\u0003\u0002\u0002\u0002\u0002",
|
||||
"q\u0003\u0002\u0002\u0002\u0002s\u0003\u0002\u0002\u0002\u0002u\u0003",
|
||||
"\u0002\u0002\u0002\u0002w\u0003\u0002\u0002\u0002\u0002y\u0003\u0002",
|
||||
"\u0002\u0002\u0002{\u0003\u0002\u0002\u0002\u0002}\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u007f\u0003\u0002\u0002\u0002\u0002\u0081\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0083\u0003\u0002\u0002\u0002\u0002\u0085\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0087\u0003\u0002\u0002\u0002\u0002\u0089\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u008b\u0003\u0002\u0002\u0002\u0002\u008d\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u008f\u0003\u0002\u0002\u0002\u0002\u0091\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0093\u0003\u0002\u0002\u0002\u0002\u0095\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0097\u0003\u0002\u0002\u0002\u0002\u0099\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u009b\u0003\u0002\u0002\u0002\u0002\u00d5\u0003\u0002\u0002",
|
||||
"\u0002\u0003\u00d7\u0003\u0002\u0002\u0002\u0005\u00d9\u0003\u0002\u0002",
|
||||
"\u0002\u0007\u00dc\u0003\u0002\u0002\u0002\t\u00df\u0003\u0002\u0002",
|
||||
"\u0002\u000b\u00e2\u0003\u0002\u0002\u0002\r\u00e5\u0003\u0002\u0002",
|
||||
"\u0002\u000f\u00e7\u0003\u0002\u0002\u0002\u0011\u00e9\u0003\u0002\u0002",
|
||||
"\u0002\u0013\u00ec\u0003\u0002\u0002\u0002\u0015\u00ef\u0003\u0002\u0002",
|
||||
"\u0002\u0017\u00f1\u0003\u0002\u0002\u0002\u0019\u00f3\u0003\u0002\u0002",
|
||||
"\u0002\u001b\u00f5\u0003\u0002\u0002\u0002\u001d\u00f7\u0003\u0002\u0002",
|
||||
"\u0002\u001f\u00f9\u0003\u0002\u0002\u0002!\u00fb\u0003\u0002\u0002",
|
||||
"\u0002#\u00fd\u0003\u0002\u0002\u0002%\u0100\u0003\u0002\u0002\u0002",
|
||||
"\'\u0103\u0003\u0002\u0002\u0002)\u0105\u0003\u0002\u0002\u0002+\u0107",
|
||||
"\u0003\u0002\u0002\u0002-\u0109\u0003\u0002\u0002\u0002/\u010b\u0003",
|
||||
"\u0002\u0002\u00021\u010d\u0003\u0002\u0002\u00023\u010f\u0003\u0002",
|
||||
"\u0002\u00025\u0111\u0003\u0002\u0002\u00027\u011b\u0003\u0002\u0002",
|
||||
"\u00029\u0125\u0003\u0002\u0002\u0002;\u0127\u0003\u0002\u0002\u0002",
|
||||
"=\u012b\u0003\u0002\u0002\u0002?\u012f\u0003\u0002\u0002\u0002A\u0137",
|
||||
"\u0003\u0002\u0002\u0002C\u013c\u0003\u0002\u0002\u0002E\u0145\u0003",
|
||||
"\u0002\u0002\u0002G\u014b\u0003\u0002\u0002\u0002I\u0152\u0003\u0002",
|
||||
"\u0002\u0002K\u0156\u0003\u0002\u0002\u0002M\u015c\u0003\u0002\u0002",
|
||||
"\u0002O\u015f\u0003\u0002\u0002\u0002Q\u0167\u0003\u0002\u0002\u0002",
|
||||
"S\u016e\u0003\u0002\u0002\u0002U\u0173\u0003\u0002\u0002\u0002W\u0184",
|
||||
"\u0003\u0002\u0002\u0002Y\u0188\u0003\u0002\u0002\u0002[\u018d\u0003",
|
||||
"\u0002\u0002\u0002]\u0193\u0003\u0002\u0002\u0002_\u019d\u0003\u0002",
|
||||
"\u0002\u0002a\u019f\u0003\u0002\u0002\u0002c\u01a9\u0003\u0002\u0002",
|
||||
"\u0002e\u01ab\u0003\u0002\u0002\u0002g\u01b4\u0003\u0002\u0002\u0002",
|
||||
"i\u01bb\u0003\u0002\u0002\u0002k\u01c3\u0003\u0002\u0002\u0002m\u01ca",
|
||||
"\u0003\u0002\u0002\u0002o\u01d8\u0003\u0002\u0002\u0002q\u01dd\u0003",
|
||||
"\u0002\u0002\u0002s\u01e2\u0003\u0002\u0002\u0002u\u01e9\u0003\u0002",
|
||||
"\u0002\u0002w\u01f0\u0003\u0002\u0002\u0002y\u01f5\u0003\u0002\u0002",
|
||||
"\u0002{\u01fa\u0003\u0002\u0002\u0002}\u0200\u0003\u0002\u0002\u0002",
|
||||
"\u007f\u0208\u0003\u0002\u0002\u0002\u0081\u020e\u0003\u0002\u0002\u0002",
|
||||
"\u0083\u0215\u0003\u0002\u0002\u0002\u0085\u0218\u0003\u0002\u0002\u0002",
|
||||
"\u0087\u0220\u0003\u0002\u0002\u0002\u0089\u0224\u0003\u0002\u0002\u0002",
|
||||
"\u008b\u0228\u0003\u0002\u0002\u0002\u008d\u0247\u0003\u0002\u0002\u0002",
|
||||
"\u008f\u0251\u0003\u0002\u0002\u0002\u0091\u0264\u0003\u0002\u0002\u0002",
|
||||
"\u0093\u027f\u0003\u0002\u0002\u0002\u0095\u0281\u0003\u0002\u0002\u0002",
|
||||
"\u0097\u0293\u0003\u0002\u0002\u0002\u0099\u02a1\u0003\u0002\u0002\u0002",
|
||||
"\u009b\u02a5\u0003\u0002\u0002\u0002\u009d\u02a7\u0003\u0002\u0002\u0002",
|
||||
"\u009f\u02a9\u0003\u0002\u0002\u0002\u00a1\u02ab\u0003\u0002\u0002\u0002",
|
||||
"\u00a3\u02ad\u0003\u0002\u0002\u0002\u00a5\u02af\u0003\u0002\u0002\u0002",
|
||||
"\u00a7\u02b1\u0003\u0002\u0002\u0002\u00a9\u02b3\u0003\u0002\u0002\u0002",
|
||||
"\u00ab\u02b5\u0003\u0002\u0002\u0002\u00ad\u02b7\u0003\u0002\u0002\u0002",
|
||||
"\u00af\u02b9\u0003\u0002\u0002\u0002\u00b1\u02bb\u0003\u0002\u0002\u0002",
|
||||
"\u00b3\u02bd\u0003\u0002\u0002\u0002\u00b5\u02bf\u0003\u0002\u0002\u0002",
|
||||
"\u00b7\u02c1\u0003\u0002\u0002\u0002\u00b9\u02c3\u0003\u0002\u0002\u0002",
|
||||
"\u00bb\u02c5\u0003\u0002\u0002\u0002\u00bd\u02c7\u0003\u0002\u0002\u0002",
|
||||
"\u00bf\u02c9\u0003\u0002\u0002\u0002\u00c1\u02cb\u0003\u0002\u0002\u0002",
|
||||
"\u00c3\u02cd\u0003\u0002\u0002\u0002\u00c5\u02cf\u0003\u0002\u0002\u0002",
|
||||
"\u00c7\u02d1\u0003\u0002\u0002\u0002\u00c9\u02d3\u0003\u0002\u0002\u0002",
|
||||
"\u00cb\u02d5\u0003\u0002\u0002\u0002\u00cd\u02d7\u0003\u0002\u0002\u0002",
|
||||
"\u00cf\u02d9\u0003\u0002\u0002\u0002\u00d1\u02db\u0003\u0002\u0002\u0002",
|
||||
"\u00d3\u02dd\u0003\u0002\u0002\u0002\u00d5\u02df\u0003\u0002\u0002\u0002",
|
||||
"\u00d7\u00d8\u00070\u0002\u0002\u00d8\u0004\u0003\u0002\u0002\u0002",
|
||||
"\u00d9\u00da\u0007?\u0002\u0002\u00da\u00db\u0007\u0080\u0002\u0002",
|
||||
"\u00db\u0006\u0003\u0002\u0002\u0002\u00dc\u00dd\u0007#\u0002\u0002",
|
||||
"\u00dd\u00de\u0007\u0080\u0002\u0002\u00de\b\u0003\u0002\u0002\u0002",
|
||||
"\u00df\u00e0\u0007?\u0002\u0002\u00e0\u00e1\u0007?\u0002\u0002\u00e1",
|
||||
"\n\u0003\u0002\u0002\u0002\u00e2\u00e3\u0007#\u0002\u0002\u00e3\u00e4",
|
||||
"\u0007?\u0002\u0002\u00e4\f\u0003\u0002\u0002\u0002\u00e5\u00e6\u0007",
|
||||
">\u0002\u0002\u00e6\u000e\u0003\u0002\u0002\u0002\u00e7\u00e8\u0007",
|
||||
"@\u0002\u0002\u00e8\u0010\u0003\u0002\u0002\u0002\u00e9\u00ea\u0007",
|
||||
">\u0002\u0002\u00ea\u00eb\u0007?\u0002\u0002\u00eb\u0012\u0003\u0002",
|
||||
"\u0002\u0002\u00ec\u00ed\u0007@\u0002\u0002\u00ed\u00ee\u0007?\u0002",
|
||||
"\u0002\u00ee\u0014\u0003\u0002\u0002\u0002\u00ef\u00f0\u0007-\u0002",
|
||||
"\u0002\u00f0\u0016\u0003\u0002\u0002\u0002\u00f1\u00f2\u0007/\u0002",
|
||||
"\u0002\u00f2\u0018\u0003\u0002\u0002\u0002\u00f3\u00f4\u0007,\u0002",
|
||||
"\u0002\u00f4\u001a\u0003\u0002\u0002\u0002\u00f5\u00f6\u00071\u0002",
|
||||
"\u0002\u00f6\u001c\u0003\u0002\u0002\u0002\u00f7\u00f8\u0007\'\u0002",
|
||||
"\u0002\u00f8\u001e\u0003\u0002\u0002\u0002\u00f9\u00fa\u0007A\u0002",
|
||||
"\u0002\u00fa \u0003\u0002\u0002\u0002\u00fb\u00fc\u0007<\u0002\u0002",
|
||||
"\u00fc\"\u0003\u0002\u0002\u0002\u00fd\u00fe\u0007<\u0002\u0002\u00fe",
|
||||
"\u00ff\u0007<\u0002\u0002\u00ff$\u0003\u0002\u0002\u0002\u0100\u0101",
|
||||
"\u00070\u0002\u0002\u0101\u0102\u00070\u0002\u0002\u0102&\u0003\u0002",
|
||||
"\u0002\u0002\u0103\u0104\u0007.\u0002\u0002\u0104(\u0003\u0002\u0002",
|
||||
"\u0002\u0105\u0106\u0007*\u0002\u0002\u0106*\u0003\u0002\u0002\u0002",
|
||||
"\u0107\u0108\u0007+\u0002\u0002\u0108,\u0003\u0002\u0002\u0002\u0109",
|
||||
"\u010a\u0007}\u0002\u0002\u010a.\u0003\u0002\u0002\u0002\u010b\u010c",
|
||||
"\u0007\u007f\u0002\u0002\u010c0\u0003\u0002\u0002\u0002\u010d\u010e",
|
||||
"\u0007]\u0002\u0002\u010e2\u0003\u0002\u0002\u0002\u010f\u0110\u0007",
|
||||
"_\u0002\u0002\u01104\u0003\u0002\u0002\u0002\u0111\u0112\u0005\u00a1",
|
||||
"Q\u0002\u0112\u0113\u0005\u00adW\u0002\u0113\u0114\u0005\u00adW\u0002",
|
||||
"\u0114\u0115\u0005\u00c3b\u0002\u0115\u0116\u0005\u00a9U\u0002\u0116",
|
||||
"\u0117\u0005\u00adW\u0002\u0117\u0118\u0005\u00a1Q\u0002\u0118\u0119",
|
||||
"\u0005\u00c7d\u0002\u0119\u011a\u0005\u00a9U\u0002\u011a6\u0003\u0002",
|
||||
"\u0002\u0002\u011b\u011c\u0005\u00a1Q\u0002\u011c\u011d\u0005\u00b7",
|
||||
"\\\u0002\u011d\u011e\u0005\u00b7\\\u0002\u011e8\u0003\u0002\u0002\u0002",
|
||||
"\u011f\u0120\u0005\u00a1Q\u0002\u0120\u0121\u0005\u00bb^\u0002\u0121",
|
||||
"\u0122\u0005\u00a7T\u0002\u0122\u0126\u0003\u0002\u0002\u0002\u0123",
|
||||
"\u0124\u0007(\u0002\u0002\u0124\u0126\u0007(\u0002\u0002\u0125\u011f",
|
||||
"\u0003\u0002\u0002\u0002\u0125\u0123\u0003\u0002\u0002\u0002\u0126:",
|
||||
"\u0003\u0002\u0002\u0002\u0127\u0128\u0005\u00a1Q\u0002\u0128\u0129",
|
||||
"\u0005\u00bb^\u0002\u0129\u012a\u0005\u00d1i\u0002\u012a<\u0003\u0002",
|
||||
"\u0002\u0002\u012b\u012c\u0005\u00a1Q\u0002\u012c\u012d\u0005\u00c5",
|
||||
"c\u0002\u012d\u012e\u0005\u00a5S\u0002\u012e>\u0003\u0002\u0002\u0002",
|
||||
"\u012f\u0130\u0005\u00a5S\u0002\u0130\u0131\u0005\u00bd_\u0002\u0131",
|
||||
"\u0132\u0005\u00b7\\\u0002\u0132\u0133\u0005\u00b7\\\u0002\u0133\u0134",
|
||||
"\u0005\u00a9U\u0002\u0134\u0135\u0005\u00a5S\u0002\u0135\u0136\u0005",
|
||||
"\u00c7d\u0002\u0136@\u0003\u0002\u0002\u0002\u0137\u0138\u0005\u00a7",
|
||||
"T\u0002\u0138\u0139\u0005\u00a9U\u0002\u0139\u013a\u0005\u00c5c\u0002",
|
||||
"\u013a\u013b\u0005\u00a5S\u0002\u013bB\u0003\u0002\u0002\u0002\u013c",
|
||||
"\u013d\u0005\u00a7T\u0002\u013d\u013e\u0005\u00b1Y\u0002\u013e\u013f",
|
||||
"\u0005\u00c5c\u0002\u013f\u0140\u0005\u00c7d\u0002\u0140\u0141\u0005",
|
||||
"\u00b1Y\u0002\u0141\u0142\u0005\u00bb^\u0002\u0142\u0143\u0005\u00a5",
|
||||
"S\u0002\u0143\u0144\u0005\u00c7d\u0002\u0144D\u0003\u0002\u0002\u0002",
|
||||
"\u0145\u0146\u0005\u00abV\u0002\u0146\u0147\u0005\u00a1Q\u0002\u0147",
|
||||
"\u0148\u0005\u00b7\\\u0002\u0148\u0149\u0005\u00c5c\u0002\u0149\u014a",
|
||||
"\u0005\u00a9U\u0002\u014aF\u0003\u0002\u0002\u0002\u014b\u014c\u0005",
|
||||
"\u00abV\u0002\u014c\u014d\u0005\u00b1Y\u0002\u014d\u014e\u0005\u00b7",
|
||||
"\\\u0002\u014e\u014f\u0005\u00c7d\u0002\u014f\u0150\u0005\u00a9U\u0002",
|
||||
"\u0150\u0151\u0005\u00c3b\u0002\u0151H\u0003\u0002\u0002\u0002\u0152",
|
||||
"\u0153\u0005\u00abV\u0002\u0153\u0154\u0005\u00bd_\u0002\u0154\u0155",
|
||||
"\u0005\u00c3b\u0002\u0155J\u0003\u0002\u0002\u0002\u0156\u0157\u0005",
|
||||
"\u00adW\u0002\u0157\u0158\u0005\u00c3b\u0002\u0158\u0159\u0005\u00a1",
|
||||
"Q\u0002\u0159\u015a\u0005\u00bf`\u0002\u015a\u015b\u0005\u00afX\u0002",
|
||||
"\u015bL\u0003\u0002\u0002\u0002\u015c\u015d\u0005\u00b1Y\u0002\u015d",
|
||||
"\u015e\u0005\u00bb^\u0002\u015eN\u0003\u0002\u0002\u0002\u015f\u0160",
|
||||
"\u0005\u00b1Y\u0002\u0160\u0161\u0005\u00bb^\u0002\u0161\u0162\u0005",
|
||||
"\u00a3R\u0002\u0162\u0163\u0005\u00bd_\u0002\u0163\u0164\u0005\u00c9",
|
||||
"e\u0002\u0164\u0165\u0005\u00bb^\u0002\u0165\u0166\u0005\u00a7T\u0002",
|
||||
"\u0166P\u0003\u0002\u0002\u0002\u0167\u0168\u0005\u00b1Y\u0002\u0168",
|
||||
"\u0169\u0005\u00bb^\u0002\u0169\u016a\u0005\u00c5c\u0002\u016a\u016b",
|
||||
"\u0005\u00a9U\u0002\u016b\u016c\u0005\u00c3b\u0002\u016c\u016d\u0005",
|
||||
"\u00c7d\u0002\u016dR\u0003\u0002\u0002\u0002\u016e\u016f\u0005\u00b1",
|
||||
"Y\u0002\u016f\u0170\u0005\u00bb^\u0002\u0170\u0171\u0005\u00c7d\u0002",
|
||||
"\u0171\u0172\u0005\u00bd_\u0002\u0172T\u0003\u0002\u0002\u0002\u0173",
|
||||
"\u0174\u0005\u00b5[\u0002\u0174\u0175\u0007a\u0002\u0002\u0175\u0176",
|
||||
"\u0005\u00c5c\u0002\u0176\u0177\u0005\u00afX\u0002\u0177\u0178\u0005",
|
||||
"\u00bd_\u0002\u0178\u0179\u0005\u00c3b\u0002\u0179\u017a\u0005\u00c7",
|
||||
"d\u0002\u017a\u017b\u0005\u00a9U\u0002\u017b\u017c\u0005\u00c5c\u0002",
|
||||
"\u017c\u017d\u0005\u00c7d\u0002\u017d\u017e\u0007a\u0002\u0002\u017e",
|
||||
"\u017f\u0005\u00bf`\u0002\u017f\u0180\u0005\u00a1Q\u0002\u0180\u0181",
|
||||
"\u0005\u00c7d\u0002\u0181\u0182\u0005\u00afX\u0002\u0182\u0183\u0005",
|
||||
"\u00c5c\u0002\u0183V\u0003\u0002\u0002\u0002\u0184\u0185\u0005\u00b7",
|
||||
"\\\u0002\u0185\u0186\u0005\u00a9U\u0002\u0186\u0187\u0005\u00c7d\u0002",
|
||||
"\u0187X\u0003\u0002\u0002\u0002\u0188\u0189\u0005\u00b7\\\u0002\u0189",
|
||||
"\u018a\u0005\u00b1Y\u0002\u018a\u018b\u0005\u00b5[\u0002\u018b\u018c",
|
||||
"\u0005\u00a9U\u0002\u018cZ\u0003\u0002\u0002\u0002\u018d\u018e\u0005",
|
||||
"\u00b7\\\u0002\u018e\u018f\u0005\u00b1Y\u0002\u018f\u0190\u0005\u00b9",
|
||||
"]\u0002\u0190\u0191\u0005\u00b1Y\u0002\u0191\u0192\u0005\u00c7d\u0002",
|
||||
"\u0192\\\u0003\u0002\u0002\u0002\u0193\u0194\u0005\u00bb^\u0002\u0194",
|
||||
"\u0195\u0005\u00bd_\u0002\u0195\u0196\u0005\u00bb^\u0002\u0196\u0197",
|
||||
"\u0005\u00a9U\u0002\u0197^\u0003\u0002\u0002\u0002\u0198\u0199\u0005",
|
||||
"\u00bb^\u0002\u0199\u019a\u0005\u00bd_\u0002\u019a\u019b\u0005\u00c7",
|
||||
"d\u0002\u019b\u019e\u0003\u0002\u0002\u0002\u019c\u019e\u0007#\u0002",
|
||||
"\u0002\u019d\u0198\u0003\u0002\u0002\u0002\u019d\u019c\u0003\u0002\u0002",
|
||||
"\u0002\u019e`\u0003\u0002\u0002\u0002\u019f\u01a0\u0005\u00bb^\u0002",
|
||||
"\u01a0\u01a1\u0005\u00c9e\u0002\u01a1\u01a2\u0005\u00b7\\\u0002\u01a2",
|
||||
"\u01a3\u0005\u00b7\\\u0002\u01a3b\u0003\u0002\u0002\u0002\u01a4\u01a5",
|
||||
"\u0005\u00bd_\u0002\u01a5\u01a6\u0005\u00c3b\u0002\u01a6\u01aa\u0003",
|
||||
"\u0002\u0002\u0002\u01a7\u01a8\u0007~\u0002\u0002\u01a8\u01aa\u0007",
|
||||
"~\u0002\u0002\u01a9\u01a4\u0003\u0002\u0002\u0002\u01a9\u01a7\u0003",
|
||||
"\u0002\u0002\u0002\u01aad\u0003\u0002\u0002\u0002\u01ab\u01ac\u0005",
|
||||
"\u00bd_\u0002\u01ac\u01ad\u0005\u00c9e\u0002\u01ad\u01ae\u0005\u00c7",
|
||||
"d\u0002\u01ae\u01af\u0005\u00a3R\u0002\u01af\u01b0\u0005\u00bd_\u0002",
|
||||
"\u01b0\u01b1\u0005\u00c9e\u0002\u01b1\u01b2\u0005\u00bb^\u0002\u01b2",
|
||||
"\u01b3\u0005\u00a7T\u0002\u01b3f\u0003\u0002\u0002\u0002\u01b4\u01b5",
|
||||
"\u0005\u00c3b\u0002\u01b5\u01b6\u0005\u00a9U\u0002\u01b6\u01b7\u0005",
|
||||
"\u00b9]\u0002\u01b7\u01b8\u0005\u00bd_\u0002\u01b8\u01b9\u0005\u00cb",
|
||||
"f\u0002\u01b9\u01ba\u0005\u00a9U\u0002\u01bah\u0003\u0002\u0002\u0002",
|
||||
"\u01bb\u01bc\u0005\u00c3b\u0002\u01bc\u01bd\u0005\u00a9U\u0002\u01bd",
|
||||
"\u01be\u0005\u00bf`\u0002\u01be\u01bf\u0005\u00b7\\\u0002\u01bf\u01c0",
|
||||
"\u0005\u00a1Q\u0002\u01c0\u01c1\u0005\u00a5S\u0002\u01c1\u01c2\u0005",
|
||||
"\u00a9U\u0002\u01c2j\u0003\u0002\u0002\u0002\u01c3\u01c4\u0005\u00c3",
|
||||
"b\u0002\u01c4\u01c5\u0005\u00a9U\u0002\u01c5\u01c6\u0005\u00c7d\u0002",
|
||||
"\u01c6\u01c7\u0005\u00c9e\u0002\u01c7\u01c8\u0005\u00c3b\u0002\u01c8",
|
||||
"\u01c9\u0005\u00bb^\u0002\u01c9l\u0003\u0002\u0002\u0002\u01ca\u01cb",
|
||||
"\u0005\u00c5c\u0002\u01cb\u01cc\u0005\u00afX\u0002\u01cc\u01cd\u0005",
|
||||
"\u00bd_\u0002\u01cd\u01ce\u0005\u00c3b\u0002\u01ce\u01cf\u0005\u00c7",
|
||||
"d\u0002\u01cf\u01d0\u0005\u00a9U\u0002\u01d0\u01d1\u0005\u00c5c\u0002",
|
||||
"\u01d1\u01d2\u0005\u00c7d\u0002\u01d2\u01d3\u0007a\u0002\u0002\u01d3",
|
||||
"\u01d4\u0005\u00bf`\u0002\u01d4\u01d5\u0005\u00a1Q\u0002\u01d5\u01d6",
|
||||
"\u0005\u00c7d\u0002\u01d6\u01d7\u0005\u00afX\u0002\u01d7n\u0003\u0002",
|
||||
"\u0002\u0002\u01d8\u01d9\u0005\u00c5c\u0002\u01d9\u01da\u0005\u00bd",
|
||||
"_\u0002\u01da\u01db\u0005\u00c3b\u0002\u01db\u01dc\u0005\u00c7d\u0002",
|
||||
"\u01dcp\u0003\u0002\u0002\u0002\u01dd\u01de\u0005\u00c7d\u0002\u01de",
|
||||
"\u01df\u0005\u00c3b\u0002\u01df\u01e0\u0005\u00c9e\u0002\u01e0\u01e1",
|
||||
"\u0005\u00a9U\u0002\u01e1r\u0003\u0002\u0002\u0002\u01e2\u01e3\u0005",
|
||||
"\u00c9e\u0002\u01e3\u01e4\u0005\u00bf`\u0002\u01e4\u01e5\u0005\u00a7",
|
||||
"T\u0002\u01e5\u01e6\u0005\u00a1Q\u0002\u01e6\u01e7\u0005\u00c7d\u0002",
|
||||
"\u01e7\u01e8\u0005\u00a9U\u0002\u01e8t\u0003\u0002\u0002\u0002\u01e9",
|
||||
"\u01ea\u0005\u00c9e\u0002\u01ea\u01eb\u0005\u00bf`\u0002\u01eb\u01ec",
|
||||
"\u0005\u00c5c\u0002\u01ec\u01ed\u0005\u00a9U\u0002\u01ed\u01ee\u0005",
|
||||
"\u00c3b\u0002\u01ee\u01ef\u0005\u00c7d\u0002\u01efv\u0003\u0002\u0002",
|
||||
"\u0002\u01f0\u01f1\u0005\u00cdg\u0002\u01f1\u01f2\u0005\u00b1Y\u0002",
|
||||
"\u01f2\u01f3\u0005\u00c7d\u0002\u01f3\u01f4\u0005\u00afX\u0002\u01f4",
|
||||
"x\u0003\u0002\u0002\u0002\u01f5\u01f6\u0005\u00b5[\u0002\u01f6\u01f7",
|
||||
"\u0005\u00a9U\u0002\u01f7\u01f8\u0005\u00a9U\u0002\u01f8\u01f9\u0005",
|
||||
"\u00bf`\u0002\u01f9z\u0003\u0002\u0002\u0002\u01fa\u01fb\u0005\u00a5",
|
||||
"S\u0002\u01fb\u01fc\u0005\u00bd_\u0002\u01fc\u01fd\u0005\u00c9e\u0002",
|
||||
"\u01fd\u01fe\u0005\u00bb^\u0002\u01fe\u01ff\u0005\u00c7d\u0002\u01ff",
|
||||
"|\u0003\u0002\u0002\u0002\u0200\u0201\u0005\u00bd_\u0002\u0201\u0202",
|
||||
"\u0005\u00bf`\u0002\u0202\u0203\u0005\u00c7d\u0002\u0203\u0204\u0005",
|
||||
"\u00b1Y\u0002\u0204\u0205\u0005\u00bd_\u0002\u0205\u0206\u0005\u00bb",
|
||||
"^\u0002\u0206\u0207\u0005\u00c5c\u0002\u0207~\u0003\u0002\u0002\u0002",
|
||||
"\u0208\u0209\u0005\u00bf`\u0002\u0209\u020a\u0005\u00c3b\u0002\u020a",
|
||||
"\u020b\u0005\u00c9e\u0002\u020b\u020c\u0005\u00bb^\u0002\u020c\u020d",
|
||||
"\u0005\u00a9U\u0002\u020d\u0080\u0003\u0002\u0002\u0002\u020e\u020f",
|
||||
"\u0005\u00c5c\u0002\u020f\u0210\u0005\u00a9U\u0002\u0210\u0211\u0005",
|
||||
"\u00a1Q\u0002\u0211\u0212\u0005\u00c3b\u0002\u0212\u0213\u0005\u00a5",
|
||||
"S\u0002\u0213\u0214\u0005\u00afX\u0002\u0214\u0082\u0003\u0002\u0002",
|
||||
"\u0002\u0215\u0216\u0005\u00c7d\u0002\u0216\u0217\u0005\u00bd_\u0002",
|
||||
"\u0217\u0084\u0003\u0002\u0002\u0002\u0218\u0219\u0005\u00a5S\u0002",
|
||||
"\u0219\u021a\u0005\u00c9e\u0002\u021a\u021b\u0005\u00c3b\u0002\u021b",
|
||||
"\u021c\u0005\u00c3b\u0002\u021c\u021d\u0005\u00a9U\u0002\u021d\u021e",
|
||||
"\u0005\u00bb^\u0002\u021e\u021f\u0005\u00c7d\u0002\u021f\u0086\u0003",
|
||||
"\u0002\u0002\u0002\u0220\u0221\u0005\u00bb^\u0002\u0221\u0222\u0005",
|
||||
"\u00a9U\u0002\u0222\u0223\u0005\u00cdg\u0002\u0223\u0088\u0003\u0002",
|
||||
"\u0002\u0002\u0224\u0225\u0005\u00bd_\u0002\u0225\u0226\u0005\u00b7",
|
||||
"\\\u0002\u0226\u0227\u0005\u00a7T\u0002\u0227\u008a\u0003\u0002\u0002",
|
||||
"\u0002\u0228\u022c\t\u0002\u0002\u0002\u0229\u022b\t\u0003\u0002\u0002",
|
||||
"\u022a\u0229\u0003\u0002\u0002\u0002\u022b\u022e\u0003\u0002\u0002\u0002",
|
||||
"\u022c\u022a\u0003\u0002\u0002\u0002\u022c\u022d\u0003\u0002\u0002\u0002",
|
||||
"\u022d\u008c\u0003\u0002\u0002\u0002\u022e\u022c\u0003\u0002\u0002\u0002",
|
||||
"\u022f\u0233\t\u0004\u0002\u0002\u0230\u0232\u0005\u009fP\u0002\u0231",
|
||||
"\u0230\u0003\u0002\u0002\u0002\u0232\u0235\u0003\u0002\u0002\u0002\u0233",
|
||||
"\u0231\u0003\u0002\u0002\u0002\u0233\u0234\u0003\u0002\u0002\u0002\u0234",
|
||||
"\u0248\u0003\u0002\u0002\u0002\u0235\u0233\u0003\u0002\u0002\u0002\u0236",
|
||||
"\u0248\u00072\u0002\u0002\u0237\u0238\u00072\u0002\u0002\u0238\u0239",
|
||||
"\u0007z\u0002\u0002\u0239\u023b\u0003\u0002\u0002\u0002\u023a\u023c",
|
||||
"\u0005\u009dO\u0002\u023b\u023a\u0003\u0002\u0002\u0002\u023c\u023d",
|
||||
"\u0003\u0002\u0002\u0002\u023d\u023b\u0003\u0002\u0002\u0002\u023d\u023e",
|
||||
"\u0003\u0002\u0002\u0002\u023e\u0248\u0003\u0002\u0002\u0002\u023f\u0240",
|
||||
"\u00072\u0002\u0002\u0240\u0241\u0007d\u0002\u0002\u0241\u0243\u0003",
|
||||
"\u0002\u0002\u0002\u0242\u0244\t\u0005\u0002\u0002\u0243\u0242\u0003",
|
||||
"\u0002\u0002\u0002\u0244\u0245\u0003\u0002\u0002\u0002\u0245\u0243\u0003",
|
||||
"\u0002\u0002\u0002\u0245\u0246\u0003\u0002\u0002\u0002\u0246\u0248\u0003",
|
||||
"\u0002\u0002\u0002\u0247\u022f\u0003\u0002\u0002\u0002\u0247\u0236\u0003",
|
||||
"\u0002\u0002\u0002\u0247\u0237\u0003\u0002\u0002\u0002\u0247\u023f\u0003",
|
||||
"\u0002\u0002\u0002\u0248\u008e\u0003\u0002\u0002\u0002\u0249\u024d\t",
|
||||
"\u0004\u0002\u0002\u024a\u024c\u0005\u009fP\u0002\u024b\u024a\u0003",
|
||||
"\u0002\u0002\u0002\u024c\u024f\u0003\u0002\u0002\u0002\u024d\u024b\u0003",
|
||||
"\u0002\u0002\u0002\u024d\u024e\u0003\u0002\u0002\u0002\u024e\u0252\u0003",
|
||||
"\u0002\u0002\u0002\u024f\u024d\u0003\u0002\u0002\u0002\u0250\u0252\u0007",
|
||||
"2\u0002\u0002\u0251\u0249\u0003\u0002\u0002\u0002\u0251\u0250\u0003",
|
||||
"\u0002\u0002\u0002\u0251\u0252\u0003\u0002\u0002\u0002\u0252\u0253\u0003",
|
||||
"\u0002\u0002\u0002\u0253\u0255\u00070\u0002\u0002\u0254\u0256\u0005",
|
||||
"\u009fP\u0002\u0255\u0254\u0003\u0002\u0002\u0002\u0256\u0257\u0003",
|
||||
"\u0002\u0002\u0002\u0257\u0255\u0003\u0002\u0002\u0002\u0257\u0258\u0003",
|
||||
"\u0002\u0002\u0002\u0258\u0262\u0003\u0002\u0002\u0002\u0259\u025b\u0005",
|
||||
"\u00a9U\u0002\u025a\u025c\t\u0006\u0002\u0002\u025b\u025a\u0003\u0002",
|
||||
"\u0002\u0002\u025b\u025c\u0003\u0002\u0002\u0002\u025c\u025e\u0003\u0002",
|
||||
"\u0002\u0002\u025d\u025f\u0005\u009fP\u0002\u025e\u025d\u0003\u0002",
|
||||
"\u0002\u0002\u025f\u0260\u0003\u0002\u0002\u0002\u0260\u025e\u0003\u0002",
|
||||
"\u0002\u0002\u0260\u0261\u0003\u0002\u0002\u0002\u0261\u0263\u0003\u0002",
|
||||
"\u0002\u0002\u0262\u0259\u0003\u0002\u0002\u0002\u0262\u0263\u0003\u0002",
|
||||
"\u0002\u0002\u0263\u0090\u0003\u0002\u0002\u0002\u0264\u0265\u0007B",
|
||||
"\u0002\u0002\u0265\u0266\u0005\u008bF\u0002\u0266\u0092\u0003\u0002",
|
||||
"\u0002\u0002\u0267\u026f\u0007)\u0002\u0002\u0268\u0269\u0007^\u0002",
|
||||
"\u0002\u0269\u026e\u000b\u0002\u0002\u0002\u026a\u026b\u0007)\u0002",
|
||||
"\u0002\u026b\u026e\u0007)\u0002\u0002\u026c\u026e\n\u0007\u0002\u0002",
|
||||
"\u026d\u0268\u0003\u0002\u0002\u0002\u026d\u026a\u0003\u0002\u0002\u0002",
|
||||
"\u026d\u026c\u0003\u0002\u0002\u0002\u026e\u0271\u0003\u0002\u0002\u0002",
|
||||
"\u026f\u026d\u0003\u0002\u0002\u0002\u026f\u0270\u0003\u0002\u0002\u0002",
|
||||
"\u0270\u0272\u0003\u0002\u0002\u0002\u0271\u026f\u0003\u0002\u0002\u0002",
|
||||
"\u0272\u0280\u0007)\u0002\u0002\u0273\u027b\u0007$\u0002\u0002\u0274",
|
||||
"\u0275\u0007^\u0002\u0002\u0275\u027a\u000b\u0002\u0002\u0002\u0276",
|
||||
"\u0277\u0007$\u0002\u0002\u0277\u027a\u0007$\u0002\u0002\u0278\u027a",
|
||||
"\n\b\u0002\u0002\u0279\u0274\u0003\u0002\u0002\u0002\u0279\u0276\u0003",
|
||||
"\u0002\u0002\u0002\u0279\u0278\u0003\u0002\u0002\u0002\u027a\u027d\u0003",
|
||||
"\u0002\u0002\u0002\u027b\u0279\u0003\u0002\u0002\u0002\u027b\u027c\u0003",
|
||||
"\u0002\u0002\u0002\u027c\u027e\u0003\u0002\u0002\u0002\u027d\u027b\u0003",
|
||||
"\u0002\u0002\u0002\u027e\u0280\u0007$\u0002\u0002\u027f\u0267\u0003",
|
||||
"\u0002\u0002\u0002\u027f\u0273\u0003\u0002\u0002\u0002\u0280\u0094\u0003",
|
||||
"\u0002\u0002\u0002\u0281\u0282\u00071\u0002\u0002\u0282\u0283\u0007",
|
||||
"1\u0002\u0002\u0283\u0287\u0003\u0002\u0002\u0002\u0284\u0286\n\t\u0002",
|
||||
"\u0002\u0285\u0284\u0003\u0002\u0002\u0002\u0286\u0289\u0003\u0002\u0002",
|
||||
"\u0002\u0287\u0285\u0003\u0002\u0002\u0002\u0287\u0288\u0003\u0002\u0002",
|
||||
"\u0002\u0288\u028f\u0003\u0002\u0002\u0002\u0289\u0287\u0003\u0002\u0002",
|
||||
"\u0002\u028a\u028c\u0007\u000f\u0002\u0002\u028b\u028a\u0003\u0002\u0002",
|
||||
"\u0002\u028b\u028c\u0003\u0002\u0002\u0002\u028c\u028d\u0003\u0002\u0002",
|
||||
"\u0002\u028d\u0290\u0007\f\u0002\u0002\u028e\u0290\u0007\u0002\u0002",
|
||||
"\u0003\u028f\u028b\u0003\u0002\u0002\u0002\u028f\u028e\u0003\u0002\u0002",
|
||||
"\u0002\u0290\u0291\u0003\u0002\u0002\u0002\u0291\u0292\bK\u0002\u0002",
|
||||
"\u0292\u0096\u0003\u0002\u0002\u0002\u0293\u0294\u00071\u0002\u0002",
|
||||
"\u0294\u0295\u0007,\u0002\u0002\u0295\u0299\u0003\u0002\u0002\u0002",
|
||||
"\u0296\u0298\u000b\u0002\u0002\u0002\u0297\u0296\u0003\u0002\u0002\u0002",
|
||||
"\u0298\u029b\u0003\u0002\u0002\u0002\u0299\u029a\u0003\u0002\u0002\u0002",
|
||||
"\u0299\u0297\u0003\u0002\u0002\u0002\u029a\u029c\u0003\u0002\u0002\u0002",
|
||||
"\u029b\u0299\u0003\u0002\u0002\u0002\u029c\u029d\u0007,\u0002\u0002",
|
||||
"\u029d\u029e\u00071\u0002\u0002\u029e\u029f\u0003\u0002\u0002\u0002",
|
||||
"\u029f\u02a0\bL\u0002\u0002\u02a0\u0098\u0003\u0002\u0002\u0002\u02a1",
|
||||
"\u02a2\t\n\u0002\u0002\u02a2\u02a3\u0003\u0002\u0002\u0002\u02a3\u02a4",
|
||||
"\bM\u0002\u0002\u02a4\u009a\u0003\u0002\u0002\u0002\u02a5\u02a6\u000b",
|
||||
"\u0002\u0002\u0002\u02a6\u009c\u0003\u0002\u0002\u0002\u02a7\u02a8\t",
|
||||
"\u000b\u0002\u0002\u02a8\u009e\u0003\u0002\u0002\u0002\u02a9\u02aa\t",
|
||||
"\f\u0002\u0002\u02aa\u00a0\u0003\u0002\u0002\u0002\u02ab\u02ac\t\r\u0002",
|
||||
"\u0002\u02ac\u00a2\u0003\u0002\u0002\u0002\u02ad\u02ae\t\u000e\u0002",
|
||||
"\u0002\u02ae\u00a4\u0003\u0002\u0002\u0002\u02af\u02b0\t\u000f\u0002",
|
||||
"\u0002\u02b0\u00a6\u0003\u0002\u0002\u0002\u02b1\u02b2\t\u0010\u0002",
|
||||
"\u0002\u02b2\u00a8\u0003\u0002\u0002\u0002\u02b3\u02b4\t\u0011\u0002",
|
||||
"\u0002\u02b4\u00aa\u0003\u0002\u0002\u0002\u02b5\u02b6\t\u0012\u0002",
|
||||
"\u0002\u02b6\u00ac\u0003\u0002\u0002\u0002\u02b7\u02b8\t\u0013\u0002",
|
||||
"\u0002\u02b8\u00ae\u0003\u0002\u0002\u0002\u02b9\u02ba\t\u0014\u0002",
|
||||
"\u0002\u02ba\u00b0\u0003\u0002\u0002\u0002\u02bb\u02bc\t\u0015\u0002",
|
||||
"\u0002\u02bc\u00b2\u0003\u0002\u0002\u0002\u02bd\u02be\t\u0016\u0002",
|
||||
"\u0002\u02be\u00b4\u0003\u0002\u0002\u0002\u02bf\u02c0\t\u0017\u0002",
|
||||
"\u0002\u02c0\u00b6\u0003\u0002\u0002\u0002\u02c1\u02c2\t\u0018\u0002",
|
||||
"\u0002\u02c2\u00b8\u0003\u0002\u0002\u0002\u02c3\u02c4\t\u0019\u0002",
|
||||
"\u0002\u02c4\u00ba\u0003\u0002\u0002\u0002\u02c5\u02c6\t\u001a\u0002",
|
||||
"\u0002\u02c6\u00bc\u0003\u0002\u0002\u0002\u02c7\u02c8\t\u001b\u0002",
|
||||
"\u0002\u02c8\u00be\u0003\u0002\u0002\u0002\u02c9\u02ca\t\u001c\u0002",
|
||||
"\u0002\u02ca\u00c0\u0003\u0002\u0002\u0002\u02cb\u02cc\t\u001d\u0002",
|
||||
"\u0002\u02cc\u00c2\u0003\u0002\u0002\u0002\u02cd\u02ce\t\u001e\u0002",
|
||||
"\u0002\u02ce\u00c4\u0003\u0002\u0002\u0002\u02cf\u02d0\t\u001f\u0002",
|
||||
"\u0002\u02d0\u00c6\u0003\u0002\u0002\u0002\u02d1\u02d2\t \u0002\u0002",
|
||||
"\u02d2\u00c8\u0003\u0002\u0002\u0002\u02d3\u02d4\t!\u0002\u0002\u02d4",
|
||||
"\u00ca\u0003\u0002\u0002\u0002\u02d5\u02d6\t\"\u0002\u0002\u02d6\u00cc",
|
||||
"\u0003\u0002\u0002\u0002\u02d7\u02d8\t#\u0002\u0002\u02d8\u00ce\u0003",
|
||||
"\u0002\u0002\u0002\u02d9\u02da\t$\u0002\u0002\u02da\u00d0\u0003\u0002",
|
||||
"\u0002\u0002\u02db\u02dc\t%\u0002\u0002\u02dc\u00d2\u0003\u0002\u0002",
|
||||
"\u0002\u02dd\u02de\t&\u0002\u0002\u02de\u00d4\u0003\u0002\u0002\u0002",
|
||||
"\u02df\u02e0\u000b\u0002\u0002\u0002\u02e0\u02e1\u0003\u0002\u0002\u0002",
|
||||
"\u02e1\u02e2\bk\u0003\u0002\u02e2\u00d6\u0003\u0002\u0002\u0002\u001a",
|
||||
"\u0002\u0125\u019d\u01a9\u022c\u0233\u023d\u0245\u0247\u024d\u0251\u0257",
|
||||
"\u025b\u0260\u0262\u026d\u026f\u0279\u027b\u027f\u0287\u028b\u028f\u0299",
|
||||
"\u0004\u0002\u0003\u0002\u0002\u0004\u0002"].join("");
|
||||
|
||||
|
||||
const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
|
||||
|
||||
const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) );
|
||||
|
||||
export default class CAQLLexer extends antlr4.Lexer {
|
||||
|
||||
static grammarFileName = "CAQLLexer.g4";
|
||||
static channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "ERRORCHANNEL" ];
|
||||
static modeNames = [ "DEFAULT_MODE" ];
|
||||
static literalNames = [ null, "'.'", "'=~'", "'!~'", "'=='", "'!='", "'<'",
|
||||
"'>'", "'<='", "'>='", "'+'", "'-'", "'*'", "'/'",
|
||||
"'%'", "'?'", "':'", "'::'", "'..'", "','", "'('",
|
||||
"')'", "'{'", "'}'", "'['", "']'" ];
|
||||
static symbolicNames = [ null, "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH",
|
||||
"T_EQ", "T_NE", "T_LT", "T_GT", "T_LE", "T_GE",
|
||||
"T_PLUS", "T_MINUS", "T_TIMES", "T_DIV", "T_MOD",
|
||||
"T_QUESTION", "T_COLON", "T_SCOPE", "T_RANGE",
|
||||
"T_COMMA", "T_OPEN", "T_CLOSE", "T_OBJECT_OPEN",
|
||||
"T_OBJECT_CLOSE", "T_ARRAY_OPEN", "T_ARRAY_CLOSE",
|
||||
"T_AGGREGATE", "T_ALL", "T_AND", "T_ANY", "T_ASC",
|
||||
"T_COLLECT", "T_DESC", "T_DISTINCT", "T_FALSE",
|
||||
"T_FILTER", "T_FOR", "T_GRAPH", "T_IN", "T_INBOUND",
|
||||
"T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS", "T_LET",
|
||||
"T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
|
||||
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE",
|
||||
"T_RETURN", "T_SHORTEST_PATH", "T_SORT", "T_TRUE",
|
||||
"T_UPDATE", "T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT",
|
||||
"T_OPTIONS", "T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT",
|
||||
"T_NEW", "T_OLD", "T_STRING", "T_INT", "T_FLOAT",
|
||||
"T_PARAMETER", "T_QUOTED_STRING", "SINGLE_LINE_COMMENT",
|
||||
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR",
|
||||
"ERROR_RECONGNIGION" ];
|
||||
static ruleNames = [ "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH", "T_EQ",
|
||||
"T_NE", "T_LT", "T_GT", "T_LE", "T_GE", "T_PLUS",
|
||||
"T_MINUS", "T_TIMES", "T_DIV", "T_MOD", "T_QUESTION",
|
||||
"T_COLON", "T_SCOPE", "T_RANGE", "T_COMMA", "T_OPEN",
|
||||
"T_CLOSE", "T_OBJECT_OPEN", "T_OBJECT_CLOSE", "T_ARRAY_OPEN",
|
||||
"T_ARRAY_CLOSE", "T_AGGREGATE", "T_ALL", "T_AND",
|
||||
"T_ANY", "T_ASC", "T_COLLECT", "T_DESC", "T_DISTINCT",
|
||||
"T_FALSE", "T_FILTER", "T_FOR", "T_GRAPH", "T_IN",
|
||||
"T_INBOUND", "T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS",
|
||||
"T_LET", "T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
|
||||
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE", "T_RETURN",
|
||||
"T_SHORTEST_PATH", "T_SORT", "T_TRUE", "T_UPDATE",
|
||||
"T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT", "T_OPTIONS",
|
||||
"T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT", "T_NEW",
|
||||
"T_OLD", "T_STRING", "T_INT", "T_FLOAT", "T_PARAMETER",
|
||||
"T_QUOTED_STRING", "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT",
|
||||
"SPACES", "UNEXPECTED_CHAR", "HEX_DIGIT", "DIGIT",
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
|
||||
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
|
||||
"U", "V", "W", "X", "Y", "Z", "ERROR_RECONGNIGION" ];
|
||||
|
||||
constructor(input) {
|
||||
super(input)
|
||||
this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache());
|
||||
}
|
||||
|
||||
get atn() {
|
||||
return atn;
|
||||
}
|
||||
}
|
||||
|
||||
CAQLLexer.EOF = antlr4.Token.EOF;
|
||||
CAQLLexer.DOT = 1;
|
||||
CAQLLexer.T_REGEX_MATCH = 2;
|
||||
CAQLLexer.T_REGEX_NON_MATCH = 3;
|
||||
CAQLLexer.T_EQ = 4;
|
||||
CAQLLexer.T_NE = 5;
|
||||
CAQLLexer.T_LT = 6;
|
||||
CAQLLexer.T_GT = 7;
|
||||
CAQLLexer.T_LE = 8;
|
||||
CAQLLexer.T_GE = 9;
|
||||
CAQLLexer.T_PLUS = 10;
|
||||
CAQLLexer.T_MINUS = 11;
|
||||
CAQLLexer.T_TIMES = 12;
|
||||
CAQLLexer.T_DIV = 13;
|
||||
CAQLLexer.T_MOD = 14;
|
||||
CAQLLexer.T_QUESTION = 15;
|
||||
CAQLLexer.T_COLON = 16;
|
||||
CAQLLexer.T_SCOPE = 17;
|
||||
CAQLLexer.T_RANGE = 18;
|
||||
CAQLLexer.T_COMMA = 19;
|
||||
CAQLLexer.T_OPEN = 20;
|
||||
CAQLLexer.T_CLOSE = 21;
|
||||
CAQLLexer.T_OBJECT_OPEN = 22;
|
||||
CAQLLexer.T_OBJECT_CLOSE = 23;
|
||||
CAQLLexer.T_ARRAY_OPEN = 24;
|
||||
CAQLLexer.T_ARRAY_CLOSE = 25;
|
||||
CAQLLexer.T_AGGREGATE = 26;
|
||||
CAQLLexer.T_ALL = 27;
|
||||
CAQLLexer.T_AND = 28;
|
||||
CAQLLexer.T_ANY = 29;
|
||||
CAQLLexer.T_ASC = 30;
|
||||
CAQLLexer.T_COLLECT = 31;
|
||||
CAQLLexer.T_DESC = 32;
|
||||
CAQLLexer.T_DISTINCT = 33;
|
||||
CAQLLexer.T_FALSE = 34;
|
||||
CAQLLexer.T_FILTER = 35;
|
||||
CAQLLexer.T_FOR = 36;
|
||||
CAQLLexer.T_GRAPH = 37;
|
||||
CAQLLexer.T_IN = 38;
|
||||
CAQLLexer.T_INBOUND = 39;
|
||||
CAQLLexer.T_INSERT = 40;
|
||||
CAQLLexer.T_INTO = 41;
|
||||
CAQLLexer.T_K_SHORTEST_PATHS = 42;
|
||||
CAQLLexer.T_LET = 43;
|
||||
CAQLLexer.T_LIKE = 44;
|
||||
CAQLLexer.T_LIMIT = 45;
|
||||
CAQLLexer.T_NONE = 46;
|
||||
CAQLLexer.T_NOT = 47;
|
||||
CAQLLexer.T_NULL = 48;
|
||||
CAQLLexer.T_OR = 49;
|
||||
CAQLLexer.T_OUTBOUND = 50;
|
||||
CAQLLexer.T_REMOVE = 51;
|
||||
CAQLLexer.T_REPLACE = 52;
|
||||
CAQLLexer.T_RETURN = 53;
|
||||
CAQLLexer.T_SHORTEST_PATH = 54;
|
||||
CAQLLexer.T_SORT = 55;
|
||||
CAQLLexer.T_TRUE = 56;
|
||||
CAQLLexer.T_UPDATE = 57;
|
||||
CAQLLexer.T_UPSERT = 58;
|
||||
CAQLLexer.T_WITH = 59;
|
||||
CAQLLexer.T_KEEP = 60;
|
||||
CAQLLexer.T_COUNT = 61;
|
||||
CAQLLexer.T_OPTIONS = 62;
|
||||
CAQLLexer.T_PRUNE = 63;
|
||||
CAQLLexer.T_SEARCH = 64;
|
||||
CAQLLexer.T_TO = 65;
|
||||
CAQLLexer.T_CURRENT = 66;
|
||||
CAQLLexer.T_NEW = 67;
|
||||
CAQLLexer.T_OLD = 68;
|
||||
CAQLLexer.T_STRING = 69;
|
||||
CAQLLexer.T_INT = 70;
|
||||
CAQLLexer.T_FLOAT = 71;
|
||||
CAQLLexer.T_PARAMETER = 72;
|
||||
CAQLLexer.T_QUOTED_STRING = 73;
|
||||
CAQLLexer.SINGLE_LINE_COMMENT = 74;
|
||||
CAQLLexer.MULTILINE_COMMENT = 75;
|
||||
CAQLLexer.SPACES = 76;
|
||||
CAQLLexer.UNEXPECTED_CHAR = 77;
|
||||
CAQLLexer.ERROR_RECONGNIGION = 78;
|
||||
|
||||
CAQLLexer.ERRORCHANNEL = 2;
|
||||
|
||||
|
||||
|
||||
103
ui/src/suggestions/grammar/CAQLLexer.tokens
Normal file
@@ -0,0 +1,103 @@
|
||||
DOT=1
|
||||
T_REGEX_MATCH=2
|
||||
T_REGEX_NON_MATCH=3
|
||||
T_EQ=4
|
||||
T_NE=5
|
||||
T_LT=6
|
||||
T_GT=7
|
||||
T_LE=8
|
||||
T_GE=9
|
||||
T_PLUS=10
|
||||
T_MINUS=11
|
||||
T_TIMES=12
|
||||
T_DIV=13
|
||||
T_MOD=14
|
||||
T_QUESTION=15
|
||||
T_COLON=16
|
||||
T_SCOPE=17
|
||||
T_RANGE=18
|
||||
T_COMMA=19
|
||||
T_OPEN=20
|
||||
T_CLOSE=21
|
||||
T_OBJECT_OPEN=22
|
||||
T_OBJECT_CLOSE=23
|
||||
T_ARRAY_OPEN=24
|
||||
T_ARRAY_CLOSE=25
|
||||
T_AGGREGATE=26
|
||||
T_ALL=27
|
||||
T_AND=28
|
||||
T_ANY=29
|
||||
T_ASC=30
|
||||
T_COLLECT=31
|
||||
T_DESC=32
|
||||
T_DISTINCT=33
|
||||
T_FALSE=34
|
||||
T_FILTER=35
|
||||
T_FOR=36
|
||||
T_GRAPH=37
|
||||
T_IN=38
|
||||
T_INBOUND=39
|
||||
T_INSERT=40
|
||||
T_INTO=41
|
||||
T_K_SHORTEST_PATHS=42
|
||||
T_LET=43
|
||||
T_LIKE=44
|
||||
T_LIMIT=45
|
||||
T_NONE=46
|
||||
T_NOT=47
|
||||
T_NULL=48
|
||||
T_OR=49
|
||||
T_OUTBOUND=50
|
||||
T_REMOVE=51
|
||||
T_REPLACE=52
|
||||
T_RETURN=53
|
||||
T_SHORTEST_PATH=54
|
||||
T_SORT=55
|
||||
T_TRUE=56
|
||||
T_UPDATE=57
|
||||
T_UPSERT=58
|
||||
T_WITH=59
|
||||
T_KEEP=60
|
||||
T_COUNT=61
|
||||
T_OPTIONS=62
|
||||
T_PRUNE=63
|
||||
T_SEARCH=64
|
||||
T_TO=65
|
||||
T_CURRENT=66
|
||||
T_NEW=67
|
||||
T_OLD=68
|
||||
T_STRING=69
|
||||
T_INT=70
|
||||
T_FLOAT=71
|
||||
T_PARAMETER=72
|
||||
T_QUOTED_STRING=73
|
||||
SINGLE_LINE_COMMENT=74
|
||||
MULTILINE_COMMENT=75
|
||||
SPACES=76
|
||||
UNEXPECTED_CHAR=77
|
||||
ERROR_RECONGNIGION=78
|
||||
'.'=1
|
||||
'=~'=2
|
||||
'!~'=3
|
||||
'=='=4
|
||||
'!='=5
|
||||
'<'=6
|
||||
'>'=7
|
||||
'<='=8
|
||||
'>='=9
|
||||
'+'=10
|
||||
'-'=11
|
||||
'*'=12
|
||||
'/'=13
|
||||
'%'=14
|
||||
'?'=15
|
||||
':'=16
|
||||
'::'=17
|
||||
'..'=18
|
||||
','=19
|
||||
'('=20
|
||||
')'=21
|
||||
'{'=22
|
||||
'}'=23
|
||||
'['=24
|
||||
']'=25
|
||||
178
ui/src/suggestions/grammar/CAQLParser.interp
Normal file
1866
ui/src/suggestions/grammar/CAQLParser.js
Normal file
103
ui/src/suggestions/grammar/CAQLParser.tokens
Normal file
@@ -0,0 +1,103 @@
|
||||
DOT=1
|
||||
T_REGEX_MATCH=2
|
||||
T_REGEX_NON_MATCH=3
|
||||
T_EQ=4
|
||||
T_NE=5
|
||||
T_LT=6
|
||||
T_GT=7
|
||||
T_LE=8
|
||||
T_GE=9
|
||||
T_PLUS=10
|
||||
T_MINUS=11
|
||||
T_TIMES=12
|
||||
T_DIV=13
|
||||
T_MOD=14
|
||||
T_QUESTION=15
|
||||
T_COLON=16
|
||||
T_SCOPE=17
|
||||
T_RANGE=18
|
||||
T_COMMA=19
|
||||
T_OPEN=20
|
||||
T_CLOSE=21
|
||||
T_OBJECT_OPEN=22
|
||||
T_OBJECT_CLOSE=23
|
||||
T_ARRAY_OPEN=24
|
||||
T_ARRAY_CLOSE=25
|
||||
T_AGGREGATE=26
|
||||
T_ALL=27
|
||||
T_AND=28
|
||||
T_ANY=29
|
||||
T_ASC=30
|
||||
T_COLLECT=31
|
||||
T_DESC=32
|
||||
T_DISTINCT=33
|
||||
T_FALSE=34
|
||||
T_FILTER=35
|
||||
T_FOR=36
|
||||
T_GRAPH=37
|
||||
T_IN=38
|
||||
T_INBOUND=39
|
||||
T_INSERT=40
|
||||
T_INTO=41
|
||||
T_K_SHORTEST_PATHS=42
|
||||
T_LET=43
|
||||
T_LIKE=44
|
||||
T_LIMIT=45
|
||||
T_NONE=46
|
||||
T_NOT=47
|
||||
T_NULL=48
|
||||
T_OR=49
|
||||
T_OUTBOUND=50
|
||||
T_REMOVE=51
|
||||
T_REPLACE=52
|
||||
T_RETURN=53
|
||||
T_SHORTEST_PATH=54
|
||||
T_SORT=55
|
||||
T_TRUE=56
|
||||
T_UPDATE=57
|
||||
T_UPSERT=58
|
||||
T_WITH=59
|
||||
T_KEEP=60
|
||||
T_COUNT=61
|
||||
T_OPTIONS=62
|
||||
T_PRUNE=63
|
||||
T_SEARCH=64
|
||||
T_TO=65
|
||||
T_CURRENT=66
|
||||
T_NEW=67
|
||||
T_OLD=68
|
||||
T_STRING=69
|
||||
T_INT=70
|
||||
T_FLOAT=71
|
||||
T_PARAMETER=72
|
||||
T_QUOTED_STRING=73
|
||||
SINGLE_LINE_COMMENT=74
|
||||
MULTILINE_COMMENT=75
|
||||
SPACES=76
|
||||
UNEXPECTED_CHAR=77
|
||||
ERROR_RECONGNIGION=78
|
||||
'.'=1
|
||||
'=~'=2
|
||||
'!~'=3
|
||||
'=='=4
|
||||
'!='=5
|
||||
'<'=6
|
||||
'>'=7
|
||||
'<='=8
|
||||
'>='=9
|
||||
'+'=10
|
||||
'-'=11
|
||||
'*'=12
|
||||
'/'=13
|
||||
'%'=14
|
||||
'?'=15
|
||||
':'=16
|
||||
'::'=17
|
||||
'..'=18
|
||||
','=19
|
||||
'('=20
|
||||
')'=21
|
||||
'{'=22
|
||||
'}'=23
|
||||
'['=24
|
||||
']'=25
|
||||
108
ui/src/suggestions/grammar/CAQLParserListener.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// Generated from CAQLParser.g4 by ANTLR 4.9.2
|
||||
// jshint ignore: start
|
||||
import antlr4 from 'antlr4';
|
||||
|
||||
// This class defines a complete listener for a parse tree produced by CAQLParser.
|
||||
export default class CAQLParserListener extends antlr4.tree.ParseTreeListener {
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#parse.
|
||||
enterParse(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#parse.
|
||||
exitParse(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#expression.
|
||||
enterExpression(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#expression.
|
||||
exitExpression(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#operator_unary.
|
||||
enterOperator_unary(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#operator_unary.
|
||||
exitOperator_unary(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#reference.
|
||||
enterReference(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#reference.
|
||||
exitReference(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#compound_value.
|
||||
enterCompound_value(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#compound_value.
|
||||
exitCompound_value(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#function_call.
|
||||
enterFunction_call(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#function_call.
|
||||
exitFunction_call(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#value_literal.
|
||||
enterValue_literal(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#value_literal.
|
||||
exitValue_literal(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#array.
|
||||
enterArray(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#array.
|
||||
exitArray(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#object.
|
||||
enterObject(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#object.
|
||||
exitObject(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#object_element.
|
||||
enterObject_element(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#object_element.
|
||||
exitObject_element(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#object_element_name.
|
||||
enterObject_element_name(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#object_element_name.
|
||||
exitObject_element_name(ctx) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
282
ui/src/suggestions/grammar/RQLLexer.interp
Normal file
607
ui/src/suggestions/grammar/RQLLexer.js
Normal file
@@ -0,0 +1,607 @@
|
||||
// Generated from CAQLLexer.g4 by ANTLR 4.9.2
|
||||
// jshint ignore: start
|
||||
import antlr4 from 'antlr4';
|
||||
|
||||
|
||||
|
||||
const serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786",
|
||||
"\u5964\u0002P\u02e3\b\u0001\u0004\u0002\t\u0002\u0004\u0003\t\u0003",
|
||||
"\u0004\u0004\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007",
|
||||
"\t\u0007\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004",
|
||||
"\f\t\f\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010",
|
||||
"\t\u0010\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013",
|
||||
"\u0004\u0014\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017",
|
||||
"\t\u0017\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a",
|
||||
"\u0004\u001b\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e",
|
||||
"\t\u001e\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#",
|
||||
"\t#\u0004$\t$\u0004%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004",
|
||||
"*\t*\u0004+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u0004",
|
||||
"1\t1\u00042\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u0004",
|
||||
"8\t8\u00049\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004",
|
||||
"?\t?\u0004@\t@\u0004A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004",
|
||||
"F\tF\u0004G\tG\u0004H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004",
|
||||
"M\tM\u0004N\tN\u0004O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004",
|
||||
"T\tT\u0004U\tU\u0004V\tV\u0004W\tW\u0004X\tX\u0004Y\tY\u0004Z\tZ\u0004",
|
||||
"[\t[\u0004\\\t\\\u0004]\t]\u0004^\t^\u0004_\t_\u0004`\t`\u0004a\ta\u0004",
|
||||
"b\tb\u0004c\tc\u0004d\td\u0004e\te\u0004f\tf\u0004g\tg\u0004h\th\u0004",
|
||||
"i\ti\u0004j\tj\u0004k\tk\u0003\u0002\u0003\u0002\u0003\u0003\u0003\u0003",
|
||||
"\u0003\u0003\u0003\u0004\u0003\u0004\u0003\u0004\u0003\u0005\u0003\u0005",
|
||||
"\u0003\u0005\u0003\u0006\u0003\u0006\u0003\u0006\u0003\u0007\u0003\u0007",
|
||||
"\u0003\b\u0003\b\u0003\t\u0003\t\u0003\t\u0003\n\u0003\n\u0003\n\u0003",
|
||||
"\u000b\u0003\u000b\u0003\f\u0003\f\u0003\r\u0003\r\u0003\u000e\u0003",
|
||||
"\u000e\u0003\u000f\u0003\u000f\u0003\u0010\u0003\u0010\u0003\u0011\u0003",
|
||||
"\u0011\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0013\u0003\u0013\u0003",
|
||||
"\u0013\u0003\u0014\u0003\u0014\u0003\u0015\u0003\u0015\u0003\u0016\u0003",
|
||||
"\u0016\u0003\u0017\u0003\u0017\u0003\u0018\u0003\u0018\u0003\u0019\u0003",
|
||||
"\u0019\u0003\u001a\u0003\u001a\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
|
||||
"\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003",
|
||||
"\u001b\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001d\u0003",
|
||||
"\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0005\u001d\u0126",
|
||||
"\n\u001d\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001f",
|
||||
"\u0003\u001f\u0003\u001f\u0003\u001f\u0003 \u0003 \u0003 \u0003 \u0003",
|
||||
" \u0003 \u0003 \u0003 \u0003!\u0003!\u0003!\u0003!\u0003!\u0003\"\u0003",
|
||||
"\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003#\u0003",
|
||||
"#\u0003#\u0003#\u0003#\u0003#\u0003$\u0003$\u0003$\u0003$\u0003$\u0003",
|
||||
"$\u0003$\u0003%\u0003%\u0003%\u0003%\u0003&\u0003&\u0003&\u0003&\u0003",
|
||||
"&\u0003&\u0003\'\u0003\'\u0003\'\u0003(\u0003(\u0003(\u0003(\u0003(",
|
||||
"\u0003(\u0003(\u0003(\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0003",
|
||||
")\u0003*\u0003*\u0003*\u0003*\u0003*\u0003+\u0003+\u0003+\u0003+\u0003",
|
||||
"+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003",
|
||||
"+\u0003+\u0003+\u0003,\u0003,\u0003,\u0003,\u0003-\u0003-\u0003-\u0003",
|
||||
"-\u0003-\u0003.\u0003.\u0003.\u0003.\u0003.\u0003.\u0003/\u0003/\u0003",
|
||||
"/\u0003/\u0003/\u00030\u00030\u00030\u00030\u00030\u00050\u019e\n0\u0003",
|
||||
"1\u00031\u00031\u00031\u00031\u00032\u00032\u00032\u00032\u00032\u0005",
|
||||
"2\u01aa\n2\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u0003",
|
||||
"3\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u00035\u00035\u0003",
|
||||
"5\u00035\u00035\u00035\u00035\u00035\u00036\u00036\u00036\u00036\u0003",
|
||||
"6\u00036\u00036\u00037\u00037\u00037\u00037\u00037\u00037\u00037\u0003",
|
||||
"7\u00037\u00037\u00037\u00037\u00037\u00037\u00038\u00038\u00038\u0003",
|
||||
"8\u00038\u00039\u00039\u00039\u00039\u00039\u0003:\u0003:\u0003:\u0003",
|
||||
":\u0003:\u0003:\u0003:\u0003;\u0003;\u0003;\u0003;\u0003;\u0003;\u0003",
|
||||
";\u0003<\u0003<\u0003<\u0003<\u0003<\u0003=\u0003=\u0003=\u0003=\u0003",
|
||||
"=\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003?\u0003?\u0003?\u0003",
|
||||
"?\u0003?\u0003?\u0003?\u0003?\u0003@\u0003@\u0003@\u0003@\u0003@\u0003",
|
||||
"@\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003B\u0003B\u0003",
|
||||
"B\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003D\u0003",
|
||||
"D\u0003D\u0003D\u0003E\u0003E\u0003E\u0003E\u0003F\u0003F\u0007F\u022b",
|
||||
"\nF\fF\u000eF\u022e\u000bF\u0003G\u0003G\u0007G\u0232\nG\fG\u000eG\u0235",
|
||||
"\u000bG\u0003G\u0003G\u0003G\u0003G\u0003G\u0006G\u023c\nG\rG\u000e",
|
||||
"G\u023d\u0003G\u0003G\u0003G\u0003G\u0006G\u0244\nG\rG\u000eG\u0245",
|
||||
"\u0005G\u0248\nG\u0003H\u0003H\u0007H\u024c\nH\fH\u000eH\u024f\u000b",
|
||||
"H\u0003H\u0005H\u0252\nH\u0003H\u0003H\u0006H\u0256\nH\rH\u000eH\u0257",
|
||||
"\u0003H\u0003H\u0005H\u025c\nH\u0003H\u0006H\u025f\nH\rH\u000eH\u0260",
|
||||
"\u0005H\u0263\nH\u0003I\u0003I\u0003I\u0003J\u0003J\u0003J\u0003J\u0003",
|
||||
"J\u0003J\u0007J\u026e\nJ\fJ\u000eJ\u0271\u000bJ\u0003J\u0003J\u0003",
|
||||
"J\u0003J\u0003J\u0003J\u0003J\u0007J\u027a\nJ\fJ\u000eJ\u027d\u000b",
|
||||
"J\u0003J\u0005J\u0280\nJ\u0003K\u0003K\u0003K\u0003K\u0007K\u0286\n",
|
||||
"K\fK\u000eK\u0289\u000bK\u0003K\u0005K\u028c\nK\u0003K\u0003K\u0005",
|
||||
"K\u0290\nK\u0003K\u0003K\u0003L\u0003L\u0003L\u0003L\u0007L\u0298\n",
|
||||
"L\fL\u000eL\u029b\u000bL\u0003L\u0003L\u0003L\u0003L\u0003L\u0003M\u0003",
|
||||
"M\u0003M\u0003M\u0003N\u0003N\u0003O\u0003O\u0003P\u0003P\u0003Q\u0003",
|
||||
"Q\u0003R\u0003R\u0003S\u0003S\u0003T\u0003T\u0003U\u0003U\u0003V\u0003",
|
||||
"V\u0003W\u0003W\u0003X\u0003X\u0003Y\u0003Y\u0003Z\u0003Z\u0003[\u0003",
|
||||
"[\u0003\\\u0003\\\u0003]\u0003]\u0003^\u0003^\u0003_\u0003_\u0003`\u0003",
|
||||
"`\u0003a\u0003a\u0003b\u0003b\u0003c\u0003c\u0003d\u0003d\u0003e\u0003",
|
||||
"e\u0003f\u0003f\u0003g\u0003g\u0003h\u0003h\u0003i\u0003i\u0003j\u0003",
|
||||
"j\u0003k\u0003k\u0003k\u0003k\u0003\u0299\u0002l\u0003\u0003\u0005\u0004",
|
||||
"\u0007\u0005\t\u0006\u000b\u0007\r\b\u000f\t\u0011\n\u0013\u000b\u0015",
|
||||
"\f\u0017\r\u0019\u000e\u001b\u000f\u001d\u0010\u001f\u0011!\u0012#\u0013",
|
||||
"%\u0014\'\u0015)\u0016+\u0017-\u0018/\u00191\u001a3\u001b5\u001c7\u001d",
|
||||
"9\u001e;\u001f= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o",
|
||||
"9q:s;u<w=y>{?}@\u007fA\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008d",
|
||||
"H\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d\u0002\u009f",
|
||||
"\u0002\u00a1\u0002\u00a3\u0002\u00a5\u0002\u00a7\u0002\u00a9\u0002\u00ab",
|
||||
"\u0002\u00ad\u0002\u00af\u0002\u00b1\u0002\u00b3\u0002\u00b5\u0002\u00b7",
|
||||
"\u0002\u00b9\u0002\u00bb\u0002\u00bd\u0002\u00bf\u0002\u00c1\u0002\u00c3",
|
||||
"\u0002\u00c5\u0002\u00c7\u0002\u00c9\u0002\u00cb\u0002\u00cd\u0002\u00cf",
|
||||
"\u0002\u00d1\u0002\u00d3\u0002\u00d5P\u0003\u0002\'\u0005\u0002C\\a",
|
||||
"ac|\u0006\u00022;C\\aac|\u0003\u00023;\u0003\u000223\u0004\u0002--/",
|
||||
"/\u0004\u0002))^^\u0004\u0002$$^^\u0004\u0002\f\f\u000f\u000f\u0005",
|
||||
"\u0002\u000b\r\u000f\u000f\"\"\u0005\u00022;CHch\u0003\u00022;\u0004",
|
||||
"\u0002CCcc\u0004\u0002DDdd\u0004\u0002EEee\u0004\u0002FFff\u0004\u0002",
|
||||
"GGgg\u0004\u0002HHhh\u0004\u0002IIii\u0004\u0002JJjj\u0004\u0002KKk",
|
||||
"k\u0004\u0002LLll\u0004\u0002MMmm\u0004\u0002NNnn\u0004\u0002OOoo\u0004",
|
||||
"\u0002PPpp\u0004\u0002QQqq\u0004\u0002RRrr\u0004\u0002SSss\u0004\u0002",
|
||||
"TTtt\u0004\u0002UUuu\u0004\u0002VVvv\u0004\u0002WWww\u0004\u0002XXx",
|
||||
"x\u0004\u0002YYyy\u0004\u0002ZZzz\u0004\u0002[[{{\u0004\u0002\\\\||",
|
||||
"\u0002\u02e2\u0002\u0003\u0003\u0002\u0002\u0002\u0002\u0005\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u0007\u0003\u0002\u0002\u0002\u0002\t\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u000b\u0003\u0002\u0002\u0002\u0002\r\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u000f\u0003\u0002\u0002\u0002\u0002\u0011\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u0013\u0003\u0002\u0002\u0002\u0002\u0015\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u0017\u0003\u0002\u0002\u0002\u0002\u0019\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u001b\u0003\u0002\u0002\u0002\u0002\u001d\u0003\u0002",
|
||||
"\u0002\u0002\u0002\u001f\u0003\u0002\u0002\u0002\u0002!\u0003\u0002",
|
||||
"\u0002\u0002\u0002#\u0003\u0002\u0002\u0002\u0002%\u0003\u0002\u0002",
|
||||
"\u0002\u0002\'\u0003\u0002\u0002\u0002\u0002)\u0003\u0002\u0002\u0002",
|
||||
"\u0002+\u0003\u0002\u0002\u0002\u0002-\u0003\u0002\u0002\u0002\u0002",
|
||||
"/\u0003\u0002\u0002\u0002\u00021\u0003\u0002\u0002\u0002\u00023\u0003",
|
||||
"\u0002\u0002\u0002\u00025\u0003\u0002\u0002\u0002\u00027\u0003\u0002",
|
||||
"\u0002\u0002\u00029\u0003\u0002\u0002\u0002\u0002;\u0003\u0002\u0002",
|
||||
"\u0002\u0002=\u0003\u0002\u0002\u0002\u0002?\u0003\u0002\u0002\u0002",
|
||||
"\u0002A\u0003\u0002\u0002\u0002\u0002C\u0003\u0002\u0002\u0002\u0002",
|
||||
"E\u0003\u0002\u0002\u0002\u0002G\u0003\u0002\u0002\u0002\u0002I\u0003",
|
||||
"\u0002\u0002\u0002\u0002K\u0003\u0002\u0002\u0002\u0002M\u0003\u0002",
|
||||
"\u0002\u0002\u0002O\u0003\u0002\u0002\u0002\u0002Q\u0003\u0002\u0002",
|
||||
"\u0002\u0002S\u0003\u0002\u0002\u0002\u0002U\u0003\u0002\u0002\u0002",
|
||||
"\u0002W\u0003\u0002\u0002\u0002\u0002Y\u0003\u0002\u0002\u0002\u0002",
|
||||
"[\u0003\u0002\u0002\u0002\u0002]\u0003\u0002\u0002\u0002\u0002_\u0003",
|
||||
"\u0002\u0002\u0002\u0002a\u0003\u0002\u0002\u0002\u0002c\u0003\u0002",
|
||||
"\u0002\u0002\u0002e\u0003\u0002\u0002\u0002\u0002g\u0003\u0002\u0002",
|
||||
"\u0002\u0002i\u0003\u0002\u0002\u0002\u0002k\u0003\u0002\u0002\u0002",
|
||||
"\u0002m\u0003\u0002\u0002\u0002\u0002o\u0003\u0002\u0002\u0002\u0002",
|
||||
"q\u0003\u0002\u0002\u0002\u0002s\u0003\u0002\u0002\u0002\u0002u\u0003",
|
||||
"\u0002\u0002\u0002\u0002w\u0003\u0002\u0002\u0002\u0002y\u0003\u0002",
|
||||
"\u0002\u0002\u0002{\u0003\u0002\u0002\u0002\u0002}\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u007f\u0003\u0002\u0002\u0002\u0002\u0081\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0083\u0003\u0002\u0002\u0002\u0002\u0085\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0087\u0003\u0002\u0002\u0002\u0002\u0089\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u008b\u0003\u0002\u0002\u0002\u0002\u008d\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u008f\u0003\u0002\u0002\u0002\u0002\u0091\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0093\u0003\u0002\u0002\u0002\u0002\u0095\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u0097\u0003\u0002\u0002\u0002\u0002\u0099\u0003\u0002\u0002",
|
||||
"\u0002\u0002\u009b\u0003\u0002\u0002\u0002\u0002\u00d5\u0003\u0002\u0002",
|
||||
"\u0002\u0003\u00d7\u0003\u0002\u0002\u0002\u0005\u00d9\u0003\u0002\u0002",
|
||||
"\u0002\u0007\u00dc\u0003\u0002\u0002\u0002\t\u00df\u0003\u0002\u0002",
|
||||
"\u0002\u000b\u00e2\u0003\u0002\u0002\u0002\r\u00e5\u0003\u0002\u0002",
|
||||
"\u0002\u000f\u00e7\u0003\u0002\u0002\u0002\u0011\u00e9\u0003\u0002\u0002",
|
||||
"\u0002\u0013\u00ec\u0003\u0002\u0002\u0002\u0015\u00ef\u0003\u0002\u0002",
|
||||
"\u0002\u0017\u00f1\u0003\u0002\u0002\u0002\u0019\u00f3\u0003\u0002\u0002",
|
||||
"\u0002\u001b\u00f5\u0003\u0002\u0002\u0002\u001d\u00f7\u0003\u0002\u0002",
|
||||
"\u0002\u001f\u00f9\u0003\u0002\u0002\u0002!\u00fb\u0003\u0002\u0002",
|
||||
"\u0002#\u00fd\u0003\u0002\u0002\u0002%\u0100\u0003\u0002\u0002\u0002",
|
||||
"\'\u0103\u0003\u0002\u0002\u0002)\u0105\u0003\u0002\u0002\u0002+\u0107",
|
||||
"\u0003\u0002\u0002\u0002-\u0109\u0003\u0002\u0002\u0002/\u010b\u0003",
|
||||
"\u0002\u0002\u00021\u010d\u0003\u0002\u0002\u00023\u010f\u0003\u0002",
|
||||
"\u0002\u00025\u0111\u0003\u0002\u0002\u00027\u011b\u0003\u0002\u0002",
|
||||
"\u00029\u0125\u0003\u0002\u0002\u0002;\u0127\u0003\u0002\u0002\u0002",
|
||||
"=\u012b\u0003\u0002\u0002\u0002?\u012f\u0003\u0002\u0002\u0002A\u0137",
|
||||
"\u0003\u0002\u0002\u0002C\u013c\u0003\u0002\u0002\u0002E\u0145\u0003",
|
||||
"\u0002\u0002\u0002G\u014b\u0003\u0002\u0002\u0002I\u0152\u0003\u0002",
|
||||
"\u0002\u0002K\u0156\u0003\u0002\u0002\u0002M\u015c\u0003\u0002\u0002",
|
||||
"\u0002O\u015f\u0003\u0002\u0002\u0002Q\u0167\u0003\u0002\u0002\u0002",
|
||||
"S\u016e\u0003\u0002\u0002\u0002U\u0173\u0003\u0002\u0002\u0002W\u0184",
|
||||
"\u0003\u0002\u0002\u0002Y\u0188\u0003\u0002\u0002\u0002[\u018d\u0003",
|
||||
"\u0002\u0002\u0002]\u0193\u0003\u0002\u0002\u0002_\u019d\u0003\u0002",
|
||||
"\u0002\u0002a\u019f\u0003\u0002\u0002\u0002c\u01a9\u0003\u0002\u0002",
|
||||
"\u0002e\u01ab\u0003\u0002\u0002\u0002g\u01b4\u0003\u0002\u0002\u0002",
|
||||
"i\u01bb\u0003\u0002\u0002\u0002k\u01c3\u0003\u0002\u0002\u0002m\u01ca",
|
||||
"\u0003\u0002\u0002\u0002o\u01d8\u0003\u0002\u0002\u0002q\u01dd\u0003",
|
||||
"\u0002\u0002\u0002s\u01e2\u0003\u0002\u0002\u0002u\u01e9\u0003\u0002",
|
||||
"\u0002\u0002w\u01f0\u0003\u0002\u0002\u0002y\u01f5\u0003\u0002\u0002",
|
||||
"\u0002{\u01fa\u0003\u0002\u0002\u0002}\u0200\u0003\u0002\u0002\u0002",
|
||||
"\u007f\u0208\u0003\u0002\u0002\u0002\u0081\u020e\u0003\u0002\u0002\u0002",
|
||||
"\u0083\u0215\u0003\u0002\u0002\u0002\u0085\u0218\u0003\u0002\u0002\u0002",
|
||||
"\u0087\u0220\u0003\u0002\u0002\u0002\u0089\u0224\u0003\u0002\u0002\u0002",
|
||||
"\u008b\u0228\u0003\u0002\u0002\u0002\u008d\u0247\u0003\u0002\u0002\u0002",
|
||||
"\u008f\u0251\u0003\u0002\u0002\u0002\u0091\u0264\u0003\u0002\u0002\u0002",
|
||||
"\u0093\u027f\u0003\u0002\u0002\u0002\u0095\u0281\u0003\u0002\u0002\u0002",
|
||||
"\u0097\u0293\u0003\u0002\u0002\u0002\u0099\u02a1\u0003\u0002\u0002\u0002",
|
||||
"\u009b\u02a5\u0003\u0002\u0002\u0002\u009d\u02a7\u0003\u0002\u0002\u0002",
|
||||
"\u009f\u02a9\u0003\u0002\u0002\u0002\u00a1\u02ab\u0003\u0002\u0002\u0002",
|
||||
"\u00a3\u02ad\u0003\u0002\u0002\u0002\u00a5\u02af\u0003\u0002\u0002\u0002",
|
||||
"\u00a7\u02b1\u0003\u0002\u0002\u0002\u00a9\u02b3\u0003\u0002\u0002\u0002",
|
||||
"\u00ab\u02b5\u0003\u0002\u0002\u0002\u00ad\u02b7\u0003\u0002\u0002\u0002",
|
||||
"\u00af\u02b9\u0003\u0002\u0002\u0002\u00b1\u02bb\u0003\u0002\u0002\u0002",
|
||||
"\u00b3\u02bd\u0003\u0002\u0002\u0002\u00b5\u02bf\u0003\u0002\u0002\u0002",
|
||||
"\u00b7\u02c1\u0003\u0002\u0002\u0002\u00b9\u02c3\u0003\u0002\u0002\u0002",
|
||||
"\u00bb\u02c5\u0003\u0002\u0002\u0002\u00bd\u02c7\u0003\u0002\u0002\u0002",
|
||||
"\u00bf\u02c9\u0003\u0002\u0002\u0002\u00c1\u02cb\u0003\u0002\u0002\u0002",
|
||||
"\u00c3\u02cd\u0003\u0002\u0002\u0002\u00c5\u02cf\u0003\u0002\u0002\u0002",
|
||||
"\u00c7\u02d1\u0003\u0002\u0002\u0002\u00c9\u02d3\u0003\u0002\u0002\u0002",
|
||||
"\u00cb\u02d5\u0003\u0002\u0002\u0002\u00cd\u02d7\u0003\u0002\u0002\u0002",
|
||||
"\u00cf\u02d9\u0003\u0002\u0002\u0002\u00d1\u02db\u0003\u0002\u0002\u0002",
|
||||
"\u00d3\u02dd\u0003\u0002\u0002\u0002\u00d5\u02df\u0003\u0002\u0002\u0002",
|
||||
"\u00d7\u00d8\u00070\u0002\u0002\u00d8\u0004\u0003\u0002\u0002\u0002",
|
||||
"\u00d9\u00da\u0007?\u0002\u0002\u00da\u00db\u0007\u0080\u0002\u0002",
|
||||
"\u00db\u0006\u0003\u0002\u0002\u0002\u00dc\u00dd\u0007#\u0002\u0002",
|
||||
"\u00dd\u00de\u0007\u0080\u0002\u0002\u00de\b\u0003\u0002\u0002\u0002",
|
||||
"\u00df\u00e0\u0007?\u0002\u0002\u00e0\u00e1\u0007?\u0002\u0002\u00e1",
|
||||
"\n\u0003\u0002\u0002\u0002\u00e2\u00e3\u0007#\u0002\u0002\u00e3\u00e4",
|
||||
"\u0007?\u0002\u0002\u00e4\f\u0003\u0002\u0002\u0002\u00e5\u00e6\u0007",
|
||||
">\u0002\u0002\u00e6\u000e\u0003\u0002\u0002\u0002\u00e7\u00e8\u0007",
|
||||
"@\u0002\u0002\u00e8\u0010\u0003\u0002\u0002\u0002\u00e9\u00ea\u0007",
|
||||
">\u0002\u0002\u00ea\u00eb\u0007?\u0002\u0002\u00eb\u0012\u0003\u0002",
|
||||
"\u0002\u0002\u00ec\u00ed\u0007@\u0002\u0002\u00ed\u00ee\u0007?\u0002",
|
||||
"\u0002\u00ee\u0014\u0003\u0002\u0002\u0002\u00ef\u00f0\u0007-\u0002",
|
||||
"\u0002\u00f0\u0016\u0003\u0002\u0002\u0002\u00f1\u00f2\u0007/\u0002",
|
||||
"\u0002\u00f2\u0018\u0003\u0002\u0002\u0002\u00f3\u00f4\u0007,\u0002",
|
||||
"\u0002\u00f4\u001a\u0003\u0002\u0002\u0002\u00f5\u00f6\u00071\u0002",
|
||||
"\u0002\u00f6\u001c\u0003\u0002\u0002\u0002\u00f7\u00f8\u0007\'\u0002",
|
||||
"\u0002\u00f8\u001e\u0003\u0002\u0002\u0002\u00f9\u00fa\u0007A\u0002",
|
||||
"\u0002\u00fa \u0003\u0002\u0002\u0002\u00fb\u00fc\u0007<\u0002\u0002",
|
||||
"\u00fc\"\u0003\u0002\u0002\u0002\u00fd\u00fe\u0007<\u0002\u0002\u00fe",
|
||||
"\u00ff\u0007<\u0002\u0002\u00ff$\u0003\u0002\u0002\u0002\u0100\u0101",
|
||||
"\u00070\u0002\u0002\u0101\u0102\u00070\u0002\u0002\u0102&\u0003\u0002",
|
||||
"\u0002\u0002\u0103\u0104\u0007.\u0002\u0002\u0104(\u0003\u0002\u0002",
|
||||
"\u0002\u0105\u0106\u0007*\u0002\u0002\u0106*\u0003\u0002\u0002\u0002",
|
||||
"\u0107\u0108\u0007+\u0002\u0002\u0108,\u0003\u0002\u0002\u0002\u0109",
|
||||
"\u010a\u0007}\u0002\u0002\u010a.\u0003\u0002\u0002\u0002\u010b\u010c",
|
||||
"\u0007\u007f\u0002\u0002\u010c0\u0003\u0002\u0002\u0002\u010d\u010e",
|
||||
"\u0007]\u0002\u0002\u010e2\u0003\u0002\u0002\u0002\u010f\u0110\u0007",
|
||||
"_\u0002\u0002\u01104\u0003\u0002\u0002\u0002\u0111\u0112\u0005\u00a1",
|
||||
"Q\u0002\u0112\u0113\u0005\u00adW\u0002\u0113\u0114\u0005\u00adW\u0002",
|
||||
"\u0114\u0115\u0005\u00c3b\u0002\u0115\u0116\u0005\u00a9U\u0002\u0116",
|
||||
"\u0117\u0005\u00adW\u0002\u0117\u0118\u0005\u00a1Q\u0002\u0118\u0119",
|
||||
"\u0005\u00c7d\u0002\u0119\u011a\u0005\u00a9U\u0002\u011a6\u0003\u0002",
|
||||
"\u0002\u0002\u011b\u011c\u0005\u00a1Q\u0002\u011c\u011d\u0005\u00b7",
|
||||
"\\\u0002\u011d\u011e\u0005\u00b7\\\u0002\u011e8\u0003\u0002\u0002\u0002",
|
||||
"\u011f\u0120\u0005\u00a1Q\u0002\u0120\u0121\u0005\u00bb^\u0002\u0121",
|
||||
"\u0122\u0005\u00a7T\u0002\u0122\u0126\u0003\u0002\u0002\u0002\u0123",
|
||||
"\u0124\u0007(\u0002\u0002\u0124\u0126\u0007(\u0002\u0002\u0125\u011f",
|
||||
"\u0003\u0002\u0002\u0002\u0125\u0123\u0003\u0002\u0002\u0002\u0126:",
|
||||
"\u0003\u0002\u0002\u0002\u0127\u0128\u0005\u00a1Q\u0002\u0128\u0129",
|
||||
"\u0005\u00bb^\u0002\u0129\u012a\u0005\u00d1i\u0002\u012a<\u0003\u0002",
|
||||
"\u0002\u0002\u012b\u012c\u0005\u00a1Q\u0002\u012c\u012d\u0005\u00c5",
|
||||
"c\u0002\u012d\u012e\u0005\u00a5S\u0002\u012e>\u0003\u0002\u0002\u0002",
|
||||
"\u012f\u0130\u0005\u00a5S\u0002\u0130\u0131\u0005\u00bd_\u0002\u0131",
|
||||
"\u0132\u0005\u00b7\\\u0002\u0132\u0133\u0005\u00b7\\\u0002\u0133\u0134",
|
||||
"\u0005\u00a9U\u0002\u0134\u0135\u0005\u00a5S\u0002\u0135\u0136\u0005",
|
||||
"\u00c7d\u0002\u0136@\u0003\u0002\u0002\u0002\u0137\u0138\u0005\u00a7",
|
||||
"T\u0002\u0138\u0139\u0005\u00a9U\u0002\u0139\u013a\u0005\u00c5c\u0002",
|
||||
"\u013a\u013b\u0005\u00a5S\u0002\u013bB\u0003\u0002\u0002\u0002\u013c",
|
||||
"\u013d\u0005\u00a7T\u0002\u013d\u013e\u0005\u00b1Y\u0002\u013e\u013f",
|
||||
"\u0005\u00c5c\u0002\u013f\u0140\u0005\u00c7d\u0002\u0140\u0141\u0005",
|
||||
"\u00b1Y\u0002\u0141\u0142\u0005\u00bb^\u0002\u0142\u0143\u0005\u00a5",
|
||||
"S\u0002\u0143\u0144\u0005\u00c7d\u0002\u0144D\u0003\u0002\u0002\u0002",
|
||||
"\u0145\u0146\u0005\u00abV\u0002\u0146\u0147\u0005\u00a1Q\u0002\u0147",
|
||||
"\u0148\u0005\u00b7\\\u0002\u0148\u0149\u0005\u00c5c\u0002\u0149\u014a",
|
||||
"\u0005\u00a9U\u0002\u014aF\u0003\u0002\u0002\u0002\u014b\u014c\u0005",
|
||||
"\u00abV\u0002\u014c\u014d\u0005\u00b1Y\u0002\u014d\u014e\u0005\u00b7",
|
||||
"\\\u0002\u014e\u014f\u0005\u00c7d\u0002\u014f\u0150\u0005\u00a9U\u0002",
|
||||
"\u0150\u0151\u0005\u00c3b\u0002\u0151H\u0003\u0002\u0002\u0002\u0152",
|
||||
"\u0153\u0005\u00abV\u0002\u0153\u0154\u0005\u00bd_\u0002\u0154\u0155",
|
||||
"\u0005\u00c3b\u0002\u0155J\u0003\u0002\u0002\u0002\u0156\u0157\u0005",
|
||||
"\u00adW\u0002\u0157\u0158\u0005\u00c3b\u0002\u0158\u0159\u0005\u00a1",
|
||||
"Q\u0002\u0159\u015a\u0005\u00bf`\u0002\u015a\u015b\u0005\u00afX\u0002",
|
||||
"\u015bL\u0003\u0002\u0002\u0002\u015c\u015d\u0005\u00b1Y\u0002\u015d",
|
||||
"\u015e\u0005\u00bb^\u0002\u015eN\u0003\u0002\u0002\u0002\u015f\u0160",
|
||||
"\u0005\u00b1Y\u0002\u0160\u0161\u0005\u00bb^\u0002\u0161\u0162\u0005",
|
||||
"\u00a3R\u0002\u0162\u0163\u0005\u00bd_\u0002\u0163\u0164\u0005\u00c9",
|
||||
"e\u0002\u0164\u0165\u0005\u00bb^\u0002\u0165\u0166\u0005\u00a7T\u0002",
|
||||
"\u0166P\u0003\u0002\u0002\u0002\u0167\u0168\u0005\u00b1Y\u0002\u0168",
|
||||
"\u0169\u0005\u00bb^\u0002\u0169\u016a\u0005\u00c5c\u0002\u016a\u016b",
|
||||
"\u0005\u00a9U\u0002\u016b\u016c\u0005\u00c3b\u0002\u016c\u016d\u0005",
|
||||
"\u00c7d\u0002\u016dR\u0003\u0002\u0002\u0002\u016e\u016f\u0005\u00b1",
|
||||
"Y\u0002\u016f\u0170\u0005\u00bb^\u0002\u0170\u0171\u0005\u00c7d\u0002",
|
||||
"\u0171\u0172\u0005\u00bd_\u0002\u0172T\u0003\u0002\u0002\u0002\u0173",
|
||||
"\u0174\u0005\u00b5[\u0002\u0174\u0175\u0007a\u0002\u0002\u0175\u0176",
|
||||
"\u0005\u00c5c\u0002\u0176\u0177\u0005\u00afX\u0002\u0177\u0178\u0005",
|
||||
"\u00bd_\u0002\u0178\u0179\u0005\u00c3b\u0002\u0179\u017a\u0005\u00c7",
|
||||
"d\u0002\u017a\u017b\u0005\u00a9U\u0002\u017b\u017c\u0005\u00c5c\u0002",
|
||||
"\u017c\u017d\u0005\u00c7d\u0002\u017d\u017e\u0007a\u0002\u0002\u017e",
|
||||
"\u017f\u0005\u00bf`\u0002\u017f\u0180\u0005\u00a1Q\u0002\u0180\u0181",
|
||||
"\u0005\u00c7d\u0002\u0181\u0182\u0005\u00afX\u0002\u0182\u0183\u0005",
|
||||
"\u00c5c\u0002\u0183V\u0003\u0002\u0002\u0002\u0184\u0185\u0005\u00b7",
|
||||
"\\\u0002\u0185\u0186\u0005\u00a9U\u0002\u0186\u0187\u0005\u00c7d\u0002",
|
||||
"\u0187X\u0003\u0002\u0002\u0002\u0188\u0189\u0005\u00b7\\\u0002\u0189",
|
||||
"\u018a\u0005\u00b1Y\u0002\u018a\u018b\u0005\u00b5[\u0002\u018b\u018c",
|
||||
"\u0005\u00a9U\u0002\u018cZ\u0003\u0002\u0002\u0002\u018d\u018e\u0005",
|
||||
"\u00b7\\\u0002\u018e\u018f\u0005\u00b1Y\u0002\u018f\u0190\u0005\u00b9",
|
||||
"]\u0002\u0190\u0191\u0005\u00b1Y\u0002\u0191\u0192\u0005\u00c7d\u0002",
|
||||
"\u0192\\\u0003\u0002\u0002\u0002\u0193\u0194\u0005\u00bb^\u0002\u0194",
|
||||
"\u0195\u0005\u00bd_\u0002\u0195\u0196\u0005\u00bb^\u0002\u0196\u0197",
|
||||
"\u0005\u00a9U\u0002\u0197^\u0003\u0002\u0002\u0002\u0198\u0199\u0005",
|
||||
"\u00bb^\u0002\u0199\u019a\u0005\u00bd_\u0002\u019a\u019b\u0005\u00c7",
|
||||
"d\u0002\u019b\u019e\u0003\u0002\u0002\u0002\u019c\u019e\u0007#\u0002",
|
||||
"\u0002\u019d\u0198\u0003\u0002\u0002\u0002\u019d\u019c\u0003\u0002\u0002",
|
||||
"\u0002\u019e`\u0003\u0002\u0002\u0002\u019f\u01a0\u0005\u00bb^\u0002",
|
||||
"\u01a0\u01a1\u0005\u00c9e\u0002\u01a1\u01a2\u0005\u00b7\\\u0002\u01a2",
|
||||
"\u01a3\u0005\u00b7\\\u0002\u01a3b\u0003\u0002\u0002\u0002\u01a4\u01a5",
|
||||
"\u0005\u00bd_\u0002\u01a5\u01a6\u0005\u00c3b\u0002\u01a6\u01aa\u0003",
|
||||
"\u0002\u0002\u0002\u01a7\u01a8\u0007~\u0002\u0002\u01a8\u01aa\u0007",
|
||||
"~\u0002\u0002\u01a9\u01a4\u0003\u0002\u0002\u0002\u01a9\u01a7\u0003",
|
||||
"\u0002\u0002\u0002\u01aad\u0003\u0002\u0002\u0002\u01ab\u01ac\u0005",
|
||||
"\u00bd_\u0002\u01ac\u01ad\u0005\u00c9e\u0002\u01ad\u01ae\u0005\u00c7",
|
||||
"d\u0002\u01ae\u01af\u0005\u00a3R\u0002\u01af\u01b0\u0005\u00bd_\u0002",
|
||||
"\u01b0\u01b1\u0005\u00c9e\u0002\u01b1\u01b2\u0005\u00bb^\u0002\u01b2",
|
||||
"\u01b3\u0005\u00a7T\u0002\u01b3f\u0003\u0002\u0002\u0002\u01b4\u01b5",
|
||||
"\u0005\u00c3b\u0002\u01b5\u01b6\u0005\u00a9U\u0002\u01b6\u01b7\u0005",
|
||||
"\u00b9]\u0002\u01b7\u01b8\u0005\u00bd_\u0002\u01b8\u01b9\u0005\u00cb",
|
||||
"f\u0002\u01b9\u01ba\u0005\u00a9U\u0002\u01bah\u0003\u0002\u0002\u0002",
|
||||
"\u01bb\u01bc\u0005\u00c3b\u0002\u01bc\u01bd\u0005\u00a9U\u0002\u01bd",
|
||||
"\u01be\u0005\u00bf`\u0002\u01be\u01bf\u0005\u00b7\\\u0002\u01bf\u01c0",
|
||||
"\u0005\u00a1Q\u0002\u01c0\u01c1\u0005\u00a5S\u0002\u01c1\u01c2\u0005",
|
||||
"\u00a9U\u0002\u01c2j\u0003\u0002\u0002\u0002\u01c3\u01c4\u0005\u00c3",
|
||||
"b\u0002\u01c4\u01c5\u0005\u00a9U\u0002\u01c5\u01c6\u0005\u00c7d\u0002",
|
||||
"\u01c6\u01c7\u0005\u00c9e\u0002\u01c7\u01c8\u0005\u00c3b\u0002\u01c8",
|
||||
"\u01c9\u0005\u00bb^\u0002\u01c9l\u0003\u0002\u0002\u0002\u01ca\u01cb",
|
||||
"\u0005\u00c5c\u0002\u01cb\u01cc\u0005\u00afX\u0002\u01cc\u01cd\u0005",
|
||||
"\u00bd_\u0002\u01cd\u01ce\u0005\u00c3b\u0002\u01ce\u01cf\u0005\u00c7",
|
||||
"d\u0002\u01cf\u01d0\u0005\u00a9U\u0002\u01d0\u01d1\u0005\u00c5c\u0002",
|
||||
"\u01d1\u01d2\u0005\u00c7d\u0002\u01d2\u01d3\u0007a\u0002\u0002\u01d3",
|
||||
"\u01d4\u0005\u00bf`\u0002\u01d4\u01d5\u0005\u00a1Q\u0002\u01d5\u01d6",
|
||||
"\u0005\u00c7d\u0002\u01d6\u01d7\u0005\u00afX\u0002\u01d7n\u0003\u0002",
|
||||
"\u0002\u0002\u01d8\u01d9\u0005\u00c5c\u0002\u01d9\u01da\u0005\u00bd",
|
||||
"_\u0002\u01da\u01db\u0005\u00c3b\u0002\u01db\u01dc\u0005\u00c7d\u0002",
|
||||
"\u01dcp\u0003\u0002\u0002\u0002\u01dd\u01de\u0005\u00c7d\u0002\u01de",
|
||||
"\u01df\u0005\u00c3b\u0002\u01df\u01e0\u0005\u00c9e\u0002\u01e0\u01e1",
|
||||
"\u0005\u00a9U\u0002\u01e1r\u0003\u0002\u0002\u0002\u01e2\u01e3\u0005",
|
||||
"\u00c9e\u0002\u01e3\u01e4\u0005\u00bf`\u0002\u01e4\u01e5\u0005\u00a7",
|
||||
"T\u0002\u01e5\u01e6\u0005\u00a1Q\u0002\u01e6\u01e7\u0005\u00c7d\u0002",
|
||||
"\u01e7\u01e8\u0005\u00a9U\u0002\u01e8t\u0003\u0002\u0002\u0002\u01e9",
|
||||
"\u01ea\u0005\u00c9e\u0002\u01ea\u01eb\u0005\u00bf`\u0002\u01eb\u01ec",
|
||||
"\u0005\u00c5c\u0002\u01ec\u01ed\u0005\u00a9U\u0002\u01ed\u01ee\u0005",
|
||||
"\u00c3b\u0002\u01ee\u01ef\u0005\u00c7d\u0002\u01efv\u0003\u0002\u0002",
|
||||
"\u0002\u01f0\u01f1\u0005\u00cdg\u0002\u01f1\u01f2\u0005\u00b1Y\u0002",
|
||||
"\u01f2\u01f3\u0005\u00c7d\u0002\u01f3\u01f4\u0005\u00afX\u0002\u01f4",
|
||||
"x\u0003\u0002\u0002\u0002\u01f5\u01f6\u0005\u00b5[\u0002\u01f6\u01f7",
|
||||
"\u0005\u00a9U\u0002\u01f7\u01f8\u0005\u00a9U\u0002\u01f8\u01f9\u0005",
|
||||
"\u00bf`\u0002\u01f9z\u0003\u0002\u0002\u0002\u01fa\u01fb\u0005\u00a5",
|
||||
"S\u0002\u01fb\u01fc\u0005\u00bd_\u0002\u01fc\u01fd\u0005\u00c9e\u0002",
|
||||
"\u01fd\u01fe\u0005\u00bb^\u0002\u01fe\u01ff\u0005\u00c7d\u0002\u01ff",
|
||||
"|\u0003\u0002\u0002\u0002\u0200\u0201\u0005\u00bd_\u0002\u0201\u0202",
|
||||
"\u0005\u00bf`\u0002\u0202\u0203\u0005\u00c7d\u0002\u0203\u0204\u0005",
|
||||
"\u00b1Y\u0002\u0204\u0205\u0005\u00bd_\u0002\u0205\u0206\u0005\u00bb",
|
||||
"^\u0002\u0206\u0207\u0005\u00c5c\u0002\u0207~\u0003\u0002\u0002\u0002",
|
||||
"\u0208\u0209\u0005\u00bf`\u0002\u0209\u020a\u0005\u00c3b\u0002\u020a",
|
||||
"\u020b\u0005\u00c9e\u0002\u020b\u020c\u0005\u00bb^\u0002\u020c\u020d",
|
||||
"\u0005\u00a9U\u0002\u020d\u0080\u0003\u0002\u0002\u0002\u020e\u020f",
|
||||
"\u0005\u00c5c\u0002\u020f\u0210\u0005\u00a9U\u0002\u0210\u0211\u0005",
|
||||
"\u00a1Q\u0002\u0211\u0212\u0005\u00c3b\u0002\u0212\u0213\u0005\u00a5",
|
||||
"S\u0002\u0213\u0214\u0005\u00afX\u0002\u0214\u0082\u0003\u0002\u0002",
|
||||
"\u0002\u0215\u0216\u0005\u00c7d\u0002\u0216\u0217\u0005\u00bd_\u0002",
|
||||
"\u0217\u0084\u0003\u0002\u0002\u0002\u0218\u0219\u0005\u00a5S\u0002",
|
||||
"\u0219\u021a\u0005\u00c9e\u0002\u021a\u021b\u0005\u00c3b\u0002\u021b",
|
||||
"\u021c\u0005\u00c3b\u0002\u021c\u021d\u0005\u00a9U\u0002\u021d\u021e",
|
||||
"\u0005\u00bb^\u0002\u021e\u021f\u0005\u00c7d\u0002\u021f\u0086\u0003",
|
||||
"\u0002\u0002\u0002\u0220\u0221\u0005\u00bb^\u0002\u0221\u0222\u0005",
|
||||
"\u00a9U\u0002\u0222\u0223\u0005\u00cdg\u0002\u0223\u0088\u0003\u0002",
|
||||
"\u0002\u0002\u0224\u0225\u0005\u00bd_\u0002\u0225\u0226\u0005\u00b7",
|
||||
"\\\u0002\u0226\u0227\u0005\u00a7T\u0002\u0227\u008a\u0003\u0002\u0002",
|
||||
"\u0002\u0228\u022c\t\u0002\u0002\u0002\u0229\u022b\t\u0003\u0002\u0002",
|
||||
"\u022a\u0229\u0003\u0002\u0002\u0002\u022b\u022e\u0003\u0002\u0002\u0002",
|
||||
"\u022c\u022a\u0003\u0002\u0002\u0002\u022c\u022d\u0003\u0002\u0002\u0002",
|
||||
"\u022d\u008c\u0003\u0002\u0002\u0002\u022e\u022c\u0003\u0002\u0002\u0002",
|
||||
"\u022f\u0233\t\u0004\u0002\u0002\u0230\u0232\u0005\u009fP\u0002\u0231",
|
||||
"\u0230\u0003\u0002\u0002\u0002\u0232\u0235\u0003\u0002\u0002\u0002\u0233",
|
||||
"\u0231\u0003\u0002\u0002\u0002\u0233\u0234\u0003\u0002\u0002\u0002\u0234",
|
||||
"\u0248\u0003\u0002\u0002\u0002\u0235\u0233\u0003\u0002\u0002\u0002\u0236",
|
||||
"\u0248\u00072\u0002\u0002\u0237\u0238\u00072\u0002\u0002\u0238\u0239",
|
||||
"\u0007z\u0002\u0002\u0239\u023b\u0003\u0002\u0002\u0002\u023a\u023c",
|
||||
"\u0005\u009dO\u0002\u023b\u023a\u0003\u0002\u0002\u0002\u023c\u023d",
|
||||
"\u0003\u0002\u0002\u0002\u023d\u023b\u0003\u0002\u0002\u0002\u023d\u023e",
|
||||
"\u0003\u0002\u0002\u0002\u023e\u0248\u0003\u0002\u0002\u0002\u023f\u0240",
|
||||
"\u00072\u0002\u0002\u0240\u0241\u0007d\u0002\u0002\u0241\u0243\u0003",
|
||||
"\u0002\u0002\u0002\u0242\u0244\t\u0005\u0002\u0002\u0243\u0242\u0003",
|
||||
"\u0002\u0002\u0002\u0244\u0245\u0003\u0002\u0002\u0002\u0245\u0243\u0003",
|
||||
"\u0002\u0002\u0002\u0245\u0246\u0003\u0002\u0002\u0002\u0246\u0248\u0003",
|
||||
"\u0002\u0002\u0002\u0247\u022f\u0003\u0002\u0002\u0002\u0247\u0236\u0003",
|
||||
"\u0002\u0002\u0002\u0247\u0237\u0003\u0002\u0002\u0002\u0247\u023f\u0003",
|
||||
"\u0002\u0002\u0002\u0248\u008e\u0003\u0002\u0002\u0002\u0249\u024d\t",
|
||||
"\u0004\u0002\u0002\u024a\u024c\u0005\u009fP\u0002\u024b\u024a\u0003",
|
||||
"\u0002\u0002\u0002\u024c\u024f\u0003\u0002\u0002\u0002\u024d\u024b\u0003",
|
||||
"\u0002\u0002\u0002\u024d\u024e\u0003\u0002\u0002\u0002\u024e\u0252\u0003",
|
||||
"\u0002\u0002\u0002\u024f\u024d\u0003\u0002\u0002\u0002\u0250\u0252\u0007",
|
||||
"2\u0002\u0002\u0251\u0249\u0003\u0002\u0002\u0002\u0251\u0250\u0003",
|
||||
"\u0002\u0002\u0002\u0251\u0252\u0003\u0002\u0002\u0002\u0252\u0253\u0003",
|
||||
"\u0002\u0002\u0002\u0253\u0255\u00070\u0002\u0002\u0254\u0256\u0005",
|
||||
"\u009fP\u0002\u0255\u0254\u0003\u0002\u0002\u0002\u0256\u0257\u0003",
|
||||
"\u0002\u0002\u0002\u0257\u0255\u0003\u0002\u0002\u0002\u0257\u0258\u0003",
|
||||
"\u0002\u0002\u0002\u0258\u0262\u0003\u0002\u0002\u0002\u0259\u025b\u0005",
|
||||
"\u00a9U\u0002\u025a\u025c\t\u0006\u0002\u0002\u025b\u025a\u0003\u0002",
|
||||
"\u0002\u0002\u025b\u025c\u0003\u0002\u0002\u0002\u025c\u025e\u0003\u0002",
|
||||
"\u0002\u0002\u025d\u025f\u0005\u009fP\u0002\u025e\u025d\u0003\u0002",
|
||||
"\u0002\u0002\u025f\u0260\u0003\u0002\u0002\u0002\u0260\u025e\u0003\u0002",
|
||||
"\u0002\u0002\u0260\u0261\u0003\u0002\u0002\u0002\u0261\u0263\u0003\u0002",
|
||||
"\u0002\u0002\u0262\u0259\u0003\u0002\u0002\u0002\u0262\u0263\u0003\u0002",
|
||||
"\u0002\u0002\u0263\u0090\u0003\u0002\u0002\u0002\u0264\u0265\u0007B",
|
||||
"\u0002\u0002\u0265\u0266\u0005\u008bF\u0002\u0266\u0092\u0003\u0002",
|
||||
"\u0002\u0002\u0267\u026f\u0007)\u0002\u0002\u0268\u0269\u0007^\u0002",
|
||||
"\u0002\u0269\u026e\u000b\u0002\u0002\u0002\u026a\u026b\u0007)\u0002",
|
||||
"\u0002\u026b\u026e\u0007)\u0002\u0002\u026c\u026e\n\u0007\u0002\u0002",
|
||||
"\u026d\u0268\u0003\u0002\u0002\u0002\u026d\u026a\u0003\u0002\u0002\u0002",
|
||||
"\u026d\u026c\u0003\u0002\u0002\u0002\u026e\u0271\u0003\u0002\u0002\u0002",
|
||||
"\u026f\u026d\u0003\u0002\u0002\u0002\u026f\u0270\u0003\u0002\u0002\u0002",
|
||||
"\u0270\u0272\u0003\u0002\u0002\u0002\u0271\u026f\u0003\u0002\u0002\u0002",
|
||||
"\u0272\u0280\u0007)\u0002\u0002\u0273\u027b\u0007$\u0002\u0002\u0274",
|
||||
"\u0275\u0007^\u0002\u0002\u0275\u027a\u000b\u0002\u0002\u0002\u0276",
|
||||
"\u0277\u0007$\u0002\u0002\u0277\u027a\u0007$\u0002\u0002\u0278\u027a",
|
||||
"\n\b\u0002\u0002\u0279\u0274\u0003\u0002\u0002\u0002\u0279\u0276\u0003",
|
||||
"\u0002\u0002\u0002\u0279\u0278\u0003\u0002\u0002\u0002\u027a\u027d\u0003",
|
||||
"\u0002\u0002\u0002\u027b\u0279\u0003\u0002\u0002\u0002\u027b\u027c\u0003",
|
||||
"\u0002\u0002\u0002\u027c\u027e\u0003\u0002\u0002\u0002\u027d\u027b\u0003",
|
||||
"\u0002\u0002\u0002\u027e\u0280\u0007$\u0002\u0002\u027f\u0267\u0003",
|
||||
"\u0002\u0002\u0002\u027f\u0273\u0003\u0002\u0002\u0002\u0280\u0094\u0003",
|
||||
"\u0002\u0002\u0002\u0281\u0282\u00071\u0002\u0002\u0282\u0283\u0007",
|
||||
"1\u0002\u0002\u0283\u0287\u0003\u0002\u0002\u0002\u0284\u0286\n\t\u0002",
|
||||
"\u0002\u0285\u0284\u0003\u0002\u0002\u0002\u0286\u0289\u0003\u0002\u0002",
|
||||
"\u0002\u0287\u0285\u0003\u0002\u0002\u0002\u0287\u0288\u0003\u0002\u0002",
|
||||
"\u0002\u0288\u028f\u0003\u0002\u0002\u0002\u0289\u0287\u0003\u0002\u0002",
|
||||
"\u0002\u028a\u028c\u0007\u000f\u0002\u0002\u028b\u028a\u0003\u0002\u0002",
|
||||
"\u0002\u028b\u028c\u0003\u0002\u0002\u0002\u028c\u028d\u0003\u0002\u0002",
|
||||
"\u0002\u028d\u0290\u0007\f\u0002\u0002\u028e\u0290\u0007\u0002\u0002",
|
||||
"\u0003\u028f\u028b\u0003\u0002\u0002\u0002\u028f\u028e\u0003\u0002\u0002",
|
||||
"\u0002\u0290\u0291\u0003\u0002\u0002\u0002\u0291\u0292\bK\u0002\u0002",
|
||||
"\u0292\u0096\u0003\u0002\u0002\u0002\u0293\u0294\u00071\u0002\u0002",
|
||||
"\u0294\u0295\u0007,\u0002\u0002\u0295\u0299\u0003\u0002\u0002\u0002",
|
||||
"\u0296\u0298\u000b\u0002\u0002\u0002\u0297\u0296\u0003\u0002\u0002\u0002",
|
||||
"\u0298\u029b\u0003\u0002\u0002\u0002\u0299\u029a\u0003\u0002\u0002\u0002",
|
||||
"\u0299\u0297\u0003\u0002\u0002\u0002\u029a\u029c\u0003\u0002\u0002\u0002",
|
||||
"\u029b\u0299\u0003\u0002\u0002\u0002\u029c\u029d\u0007,\u0002\u0002",
|
||||
"\u029d\u029e\u00071\u0002\u0002\u029e\u029f\u0003\u0002\u0002\u0002",
|
||||
"\u029f\u02a0\bL\u0002\u0002\u02a0\u0098\u0003\u0002\u0002\u0002\u02a1",
|
||||
"\u02a2\t\n\u0002\u0002\u02a2\u02a3\u0003\u0002\u0002\u0002\u02a3\u02a4",
|
||||
"\bM\u0002\u0002\u02a4\u009a\u0003\u0002\u0002\u0002\u02a5\u02a6\u000b",
|
||||
"\u0002\u0002\u0002\u02a6\u009c\u0003\u0002\u0002\u0002\u02a7\u02a8\t",
|
||||
"\u000b\u0002\u0002\u02a8\u009e\u0003\u0002\u0002\u0002\u02a9\u02aa\t",
|
||||
"\f\u0002\u0002\u02aa\u00a0\u0003\u0002\u0002\u0002\u02ab\u02ac\t\r\u0002",
|
||||
"\u0002\u02ac\u00a2\u0003\u0002\u0002\u0002\u02ad\u02ae\t\u000e\u0002",
|
||||
"\u0002\u02ae\u00a4\u0003\u0002\u0002\u0002\u02af\u02b0\t\u000f\u0002",
|
||||
"\u0002\u02b0\u00a6\u0003\u0002\u0002\u0002\u02b1\u02b2\t\u0010\u0002",
|
||||
"\u0002\u02b2\u00a8\u0003\u0002\u0002\u0002\u02b3\u02b4\t\u0011\u0002",
|
||||
"\u0002\u02b4\u00aa\u0003\u0002\u0002\u0002\u02b5\u02b6\t\u0012\u0002",
|
||||
"\u0002\u02b6\u00ac\u0003\u0002\u0002\u0002\u02b7\u02b8\t\u0013\u0002",
|
||||
"\u0002\u02b8\u00ae\u0003\u0002\u0002\u0002\u02b9\u02ba\t\u0014\u0002",
|
||||
"\u0002\u02ba\u00b0\u0003\u0002\u0002\u0002\u02bb\u02bc\t\u0015\u0002",
|
||||
"\u0002\u02bc\u00b2\u0003\u0002\u0002\u0002\u02bd\u02be\t\u0016\u0002",
|
||||
"\u0002\u02be\u00b4\u0003\u0002\u0002\u0002\u02bf\u02c0\t\u0017\u0002",
|
||||
"\u0002\u02c0\u00b6\u0003\u0002\u0002\u0002\u02c1\u02c2\t\u0018\u0002",
|
||||
"\u0002\u02c2\u00b8\u0003\u0002\u0002\u0002\u02c3\u02c4\t\u0019\u0002",
|
||||
"\u0002\u02c4\u00ba\u0003\u0002\u0002\u0002\u02c5\u02c6\t\u001a\u0002",
|
||||
"\u0002\u02c6\u00bc\u0003\u0002\u0002\u0002\u02c7\u02c8\t\u001b\u0002",
|
||||
"\u0002\u02c8\u00be\u0003\u0002\u0002\u0002\u02c9\u02ca\t\u001c\u0002",
|
||||
"\u0002\u02ca\u00c0\u0003\u0002\u0002\u0002\u02cb\u02cc\t\u001d\u0002",
|
||||
"\u0002\u02cc\u00c2\u0003\u0002\u0002\u0002\u02cd\u02ce\t\u001e\u0002",
|
||||
"\u0002\u02ce\u00c4\u0003\u0002\u0002\u0002\u02cf\u02d0\t\u001f\u0002",
|
||||
"\u0002\u02d0\u00c6\u0003\u0002\u0002\u0002\u02d1\u02d2\t \u0002\u0002",
|
||||
"\u02d2\u00c8\u0003\u0002\u0002\u0002\u02d3\u02d4\t!\u0002\u0002\u02d4",
|
||||
"\u00ca\u0003\u0002\u0002\u0002\u02d5\u02d6\t\"\u0002\u0002\u02d6\u00cc",
|
||||
"\u0003\u0002\u0002\u0002\u02d7\u02d8\t#\u0002\u0002\u02d8\u00ce\u0003",
|
||||
"\u0002\u0002\u0002\u02d9\u02da\t$\u0002\u0002\u02da\u00d0\u0003\u0002",
|
||||
"\u0002\u0002\u02db\u02dc\t%\u0002\u0002\u02dc\u00d2\u0003\u0002\u0002",
|
||||
"\u0002\u02dd\u02de\t&\u0002\u0002\u02de\u00d4\u0003\u0002\u0002\u0002",
|
||||
"\u02df\u02e0\u000b\u0002\u0002\u0002\u02e0\u02e1\u0003\u0002\u0002\u0002",
|
||||
"\u02e1\u02e2\bk\u0003\u0002\u02e2\u00d6\u0003\u0002\u0002\u0002\u001a",
|
||||
"\u0002\u0125\u019d\u01a9\u022c\u0233\u023d\u0245\u0247\u024d\u0251\u0257",
|
||||
"\u025b\u0260\u0262\u026d\u026f\u0279\u027b\u027f\u0287\u028b\u028f\u0299",
|
||||
"\u0004\u0002\u0003\u0002\u0002\u0004\u0002"].join("");
|
||||
|
||||
|
||||
const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
|
||||
|
||||
const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) );
|
||||
|
||||
export default class CAQLLexer extends antlr4.Lexer {
|
||||
|
||||
static grammarFileName = "CAQLLexer.g4";
|
||||
static channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "ERRORCHANNEL" ];
|
||||
static modeNames = [ "DEFAULT_MODE" ];
|
||||
static literalNames = [ null, "'.'", "'=~'", "'!~'", "'=='", "'!='", "'<'",
|
||||
"'>'", "'<='", "'>='", "'+'", "'-'", "'*'", "'/'",
|
||||
"'%'", "'?'", "':'", "'::'", "'..'", "','", "'('",
|
||||
"')'", "'{'", "'}'", "'['", "']'" ];
|
||||
static symbolicNames = [ null, "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH",
|
||||
"T_EQ", "T_NE", "T_LT", "T_GT", "T_LE", "T_GE",
|
||||
"T_PLUS", "T_MINUS", "T_TIMES", "T_DIV", "T_MOD",
|
||||
"T_QUESTION", "T_COLON", "T_SCOPE", "T_RANGE",
|
||||
"T_COMMA", "T_OPEN", "T_CLOSE", "T_OBJECT_OPEN",
|
||||
"T_OBJECT_CLOSE", "T_ARRAY_OPEN", "T_ARRAY_CLOSE",
|
||||
"T_AGGREGATE", "T_ALL", "T_AND", "T_ANY", "T_ASC",
|
||||
"T_COLLECT", "T_DESC", "T_DISTINCT", "T_FALSE",
|
||||
"T_FILTER", "T_FOR", "T_GRAPH", "T_IN", "T_INBOUND",
|
||||
"T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS", "T_LET",
|
||||
"T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
|
||||
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE",
|
||||
"T_RETURN", "T_SHORTEST_PATH", "T_SORT", "T_TRUE",
|
||||
"T_UPDATE", "T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT",
|
||||
"T_OPTIONS", "T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT",
|
||||
"T_NEW", "T_OLD", "T_STRING", "T_INT", "T_FLOAT",
|
||||
"T_PARAMETER", "T_QUOTED_STRING", "SINGLE_LINE_COMMENT",
|
||||
"MULTILINE_COMMENT", "SPACES", "UNEXPECTED_CHAR",
|
||||
"ERROR_RECONGNIGION" ];
|
||||
static ruleNames = [ "DOT", "T_REGEX_MATCH", "T_REGEX_NON_MATCH", "T_EQ",
|
||||
"T_NE", "T_LT", "T_GT", "T_LE", "T_GE", "T_PLUS",
|
||||
"T_MINUS", "T_TIMES", "T_DIV", "T_MOD", "T_QUESTION",
|
||||
"T_COLON", "T_SCOPE", "T_RANGE", "T_COMMA", "T_OPEN",
|
||||
"T_CLOSE", "T_OBJECT_OPEN", "T_OBJECT_CLOSE", "T_ARRAY_OPEN",
|
||||
"T_ARRAY_CLOSE", "T_AGGREGATE", "T_ALL", "T_AND",
|
||||
"T_ANY", "T_ASC", "T_COLLECT", "T_DESC", "T_DISTINCT",
|
||||
"T_FALSE", "T_FILTER", "T_FOR", "T_GRAPH", "T_IN",
|
||||
"T_INBOUND", "T_INSERT", "T_INTO", "T_K_SHORTEST_PATHS",
|
||||
"T_LET", "T_LIKE", "T_LIMIT", "T_NONE", "T_NOT", "T_NULL",
|
||||
"T_OR", "T_OUTBOUND", "T_REMOVE", "T_REPLACE", "T_RETURN",
|
||||
"T_SHORTEST_PATH", "T_SORT", "T_TRUE", "T_UPDATE",
|
||||
"T_UPSERT", "T_WITH", "T_KEEP", "T_COUNT", "T_OPTIONS",
|
||||
"T_PRUNE", "T_SEARCH", "T_TO", "T_CURRENT", "T_NEW",
|
||||
"T_OLD", "T_STRING", "T_INT", "T_FLOAT", "T_PARAMETER",
|
||||
"T_QUOTED_STRING", "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT",
|
||||
"SPACES", "UNEXPECTED_CHAR", "HEX_DIGIT", "DIGIT",
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
|
||||
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
|
||||
"U", "V", "W", "X", "Y", "Z", "ERROR_RECONGNIGION" ];
|
||||
|
||||
constructor(input) {
|
||||
super(input)
|
||||
this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache());
|
||||
}
|
||||
|
||||
get atn() {
|
||||
return atn;
|
||||
}
|
||||
}
|
||||
|
||||
CAQLLexer.EOF = antlr4.Token.EOF;
|
||||
CAQLLexer.DOT = 1;
|
||||
CAQLLexer.T_REGEX_MATCH = 2;
|
||||
CAQLLexer.T_REGEX_NON_MATCH = 3;
|
||||
CAQLLexer.T_EQ = 4;
|
||||
CAQLLexer.T_NE = 5;
|
||||
CAQLLexer.T_LT = 6;
|
||||
CAQLLexer.T_GT = 7;
|
||||
CAQLLexer.T_LE = 8;
|
||||
CAQLLexer.T_GE = 9;
|
||||
CAQLLexer.T_PLUS = 10;
|
||||
CAQLLexer.T_MINUS = 11;
|
||||
CAQLLexer.T_TIMES = 12;
|
||||
CAQLLexer.T_DIV = 13;
|
||||
CAQLLexer.T_MOD = 14;
|
||||
CAQLLexer.T_QUESTION = 15;
|
||||
CAQLLexer.T_COLON = 16;
|
||||
CAQLLexer.T_SCOPE = 17;
|
||||
CAQLLexer.T_RANGE = 18;
|
||||
CAQLLexer.T_COMMA = 19;
|
||||
CAQLLexer.T_OPEN = 20;
|
||||
CAQLLexer.T_CLOSE = 21;
|
||||
CAQLLexer.T_OBJECT_OPEN = 22;
|
||||
CAQLLexer.T_OBJECT_CLOSE = 23;
|
||||
CAQLLexer.T_ARRAY_OPEN = 24;
|
||||
CAQLLexer.T_ARRAY_CLOSE = 25;
|
||||
CAQLLexer.T_AGGREGATE = 26;
|
||||
CAQLLexer.T_ALL = 27;
|
||||
CAQLLexer.T_AND = 28;
|
||||
CAQLLexer.T_ANY = 29;
|
||||
CAQLLexer.T_ASC = 30;
|
||||
CAQLLexer.T_COLLECT = 31;
|
||||
CAQLLexer.T_DESC = 32;
|
||||
CAQLLexer.T_DISTINCT = 33;
|
||||
CAQLLexer.T_FALSE = 34;
|
||||
CAQLLexer.T_FILTER = 35;
|
||||
CAQLLexer.T_FOR = 36;
|
||||
CAQLLexer.T_GRAPH = 37;
|
||||
CAQLLexer.T_IN = 38;
|
||||
CAQLLexer.T_INBOUND = 39;
|
||||
CAQLLexer.T_INSERT = 40;
|
||||
CAQLLexer.T_INTO = 41;
|
||||
CAQLLexer.T_K_SHORTEST_PATHS = 42;
|
||||
CAQLLexer.T_LET = 43;
|
||||
CAQLLexer.T_LIKE = 44;
|
||||
CAQLLexer.T_LIMIT = 45;
|
||||
CAQLLexer.T_NONE = 46;
|
||||
CAQLLexer.T_NOT = 47;
|
||||
CAQLLexer.T_NULL = 48;
|
||||
CAQLLexer.T_OR = 49;
|
||||
CAQLLexer.T_OUTBOUND = 50;
|
||||
CAQLLexer.T_REMOVE = 51;
|
||||
CAQLLexer.T_REPLACE = 52;
|
||||
CAQLLexer.T_RETURN = 53;
|
||||
CAQLLexer.T_SHORTEST_PATH = 54;
|
||||
CAQLLexer.T_SORT = 55;
|
||||
CAQLLexer.T_TRUE = 56;
|
||||
CAQLLexer.T_UPDATE = 57;
|
||||
CAQLLexer.T_UPSERT = 58;
|
||||
CAQLLexer.T_WITH = 59;
|
||||
CAQLLexer.T_KEEP = 60;
|
||||
CAQLLexer.T_COUNT = 61;
|
||||
CAQLLexer.T_OPTIONS = 62;
|
||||
CAQLLexer.T_PRUNE = 63;
|
||||
CAQLLexer.T_SEARCH = 64;
|
||||
CAQLLexer.T_TO = 65;
|
||||
CAQLLexer.T_CURRENT = 66;
|
||||
CAQLLexer.T_NEW = 67;
|
||||
CAQLLexer.T_OLD = 68;
|
||||
CAQLLexer.T_STRING = 69;
|
||||
CAQLLexer.T_INT = 70;
|
||||
CAQLLexer.T_FLOAT = 71;
|
||||
CAQLLexer.T_PARAMETER = 72;
|
||||
CAQLLexer.T_QUOTED_STRING = 73;
|
||||
CAQLLexer.SINGLE_LINE_COMMENT = 74;
|
||||
CAQLLexer.MULTILINE_COMMENT = 75;
|
||||
CAQLLexer.SPACES = 76;
|
||||
CAQLLexer.UNEXPECTED_CHAR = 77;
|
||||
CAQLLexer.ERROR_RECONGNIGION = 78;
|
||||
|
||||
CAQLLexer.ERRORCHANNEL = 2;
|
||||
|
||||
|
||||
|
||||
103
ui/src/suggestions/grammar/RQLLexer.tokens
Normal file
@@ -0,0 +1,103 @@
|
||||
DOT=1
|
||||
T_REGEX_MATCH=2
|
||||
T_REGEX_NON_MATCH=3
|
||||
T_EQ=4
|
||||
T_NE=5
|
||||
T_LT=6
|
||||
T_GT=7
|
||||
T_LE=8
|
||||
T_GE=9
|
||||
T_PLUS=10
|
||||
T_MINUS=11
|
||||
T_TIMES=12
|
||||
T_DIV=13
|
||||
T_MOD=14
|
||||
T_QUESTION=15
|
||||
T_COLON=16
|
||||
T_SCOPE=17
|
||||
T_RANGE=18
|
||||
T_COMMA=19
|
||||
T_OPEN=20
|
||||
T_CLOSE=21
|
||||
T_OBJECT_OPEN=22
|
||||
T_OBJECT_CLOSE=23
|
||||
T_ARRAY_OPEN=24
|
||||
T_ARRAY_CLOSE=25
|
||||
T_AGGREGATE=26
|
||||
T_ALL=27
|
||||
T_AND=28
|
||||
T_ANY=29
|
||||
T_ASC=30
|
||||
T_COLLECT=31
|
||||
T_DESC=32
|
||||
T_DISTINCT=33
|
||||
T_FALSE=34
|
||||
T_FILTER=35
|
||||
T_FOR=36
|
||||
T_GRAPH=37
|
||||
T_IN=38
|
||||
T_INBOUND=39
|
||||
T_INSERT=40
|
||||
T_INTO=41
|
||||
T_K_SHORTEST_PATHS=42
|
||||
T_LET=43
|
||||
T_LIKE=44
|
||||
T_LIMIT=45
|
||||
T_NONE=46
|
||||
T_NOT=47
|
||||
T_NULL=48
|
||||
T_OR=49
|
||||
T_OUTBOUND=50
|
||||
T_REMOVE=51
|
||||
T_REPLACE=52
|
||||
T_RETURN=53
|
||||
T_SHORTEST_PATH=54
|
||||
T_SORT=55
|
||||
T_TRUE=56
|
||||
T_UPDATE=57
|
||||
T_UPSERT=58
|
||||
T_WITH=59
|
||||
T_KEEP=60
|
||||
T_COUNT=61
|
||||
T_OPTIONS=62
|
||||
T_PRUNE=63
|
||||
T_SEARCH=64
|
||||
T_TO=65
|
||||
T_CURRENT=66
|
||||
T_NEW=67
|
||||
T_OLD=68
|
||||
T_STRING=69
|
||||
T_INT=70
|
||||
T_FLOAT=71
|
||||
T_PARAMETER=72
|
||||
T_QUOTED_STRING=73
|
||||
SINGLE_LINE_COMMENT=74
|
||||
MULTILINE_COMMENT=75
|
||||
SPACES=76
|
||||
UNEXPECTED_CHAR=77
|
||||
ERROR_RECONGNIGION=78
|
||||
'.'=1
|
||||
'=~'=2
|
||||
'!~'=3
|
||||
'=='=4
|
||||
'!='=5
|
||||
'<'=6
|
||||
'>'=7
|
||||
'<='=8
|
||||
'>='=9
|
||||
'+'=10
|
||||
'-'=11
|
||||
'*'=12
|
||||
'/'=13
|
||||
'%'=14
|
||||
'?'=15
|
||||
':'=16
|
||||
'::'=17
|
||||
'..'=18
|
||||
','=19
|
||||
'('=20
|
||||
')'=21
|
||||
'{'=22
|
||||
'}'=23
|
||||
'['=24
|
||||
']'=25
|
||||
178
ui/src/suggestions/grammar/RQLParser.interp
Normal file
1866
ui/src/suggestions/grammar/RQLParser.js
Normal file
103
ui/src/suggestions/grammar/RQLParser.tokens
Normal file
@@ -0,0 +1,103 @@
|
||||
DOT=1
|
||||
T_REGEX_MATCH=2
|
||||
T_REGEX_NON_MATCH=3
|
||||
T_EQ=4
|
||||
T_NE=5
|
||||
T_LT=6
|
||||
T_GT=7
|
||||
T_LE=8
|
||||
T_GE=9
|
||||
T_PLUS=10
|
||||
T_MINUS=11
|
||||
T_TIMES=12
|
||||
T_DIV=13
|
||||
T_MOD=14
|
||||
T_QUESTION=15
|
||||
T_COLON=16
|
||||
T_SCOPE=17
|
||||
T_RANGE=18
|
||||
T_COMMA=19
|
||||
T_OPEN=20
|
||||
T_CLOSE=21
|
||||
T_OBJECT_OPEN=22
|
||||
T_OBJECT_CLOSE=23
|
||||
T_ARRAY_OPEN=24
|
||||
T_ARRAY_CLOSE=25
|
||||
T_AGGREGATE=26
|
||||
T_ALL=27
|
||||
T_AND=28
|
||||
T_ANY=29
|
||||
T_ASC=30
|
||||
T_COLLECT=31
|
||||
T_DESC=32
|
||||
T_DISTINCT=33
|
||||
T_FALSE=34
|
||||
T_FILTER=35
|
||||
T_FOR=36
|
||||
T_GRAPH=37
|
||||
T_IN=38
|
||||
T_INBOUND=39
|
||||
T_INSERT=40
|
||||
T_INTO=41
|
||||
T_K_SHORTEST_PATHS=42
|
||||
T_LET=43
|
||||
T_LIKE=44
|
||||
T_LIMIT=45
|
||||
T_NONE=46
|
||||
T_NOT=47
|
||||
T_NULL=48
|
||||
T_OR=49
|
||||
T_OUTBOUND=50
|
||||
T_REMOVE=51
|
||||
T_REPLACE=52
|
||||
T_RETURN=53
|
||||
T_SHORTEST_PATH=54
|
||||
T_SORT=55
|
||||
T_TRUE=56
|
||||
T_UPDATE=57
|
||||
T_UPSERT=58
|
||||
T_WITH=59
|
||||
T_KEEP=60
|
||||
T_COUNT=61
|
||||
T_OPTIONS=62
|
||||
T_PRUNE=63
|
||||
T_SEARCH=64
|
||||
T_TO=65
|
||||
T_CURRENT=66
|
||||
T_NEW=67
|
||||
T_OLD=68
|
||||
T_STRING=69
|
||||
T_INT=70
|
||||
T_FLOAT=71
|
||||
T_PARAMETER=72
|
||||
T_QUOTED_STRING=73
|
||||
SINGLE_LINE_COMMENT=74
|
||||
MULTILINE_COMMENT=75
|
||||
SPACES=76
|
||||
UNEXPECTED_CHAR=77
|
||||
ERROR_RECONGNIGION=78
|
||||
'.'=1
|
||||
'=~'=2
|
||||
'!~'=3
|
||||
'=='=4
|
||||
'!='=5
|
||||
'<'=6
|
||||
'>'=7
|
||||
'<='=8
|
||||
'>='=9
|
||||
'+'=10
|
||||
'-'=11
|
||||
'*'=12
|
||||
'/'=13
|
||||
'%'=14
|
||||
'?'=15
|
||||
':'=16
|
||||
'::'=17
|
||||
'..'=18
|
||||
','=19
|
||||
'('=20
|
||||
')'=21
|
||||
'{'=22
|
||||
'}'=23
|
||||
'['=24
|
||||
']'=25
|
||||
108
ui/src/suggestions/grammar/RQLParserListener.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// Generated from CAQLParser.g4 by ANTLR 4.9.2
|
||||
// jshint ignore: start
|
||||
import antlr4 from 'antlr4';
|
||||
|
||||
// This class defines a complete listener for a parse tree produced by CAQLParser.
|
||||
export default class CAQLParserListener extends antlr4.tree.ParseTreeListener {
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#parse.
|
||||
enterParse(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#parse.
|
||||
exitParse(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#expression.
|
||||
enterExpression(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#expression.
|
||||
exitExpression(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#operator_unary.
|
||||
enterOperator_unary(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#operator_unary.
|
||||
exitOperator_unary(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#reference.
|
||||
enterReference(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#reference.
|
||||
exitReference(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#compound_value.
|
||||
enterCompound_value(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#compound_value.
|
||||
exitCompound_value(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#function_call.
|
||||
enterFunction_call(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#function_call.
|
||||
exitFunction_call(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#value_literal.
|
||||
enterValue_literal(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#value_literal.
|
||||
exitValue_literal(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#array.
|
||||
enterArray(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#array.
|
||||
exitArray(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#object.
|
||||
enterObject(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#object.
|
||||
exitObject(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#object_element.
|
||||
enterObject_element(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#object_element.
|
||||
exitObject_element(ctx) {
|
||||
}
|
||||
|
||||
|
||||
// Enter a parse tree produced by CAQLParser#object_element_name.
|
||||
enterObject_element_name(ctx) {
|
||||
}
|
||||
|
||||
// Exit a parse tree produced by CAQLParser#object_element_name.
|
||||
exitObject_element_name(ctx) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
46
ui/src/suggestions/suggestions.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import lexerModule from "./grammar/CAQLLexer.js";
|
||||
import parserModule from "./grammar/CAQLParser.js";
|
||||
|
||||
import antlr4 from "antlr4";
|
||||
|
||||
class ErrorListener extends antlr4.error.ErrorListener {
|
||||
/**
|
||||
* Checks syntax error
|
||||
*
|
||||
* @param {object} recognizer The parsing support code essentially. Most of it is error recovery stuff
|
||||
* @param {object} symbol Offending symbol
|
||||
* @param {int} line Line of offending symbol
|
||||
* @param {int} column Position in line of offending symbol
|
||||
* @param {string} message Error message
|
||||
* @param {string} payload Stack trace
|
||||
*/
|
||||
syntaxError(
|
||||
recognizer: any,
|
||||
symbol: any,
|
||||
line: number,
|
||||
column: number,
|
||||
message: string,
|
||||
payload: string
|
||||
) {
|
||||
throw {symbol, line, column, message, payload};
|
||||
}
|
||||
}
|
||||
|
||||
export function validateCAQL(term: string): any {
|
||||
const chars = new antlr4.InputStream(term);
|
||||
const lexer = new lexerModule(chars);
|
||||
|
||||
const tokens = new antlr4.CommonTokenStream(lexer);
|
||||
const parser = new parserModule(tokens);
|
||||
|
||||
const listener = new ErrorListener();
|
||||
|
||||
parser.removeErrorListeners();
|
||||
parser.addErrorListener(listener);
|
||||
try {
|
||||
parser.parse()
|
||||
return null;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
17
ui/src/types/types.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export interface Problem {
|
||||
title: string;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
enum AlertType {
|
||||
success = "success",
|
||||
info = "info",
|
||||
warning = "warning",
|
||||
error = "error",
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
name: string;
|
||||
detail: string;
|
||||
type: AlertType;
|
||||
}
|
||||
48
ui/src/views/API.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-card style="background-color: #fff;" class="mt-8">
|
||||
<div class="swagger" id="swagger" ></div>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import SwaggerUI from 'swagger-ui';
|
||||
import 'swagger-ui/dist/swagger-ui.css';
|
||||
import Vue from "vue";
|
||||
import spec from '../../../generated/community.json';
|
||||
|
||||
export default Vue.extend({
|
||||
name: "API",
|
||||
components: {},
|
||||
mounted() {
|
||||
SwaggerUI({
|
||||
spec: spec,
|
||||
dom_id: '#swagger',
|
||||
oauth2RedirectUrl: location.href
|
||||
})
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#swagger a,
|
||||
#swagger h1,
|
||||
#swagger h2,
|
||||
#swagger h3,
|
||||
#swagger h4,
|
||||
#swagger h5,
|
||||
#swagger h6 {
|
||||
color: black !important
|
||||
}
|
||||
|
||||
#swagger .info {
|
||||
padding: 0 10px 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#swagger .servers-title,
|
||||
#swagger .servers {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
264
ui/src/views/ArtifactPopup.vue
Normal file
@@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<h1>{{ name }}</h1>
|
||||
|
||||
<v-divider class="my-2"></v-divider>
|
||||
|
||||
<h2 class="text--disabled" style="font-size: 12pt" v-if="artifact">
|
||||
Status:
|
||||
<v-menu offset-y class="mr-2">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<span v-bind="attrs" v-on="on">
|
||||
<v-icon small class="mr-1" :color="statusColor(artifact.status)">{{ statusIcon(artifact.status) }}</v-icon>
|
||||
<span :class="statusColor(artifact.status) + '--text'">{{ artifact.status | capitalize }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item dense link v-for="state in otherStates" :key="state.id" @click="setStatus(state.id)">
|
||||
<v-list-item-title>
|
||||
Set status to <v-icon small>{{ statusIcon(state.id) }}</v-icon> {{ state.name }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
·
|
||||
Type:
|
||||
<v-menu
|
||||
:close-on-content-click="false"
|
||||
offset-y
|
||||
class="mr-2">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<span v-bind="attrs" v-on="on">
|
||||
{{ artifact.type ? artifact.type : "empty" }}
|
||||
</span>
|
||||
</template>
|
||||
<v-combobox
|
||||
class="pt-6 pb-0 px-3"
|
||||
style="background-color: white"
|
||||
v-model="artifacttype"
|
||||
:items="['ip', 'domain', 'md5', 'sha1', 'sha256', 'filename', 'url']"
|
||||
label="Artifact Type"
|
||||
@change="setArtifactType"
|
||||
></v-combobox>
|
||||
</v-menu>
|
||||
</h2>
|
||||
|
||||
<v-divider class="mt-0 mb-4"></v-divider>
|
||||
|
||||
<div v-if="automations">
|
||||
<v-card
|
||||
v-for="automation in artifactautomations" :key="automation.id" class="mb-4" elevation="0" outlined>
|
||||
<v-card-title>
|
||||
{{ automation.id }}
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
v-if="artifact && artifact.enrichments && automation.id in artifact.enrichments"
|
||||
@click="enrich(automation.id)"
|
||||
elevation="0"
|
||||
>
|
||||
<v-icon>mdi-sync</v-icon>
|
||||
</v-btn>
|
||||
<v-btn v-else @click="enrich(automation.id)" elevation="0">
|
||||
<v-icon>mdi-play</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text v-if="artifact && artifact.enrichments && automation.id in artifact.enrichments && artifact.enrichments[automation.id].data">
|
||||
<div class="template" v-if="artifact.enrichments[automation.id].html" v-html="artifact.enrichments[automation.id].html"></div>
|
||||
<JSONHTML v-else :json="artifact.enrichments[automation.id].data"></JSONHTML>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
|
||||
<div v-if="artifact">
|
||||
<div v-for="enrichment in artifact.enrichments" :key="enrichment.name" >
|
||||
<v-card v-if="!hasautomation(enrichment.name)" outlined>
|
||||
<v-card-title>
|
||||
{{ enrichment.name }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<vue-markdown>
|
||||
{{ enrichment.data }}
|
||||
</vue-markdown>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {
|
||||
Artifact,
|
||||
AutomationResponse, AutomationResponseTypeEnum, AutomationTypeEnum,
|
||||
Type,
|
||||
TypeColorEnum
|
||||
} from "@/client";
|
||||
import VueMarkdown from "vue-markdown";
|
||||
import { API } from "@/services/api";
|
||||
import JSONHTML from "../components/JSONHTML.vue";
|
||||
|
||||
|
||||
interface State {
|
||||
artifact?: Artifact;
|
||||
automations?: Array<AutomationResponse>;
|
||||
artifacttype: string;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "ArtifactPopup",
|
||||
components: {
|
||||
"vue-markdown": VueMarkdown,
|
||||
JSONHTML,
|
||||
},
|
||||
props: ["id", "name"],
|
||||
data: (): State => ({
|
||||
artifact: undefined,
|
||||
automations: undefined,
|
||||
artifacttype: "unknown",
|
||||
}),
|
||||
watch: {
|
||||
id: function(): void {
|
||||
this.load();
|
||||
},
|
||||
name: function(): void {
|
||||
this.load();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
artifactautomations: function (): Array<AutomationResponse> {
|
||||
if (!this.automations) {
|
||||
return [];
|
||||
}
|
||||
return this.lodash.filter(this.automations, (automation: AutomationResponse) => {
|
||||
if (!automation || !automation.type) {
|
||||
return true;
|
||||
}
|
||||
return this.lodash.includes(automation.type, AutomationResponseTypeEnum.Artifact)
|
||||
})
|
||||
},
|
||||
ticketID(): number {
|
||||
return parseInt(this.id, 10);
|
||||
},
|
||||
otherStates: function (): Array<Type> {
|
||||
return this.lodash.filter(this.$store.state.settings.artifactStates, (state: Type) => {
|
||||
if (!this.artifact || !this.artifact.status) {
|
||||
return true;
|
||||
}
|
||||
return state.id !== this.artifact.status;
|
||||
})
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setArtifactType() {
|
||||
if (!this.artifact || !this.artifact.name || this.ticketID === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let artifact = this.artifact
|
||||
artifact.type = this.artifacttype
|
||||
API.setArtifact(this.ticketID, this.artifact.name, artifact).then((response) => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Artifact type changed", type: "success" })
|
||||
if (response.data.artifacts) {
|
||||
this.lodash.forEach(response.data.artifacts, (artifact) => {
|
||||
if (artifact.name == this.name) {
|
||||
this.artifact = artifact;
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
hasautomation(name: string): boolean {
|
||||
let found = false;
|
||||
this.lodash.forEach(this.automations, (automation) => {
|
||||
if (automation.id === name) {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
return found;
|
||||
},
|
||||
loadArtifact(id: number, artifact: string) {
|
||||
API.getArtifact(id, artifact).then((response) => {
|
||||
this.artifact = response.data;
|
||||
});
|
||||
},
|
||||
loadAutomations() {
|
||||
API.listAutomations().then((response) => {
|
||||
this.automations = response.data;
|
||||
});
|
||||
},
|
||||
enrich(automation: string) {
|
||||
if (this.artifact === undefined || this.ticketID === undefined) {
|
||||
return
|
||||
}
|
||||
API.runArtifact(this.ticketID, this.name, automation);
|
||||
},
|
||||
statusIcon: function (status: string): string {
|
||||
let icon = "mdi-help";
|
||||
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
|
||||
if (status === state.id) {
|
||||
icon = state.icon;
|
||||
}
|
||||
})
|
||||
return icon;
|
||||
},
|
||||
statusColor: function (status: string) {
|
||||
let color = TypeColorEnum.Info;
|
||||
this.lodash.forEach(this.$store.state.settings.artifactStates, (state: Type) => {
|
||||
if (status === state.id && state.color) {
|
||||
color = state.color
|
||||
}
|
||||
})
|
||||
return color;
|
||||
},
|
||||
setStatus(status: string) {
|
||||
if (!this.artifact || !this.artifact.name || this.ticketID === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let artifact = this.artifact
|
||||
artifact.status = status
|
||||
API.setArtifact(this.ticketID, this.artifact.name, artifact).then((response) => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Artifact status changed", type: "success" })
|
||||
if (response.data.artifacts) {
|
||||
this.lodash.forEach(response.data.artifacts, (artifact) => {
|
||||
if (artifact.name == this.name) {
|
||||
this.artifact = artifact;
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
load() {
|
||||
this.loadArtifact(this.ticketID, this.name);
|
||||
}
|
||||
},
|
||||
mounted(): void {
|
||||
this.load();
|
||||
this.loadAutomations();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (id === "tickets/" + this.ticketID) {
|
||||
this.load();
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.template {
|
||||
overflow: auto;
|
||||
}
|
||||
.template table, .template th, .template td {
|
||||
border: 1px solid #777 !important;
|
||||
border-left: 0 !important;
|
||||
border-right: 0 !important;
|
||||
padding: 4px !important;
|
||||
}
|
||||
</style>
|
||||
131
ui/src/views/Automation.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div v-if="automation !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
|
||||
<v-alert v-if="readonly" type="info">You do not have write access to automations.</v-alert>
|
||||
<h2 v-if="readonly">Automation: {{ automation.id }}</h2>
|
||||
<h2 v-else-if="this.$route.params.id === 'new'">New Automation: {{ automation.id }}</h2>
|
||||
<h2 v-else>Edit Automation: {{ automation.id }}</h2>
|
||||
|
||||
<v-row class="flex-grow-0 flex-shrink-0">
|
||||
<v-col cols="12">
|
||||
<v-text-field :readonly="readonly" label="ID" v-model="automation.id" class="flex-grow-0 flex-shrink-0"></v-text-field>
|
||||
|
||||
<v-select
|
||||
label="Type"
|
||||
:items="types"
|
||||
item-text="id"
|
||||
return-object
|
||||
multiple
|
||||
v-model="automation.type"
|
||||
></v-select>
|
||||
|
||||
<v-text-field :readonly="readonly" label="Docker Image" v-model="automation.image" class="flex-grow-0 flex-shrink-0"></v-text-field>
|
||||
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Script</v-subheader>
|
||||
<div class="flex-grow-1 flex-shrink-1 overflow-scroll">
|
||||
<Editor v-model="automation.script" lang="python" :readonly="readonly" ></Editor>
|
||||
</div>
|
||||
|
||||
<AdvancedJSONSchemaEditor
|
||||
@save="save"
|
||||
:schema="automation.schema ? JSON.parse(automation.schema) : {}"
|
||||
hidepreview
|
||||
class="mt-4"
|
||||
:readonly="readonly"></AdvancedJSONSchemaEditor>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import Editor from "../components/Editor.vue";
|
||||
import AdvancedJSONSchemaEditor from "../components/AdvancedJSONSchemaEditor.vue";
|
||||
import {API} from "@/services/api";
|
||||
import {AutomationResponse, AutomationForm, AutomationResponseTypeEnum} from "@/client";
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
interface State {
|
||||
automation?: AutomationResponse;
|
||||
data?: any;
|
||||
valid: boolean;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Automation",
|
||||
components: { Editor, AdvancedJSONSchemaEditor },
|
||||
data: (): State => ({
|
||||
automation: undefined,
|
||||
data: undefined,
|
||||
valid: true,
|
||||
}),
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.loadAutomation();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("engineer:automation:write");
|
||||
},
|
||||
types: function (): Array<string> {
|
||||
return [ AutomationResponseTypeEnum.Global, AutomationResponseTypeEnum.Playbook, AutomationResponseTypeEnum.Artifact ]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save(schema) {
|
||||
if (this.automation === undefined) {
|
||||
return;
|
||||
}
|
||||
let automation = this.automation as any as AutomationForm;
|
||||
automation.schema = schema;
|
||||
if (this.$route.params.id == "new") {
|
||||
API.createAutomation(automation);
|
||||
} else {
|
||||
API.updateAutomation(this.$route.params.id, automation);
|
||||
}
|
||||
},
|
||||
loadAutomation() {
|
||||
if (!this.$route.params.id) {
|
||||
return;
|
||||
}
|
||||
if (this.$route.params.id == "new") {
|
||||
this.automation = { id: "my-automation", image: "docker.io/ubuntu", script: "", type: [ AutomationResponseTypeEnum.Global, AutomationResponseTypeEnum.Playbook, AutomationResponseTypeEnum.Artifact ] };
|
||||
} else {
|
||||
API.getAutomation(this.$route.params.id).then((response) => {
|
||||
this.automation = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
timeformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
dateformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
datetimeformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadAutomation();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
64
ui/src/views/AutomationList.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<v-main style="min-height: 100vh">
|
||||
<List
|
||||
:items="automations"
|
||||
routername="Automation"
|
||||
itemid="id"
|
||||
itemname="id"
|
||||
singular="Automation"
|
||||
plural="Automations"
|
||||
writepermission="engineer:automation:write"
|
||||
@delete="deleteAutomation"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {AutomationResponse} from "@/client";
|
||||
import {API} from "@/services/api";
|
||||
import List from "../components/List.vue";
|
||||
|
||||
interface State {
|
||||
automations: Array<AutomationResponse>;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "AutomationList",
|
||||
components: {List},
|
||||
data: (): State => ({
|
||||
automations: [],
|
||||
}),
|
||||
methods: {
|
||||
loadAutomations() {
|
||||
API.listAutomations().then((response) => {
|
||||
this.automations = response.data;
|
||||
});
|
||||
},
|
||||
deleteAutomation(name: string) {
|
||||
API.deleteAutomation(name).then(() => {
|
||||
this.loadAutomations();
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadAutomations();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "automations/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.loadAutomations()
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
219
ui/src/views/Dashboard.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<v-main>
|
||||
<v-row>
|
||||
<v-col v-if="statistics" cols="12" lg="7">
|
||||
<v-row>
|
||||
<v-col cols="4">
|
||||
<v-subheader>Unassigned tickets</v-subheader>
|
||||
<span style="font-size: 60pt; text-align: center; display: block">
|
||||
<router-link :to="{
|
||||
name: 'TicketList',
|
||||
params: { query: 'status == \'open\' AND !owner' }
|
||||
}">
|
||||
{{ statistics.unassigned }}
|
||||
</router-link>
|
||||
</span>
|
||||
<v-subheader>Your tickets</v-subheader>
|
||||
<span style="font-size: 60pt; text-align: center; display: block">
|
||||
<router-link :to="{
|
||||
name: 'TicketList',
|
||||
params: { query: 'status == \'open\' AND owner == \'' + $store.state.user.id + '\'' }
|
||||
}">
|
||||
{{ $store.state.user.id in statistics.open_tickets_per_user ? statistics.open_tickets_per_user[$store.state.user.id] : 0 }}
|
||||
</router-link>
|
||||
</span>
|
||||
</v-col>
|
||||
<v-col cols="8">
|
||||
<v-subheader>Open tickets per owner</v-subheader>
|
||||
<bar-chart
|
||||
v-if="open_tickets_per_user"
|
||||
:chart-data="open_tickets_per_user"
|
||||
:styles="{
|
||||
width: '100%',
|
||||
'max-height': '400px',
|
||||
position: 'relative'
|
||||
}"
|
||||
:chart-options="{
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
legend: undefined,
|
||||
scales: { xAxes: [ { ticks: { beginAtZero: true, precision: 0 } } ] },
|
||||
onClick: clickUser,
|
||||
hover: {
|
||||
onHover: function(e) {
|
||||
var point = this.getElementAtEvent(e);
|
||||
if (point.length) e.target.style.cursor = 'pointer';
|
||||
else e.target.style.cursor = 'default';
|
||||
}
|
||||
}
|
||||
}"
|
||||
></bar-chart>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="7">
|
||||
<v-subheader>Tickets created per week</v-subheader>
|
||||
<line-chart
|
||||
v-if="tickets_per_week"
|
||||
:chart-data="tickets_per_week"
|
||||
:styles="{ width: '100%', position: 'relative' }"
|
||||
:chart-options="{
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
legend: undefined,
|
||||
scales: { yAxes: [ { ticks: { beginAtZero: true, precision: 0 } } ] }
|
||||
}"
|
||||
>
|
||||
</line-chart>
|
||||
</v-col>
|
||||
<v-col cols="5">
|
||||
<v-subheader>Ticket Types</v-subheader>
|
||||
<pie-chart
|
||||
v-if="tickets_per_type"
|
||||
:chart-data="tickets_per_type"
|
||||
:styles="{ width: '100%', position: 'relative' }"
|
||||
:chart-options="{
|
||||
onClick: clickPie,
|
||||
hover: {
|
||||
onHover: function(e) {
|
||||
var point = this.getElementAtEvent(e);
|
||||
if (point.length) e.target.style.cursor = 'pointer';
|
||||
else e.target.style.cursor = 'default';
|
||||
}
|
||||
}
|
||||
}"
|
||||
>
|
||||
</pie-chart>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
<v-col cols="12" lg="5">
|
||||
<TicketList :type="this.$route.params.type" @click="open"></TicketList>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import LineChart from "../components/charts/Line";
|
||||
import BarChart from "../components/charts/Bar";
|
||||
import PieChart from "../components/charts/Doughnut";
|
||||
import { API } from "@/services/api";
|
||||
import {Statistics, TicketResponse} from "@/client";
|
||||
import {DateTime} from "luxon";
|
||||
import { colors } from "@/plugins/vuetify";
|
||||
import TicketList from "@/components/TicketList.vue";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Dashboard",
|
||||
components: {
|
||||
LineChart,
|
||||
BarChart,
|
||||
PieChart,
|
||||
TicketList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statistics: (undefined as unknown) as Statistics
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
tickets_per_type: function () {
|
||||
let data = { labels: [] as Array<string>, datasets: [{ backgroundColor: [] as Array<string>, data: [] as Array<number> }] }
|
||||
this.lodash.forEach(this.statistics.tickets_per_type, (count, type) => {
|
||||
data.labels.push(type);
|
||||
data.datasets[0].data.push(count);
|
||||
|
||||
data.datasets[0].backgroundColor.push(this.color(type));
|
||||
})
|
||||
return data
|
||||
},
|
||||
open_tickets_per_user: function () {
|
||||
let data = { labels: [] as Array<string>, datasets: [{ backgroundColor: [] as Array<string>, data: [] as Array<number> }] }
|
||||
this.lodash.forEach(this.statistics.open_tickets_per_user, (count, user) => {
|
||||
if (!user) {
|
||||
data.labels.push("unassigned");
|
||||
} else {
|
||||
data.labels.push(user);
|
||||
}
|
||||
data.datasets[0].data.push(count);
|
||||
data.datasets[0].backgroundColor.push(this.color(user));
|
||||
})
|
||||
return data
|
||||
},
|
||||
tickets_per_week: function () {
|
||||
let data = {labels: [] as Array<string>, datasets: [{backgroundColor: [] as Array<string>, data: [] as Array<number> }]}
|
||||
this.lodash.forEach(this.weeks(), (week) => {
|
||||
data.labels.push(week);
|
||||
if (week in this.statistics.tickets_per_week) {
|
||||
data.datasets[0].data.push(this.statistics.tickets_per_week[week]);
|
||||
} else {
|
||||
data.datasets[0].data.push(0);
|
||||
}
|
||||
data.datasets[0].backgroundColor.push("#607d8b");
|
||||
})
|
||||
return data
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open: function (ticket: TicketResponse) {
|
||||
if (ticket.id === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: "Ticket",
|
||||
params: {type: '-', id: ticket.id.toString()}
|
||||
});
|
||||
},
|
||||
clickUser: function (evt, elem) {
|
||||
let owner = this.open_tickets_per_user.labels[elem[0]._index];
|
||||
let query = 'status == \'open\' AND owner == \'' + owner + '\'';
|
||||
|
||||
if (owner == 'unassigned') {
|
||||
query = 'status == \'open\' AND !owner';
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: "TicketList",
|
||||
params: {query: query}
|
||||
});
|
||||
},
|
||||
clickPie: function (evt, elem) {
|
||||
this.$router.push({
|
||||
name: "TicketList",
|
||||
params: {type: this.tickets_per_type.labels[elem[0]._index]}
|
||||
});
|
||||
},
|
||||
color: function (s: string): string {
|
||||
let pos = createHash('md5').update(s).digest().readUInt32BE(0) % colors.length;
|
||||
return colors[pos];
|
||||
},
|
||||
fillData() {
|
||||
API.getStatistics().then(response => {
|
||||
this.statistics = response.data;
|
||||
});
|
||||
},
|
||||
weeks: function () {
|
||||
let w = [] as Array<string>;
|
||||
for (let i = 0; i < 53; i++) {
|
||||
w.push(DateTime.utc().minus({ weeks: i }).toFormat("kkkk-WW"))
|
||||
}
|
||||
this.lodash.reverse(w);
|
||||
return w
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fillData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
canvas {
|
||||
position: relative !important;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
217
ui/src/views/Graph.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div class="fill-height">
|
||||
<v-card
|
||||
v-if="selected !== undefined"
|
||||
class="mt-3 ml-3 px-0"
|
||||
style="position: absolute; width: 33%; left: 60px; top: 60px; z-index: 5">
|
||||
<v-card-title>
|
||||
{{ selected.name }}
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
text
|
||||
:to="{ name: 'Graph', params: { col: col(selected.id), 'id': id(selected.id) } }"
|
||||
>
|
||||
<v-icon>mdi-bullseye</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
vv-if="selected.id.startsWith('artifacts/')"
|
||||
text
|
||||
@click="to(selected.id)"
|
||||
>
|
||||
<v-icon>mdi-open-in-new</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text class="ma-0 pa-0">
|
||||
<!--TicketSnippet v-if="selected.id.startsWith('tickets/')"></TicketSnippet-->
|
||||
<!--ArtifactSnippet v-if="selected.id.startsWith('artifacts/')"></ArtifactSnippet-->
|
||||
<IDSnippet :id="selected.id"></IDSnippet>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-main class="fill-height overflow-hidden">
|
||||
<div class="d-flex flex-column fill-height overflow-hidden">
|
||||
<v-row class="flex-grow-0 pb-4">
|
||||
<v-col cols="4" class="pl-8">
|
||||
<v-slider
|
||||
class="mt-4 mb-4"
|
||||
v-model="depth"
|
||||
dense
|
||||
:label="'Depth ' + depth"
|
||||
hide-details
|
||||
max="10"
|
||||
min="0"
|
||||
></v-slider>
|
||||
</v-col>
|
||||
<v-col cols="4" class="pl-4">
|
||||
<v-slider
|
||||
class="mt-4 mb-4"
|
||||
v-model="force"
|
||||
dense
|
||||
label="Node Distance"
|
||||
hide-details
|
||||
max="10000"
|
||||
min="0"
|
||||
></v-slider>
|
||||
</v-col>
|
||||
<v-col cols="2">
|
||||
<v-switch label="Hide Labels"
|
||||
v-model="hidelabel" class="mt-6 mb-4" hide-details>
|
||||
</v-switch>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row class="flex-grow-1 mt-0">
|
||||
<d3-network
|
||||
v-if="g !== undefined && g.links !== undefined"
|
||||
:net-nodes="nodes"
|
||||
:net-links="g.links"
|
||||
:options="options"
|
||||
@node-click="nodeclick"
|
||||
class="pt-0 mt-n4"
|
||||
style="width: 100%; height: 100%"
|
||||
/>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import D3Network from "vue-d3-network";
|
||||
import {API} from "../services/api";
|
||||
import {Graph, Node} from "../client";
|
||||
// import TicketSnippet from "../components/snippets/TicketSnippet.vue";
|
||||
// import ArtifactSnippet from "../components/snippets/ArtifactSnippet.vue";
|
||||
import IDSnippet from "../components/snippets/IDSnippet.vue";
|
||||
|
||||
interface State {
|
||||
g?: Graph;
|
||||
force: number;
|
||||
depth: number;
|
||||
hidelabel: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
selected?: any;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Graph",
|
||||
components: {
|
||||
IDSnippet,
|
||||
D3Network
|
||||
},
|
||||
data: (): State => ({
|
||||
g: undefined,
|
||||
force: 3000,
|
||||
depth: 2,
|
||||
hidelabel: false,
|
||||
selected: undefined,
|
||||
}),
|
||||
computed: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
options: function (): any {
|
||||
return {
|
||||
canvas: false,
|
||||
nodeLabels: !this.hidelabel,
|
||||
nodeSize: 20,
|
||||
linkWidth: 2,
|
||||
fontSize: 16,
|
||||
force: this.force
|
||||
}
|
||||
},
|
||||
nodes: function (): Array<any> {
|
||||
if (this.g === undefined || this.g.nodes === undefined) {
|
||||
return []
|
||||
}
|
||||
return this.lodash.map(this.g.nodes, (node: Node) => {
|
||||
if (node.id === this.$route.params.col + "/" + this.$route.params.id) {
|
||||
return {id: node.id, name: node.name, _size: 40, _cssClass: "center", _labelClass: "center"}
|
||||
}
|
||||
if (node.id.startsWith("tickets/")) {
|
||||
return {id: node.id, name: node.name, _size: 30, _cssClass: "ticket", _labelClass: "event"}
|
||||
}
|
||||
return {id: node.id, name: node.name}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
depth: function () {
|
||||
this.fetchGraph();
|
||||
},
|
||||
$route: function () {
|
||||
this.fetchGraph();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
col: function (id: string): string {
|
||||
let parts = id.split("/");
|
||||
return parts[0];
|
||||
},
|
||||
id: function (id: string): string {
|
||||
let parts = id.split("/");
|
||||
return parts[1];
|
||||
},
|
||||
to: function (fid: string) {
|
||||
let col = this.col(fid);
|
||||
let id = this.id(fid);
|
||||
|
||||
if (col === 'tickets') {
|
||||
this.$router.push({
|
||||
name: "Ticket",
|
||||
params: { id: id, type: "-" }
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: "Artifact",
|
||||
params: { artifact: id }
|
||||
});
|
||||
},
|
||||
fetchGraph: function(): void {
|
||||
API.graph(this.$route.params.col, this.$route.params.id, this.depth).then((response) => {
|
||||
this.g = response.data;
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
nodeclick(e: any, node: any) {
|
||||
this.selected = node;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchGraph();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.node,
|
||||
.node.selected {
|
||||
stroke: #388E3C !important;
|
||||
}
|
||||
.node.event {
|
||||
stroke: #D32F2F !important;
|
||||
}
|
||||
.node.center {
|
||||
stroke: #FFEB3B !important;
|
||||
fill: #FFEB3B !important;
|
||||
}
|
||||
|
||||
.theme--dark .node-label,
|
||||
.theme--dark .node-label.event {
|
||||
fill: #ffffff !important;
|
||||
}
|
||||
|
||||
.node-label,
|
||||
.node-label.event {
|
||||
fill: #000000 !important;
|
||||
}
|
||||
|
||||
.link {
|
||||
stroke: #424242 !important;
|
||||
}
|
||||
.link.selected,
|
||||
.link:hover,.node:hover{
|
||||
stroke: #FFEB3B !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
13
ui/src/views/Group.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Group"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
62
ui/src/views/GroupList.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<v-main style="min-height: 100vh;">
|
||||
<List
|
||||
:items="groups"
|
||||
routername="Group"
|
||||
itemid="id"
|
||||
itemname="name"
|
||||
singular="Group"
|
||||
plural="Groups"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {Group} from "../client";
|
||||
import {API} from "../services/api";
|
||||
import List from "../components/List.vue";
|
||||
|
||||
interface State {
|
||||
groups: Array<Group>;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "GroupList",
|
||||
components: {List},
|
||||
data: (): State => ({
|
||||
groups: [],
|
||||
}),
|
||||
methods: {
|
||||
loadGroups() {
|
||||
API.listGroups().then((response) => {
|
||||
this.groups = response.data;
|
||||
});
|
||||
},
|
||||
deleteGroup(name: string) {
|
||||
// API.deleteU(name).then(() => {
|
||||
// this.loadAutomations();
|
||||
// });
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadGroups();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "groups/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.loadGroups()
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
186
ui/src/views/Job.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="$route.params.id == 'new'" class="fill-height d-flex flex-column pa-8">
|
||||
<v-alert v-if="readonly" type="info">
|
||||
You do not have write access to jobs.
|
||||
</v-alert>
|
||||
<h2>Start new job</h2>
|
||||
|
||||
<v-select
|
||||
label="Automations"
|
||||
:items="globalautomations"
|
||||
item-text="id"
|
||||
return-object
|
||||
v-model="automation"
|
||||
></v-select>
|
||||
|
||||
<v-form v-if="automation" v-model="valid">
|
||||
<v-jsf
|
||||
v-model="data"
|
||||
:schema="JSON.parse(automation.schema)"
|
||||
:options="{ readonly: true, formats: { time: timeformat, date: dateformat, 'date-time': datetimeformat } }"
|
||||
/>
|
||||
<v-btn @click="run" color="success" outlined :disabled="!valid">
|
||||
Run
|
||||
</v-btn>
|
||||
</v-form>
|
||||
</div>
|
||||
<div v-else-if="job !== undefined">
|
||||
<h2>Job: {{ job.id }}</h2>
|
||||
|
||||
<div v-if="job.automation" class="flex-grow-0 flex-shrink-0">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Automation</v-subheader>
|
||||
{{ job.automation }}
|
||||
</div>
|
||||
|
||||
<div v-if="job.container" class="flex-grow-0 flex-shrink-0">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Container</v-subheader>
|
||||
{{ job.container }}
|
||||
</div>
|
||||
|
||||
<div v-if="job.status" class="flex-grow-0 flex-shrink-0">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Status</v-subheader>
|
||||
{{ job.status }}
|
||||
</div>
|
||||
|
||||
<div v-if="job.payload" class="flex-grow-0 flex-shrink-0">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Input Payload</v-subheader>
|
||||
<Editor :value="JSON.stringify(job.payload, null, 2)" lang="json" :readonly="true"></Editor>
|
||||
</div>
|
||||
|
||||
<div v-if="job.log" class="flex-grow-0 flex-shrink-0">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Log</v-subheader>
|
||||
<Editor :value="job.log" lang="log" :readonly="true"></Editor>
|
||||
</div>
|
||||
|
||||
<div v-if="job.output" class="flex-grow-0 flex-shrink-0">
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">Output</v-subheader>
|
||||
<Editor :value="JSON.stringify(job.output, null, 2)" lang="json" :readonly="true"></Editor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {AutomationResponse, AutomationResponseTypeEnum, JobResponse} from "@/client";
|
||||
import {API} from "@/services/api";
|
||||
import {DateTime} from "luxon";
|
||||
import Editor from "@/components/Editor.vue";
|
||||
|
||||
interface State {
|
||||
job?: JobResponse,
|
||||
data?: any;
|
||||
valid: boolean;
|
||||
|
||||
automation?: AutomationResponse;
|
||||
automations: Array<AutomationResponse>;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Job",
|
||||
components: { Editor },
|
||||
data: (): State => ({
|
||||
job: undefined,
|
||||
data: undefined,
|
||||
valid: true,
|
||||
|
||||
automation: undefined,
|
||||
automations: [],
|
||||
}),
|
||||
watch: {
|
||||
$route: 'loadJob',
|
||||
},
|
||||
computed: {
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("admin:job:write");
|
||||
},
|
||||
globalautomations: function (): Array<AutomationResponse> {
|
||||
if (!this.automations) {
|
||||
return [];
|
||||
}
|
||||
return this.lodash.filter(this.automations, (automation: AutomationResponse) => {
|
||||
if (!automation || !automation.type) {
|
||||
return true;
|
||||
}
|
||||
return this.lodash.includes(automation.type, AutomationResponseTypeEnum.Global)
|
||||
})
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
timeformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
dateformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
datetimeformat: function(s: string, locale: string) {
|
||||
let format = this.$store.state.settings.timeformat;
|
||||
if (!format) {
|
||||
return DateTime.fromISO(s).toLocaleString(DateTime.DATETIME_SHORT);
|
||||
}
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
run: function () {
|
||||
if (!this.automation) {
|
||||
return;
|
||||
}
|
||||
API.runJob({ automation: this.automation.id, payload: this.data }).then(() => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Job started." });
|
||||
})
|
||||
},
|
||||
loadJob() {
|
||||
if (!this.$route.params.id) {
|
||||
return
|
||||
}
|
||||
if (this.$route.params.id == 'new') {
|
||||
// this.template = { name: "MyTemplate", schema: '{ "type": "object", "name": "Incident" }' }
|
||||
// this.schema = { type: "object", name: "Incident" }
|
||||
} else {
|
||||
API.getJob(this.$route.params.id).then((response) => {
|
||||
this.job = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
loadAutomations() {
|
||||
API.listAutomations(this.$route.params.id).then((response) => {
|
||||
this.automations = response.data;
|
||||
});
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadJob();
|
||||
this.loadAutomations();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "jobs/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.loadJob()
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
61
ui/src/views/JobList.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<v-main style="min-height: 100vh;">
|
||||
<List
|
||||
:items="jobs"
|
||||
routername="Job"
|
||||
itemid="id"
|
||||
itemname="id"
|
||||
singular="Job"
|
||||
plural="Jobs"
|
||||
writepermission="admin:job:write"
|
||||
:deletable="false"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {JobResponse} from "@/client";
|
||||
import {API} from "@/services/api";
|
||||
import List from "../components/List.vue";
|
||||
|
||||
interface State {
|
||||
jobs: Array<JobResponse>;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "JobList",
|
||||
components: {List},
|
||||
data: (): State => ({
|
||||
jobs: [],
|
||||
}),
|
||||
methods: {
|
||||
loadJobs() {
|
||||
API.listJobs().then((response) => {
|
||||
if (response.data) {
|
||||
this.jobs = response.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadJobs();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "jobs/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.loadJobs()
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
311
ui/src/views/Playbook.vue
Normal file
@@ -0,0 +1,311 @@
|
||||
<template>
|
||||
<div v-if="playbook !== undefined" class="fill-height d-flex flex-column pa-8">
|
||||
<v-alert v-if="readonly" type="info">You do not have write access to playbooks.</v-alert>
|
||||
<h2 v-if="this.$route.params.id === 'new'">New Playbook</h2>
|
||||
<h2 v-else>Edit Playbook: {{ playbook.name }}</h2>
|
||||
|
||||
<v-alert v-if="formaterrors.length" color="warning">
|
||||
<div v-for="(formaterror, index) in formaterrors" :key="index">
|
||||
{{ formaterror.instancePath }}{{ formaterror.instancePath ? ": " : "" }}{{ formaterror.message }}
|
||||
</div>
|
||||
</v-alert>
|
||||
<v-alert v-else-if="error" color="warning">
|
||||
{{ error }}
|
||||
</v-alert>
|
||||
<div v-else class="px-4 overflow-scroll">
|
||||
<vue-pipeline
|
||||
v-if="pipelineData"
|
||||
ref="pipeline"
|
||||
:x="50"
|
||||
:y="55"
|
||||
:data="pipelineData"
|
||||
:showArrow="true"
|
||||
:ystep="70"
|
||||
:xstep="100"
|
||||
lineStyle="default"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
|
||||
Playbook
|
||||
</v-subheader>
|
||||
<div class="flex-grow-1 flex-shrink-1 overflow-scroll">
|
||||
<Editor v-model="playbook.yaml" @input="updatePipeline" lang="yaml" :readonly="readonly"></Editor>
|
||||
</div>
|
||||
|
||||
<v-row v-if="!readonly" class="px-3 my-6 flex-grow-0 flex-shrink-0">
|
||||
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
|
||||
<v-icon>mdi-plus-thick</v-icon>
|
||||
Create
|
||||
</v-btn>
|
||||
<v-btn v-else color="success" @click="save" outlined>
|
||||
<v-icon>mdi-content-save</v-icon>
|
||||
Save
|
||||
</v-btn>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {Playbook, PlaybookTemplate, Task, TaskResponse} from "../client";
|
||||
import { API } from "@/services/api";
|
||||
import Editor from "../components/Editor.vue";
|
||||
import {alg, Graph} from "graphlib";
|
||||
import yaml from 'yaml';
|
||||
import Ajv from "ajv";
|
||||
|
||||
const playbookSchema = {
|
||||
type: "object",
|
||||
required: ["name", "tasks"],
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
tasks: {
|
||||
type: "object",
|
||||
additionalProperties: { $ref: "#/definitions/Task" }
|
||||
}
|
||||
},
|
||||
// additionalProperties: false,
|
||||
$id: "#/definitions/Playbook"
|
||||
};
|
||||
|
||||
const taskSchema = {
|
||||
type: "object",
|
||||
required: ["name", "type"],
|
||||
properties: {
|
||||
automation: { type: "string" },
|
||||
join: { type: "boolean" },
|
||||
msg: { type: "object", additionalProperties: { type: "string" } },
|
||||
name: { type: "string" },
|
||||
next: {
|
||||
type: "object",
|
||||
additionalProperties: { type: ["string", "null"] }
|
||||
},
|
||||
schema: { type: "object" },
|
||||
type: { type: "string", enum: ["task", "input", "automation"] }
|
||||
},
|
||||
// additionalProperties: false,
|
||||
$id: "#/definitions/Task"
|
||||
};
|
||||
|
||||
interface State {
|
||||
playbook?: PlaybookTemplate;
|
||||
g: Record<string, any>;
|
||||
selected: any;
|
||||
pipelineData: any;
|
||||
error: string;
|
||||
}
|
||||
|
||||
interface TaskWithID {
|
||||
id: string;
|
||||
task: Task;
|
||||
}
|
||||
|
||||
const inityaml = "name: VirusTotal hash check\n" +
|
||||
"tasks:\n" +
|
||||
" input:\n" +
|
||||
" name: Please enter a word\n" +
|
||||
" type: input\n" +
|
||||
" schema:\n" +
|
||||
" title: Word\n" +
|
||||
" type: object\n" +
|
||||
" properties:\n" +
|
||||
" word:\n" +
|
||||
" type: string\n" +
|
||||
" title: Enter a Word\n" +
|
||||
" default: \"\"\n" +
|
||||
" next:\n" +
|
||||
" hash: \"word != ''\"\n" +
|
||||
"\n" +
|
||||
" hash:\n" +
|
||||
" name: Hash the word\n" +
|
||||
" type: automation\n" +
|
||||
" automation: hash.sha1\n" +
|
||||
" msg:\n" +
|
||||
" payload: \"playbook.tasks['input'].data['word']\"\n" +
|
||||
" next:\n" +
|
||||
" end:\n" +
|
||||
"\n" +
|
||||
" end:\n" +
|
||||
" name: Finish the incident\n" +
|
||||
" type: task\n"
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Playbook",
|
||||
components: { Editor },
|
||||
data: (): State => ({
|
||||
playbook: undefined,
|
||||
g: {},
|
||||
selected: undefined,
|
||||
pipelineData: undefined,
|
||||
error: "",
|
||||
}),
|
||||
watch: {
|
||||
'$route': function () {
|
||||
this.loadPlaybook();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formaterrors: function (): Array<any> {
|
||||
if (!this.playbook) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
let playbook = yaml.parse(this.playbook.yaml);
|
||||
const ajv = new Ajv({validateFormats: false});
|
||||
ajv.addSchema(taskSchema, "#/definitions/Task")
|
||||
const validate = ajv.compile(playbookSchema);
|
||||
const valid = validate(playbook)
|
||||
if (!valid && validate.errors) {
|
||||
return validate.errors;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
catch (e) {
|
||||
return [e];
|
||||
}
|
||||
},
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("engineer:playbook:write");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
gstatus: function(task: TaskResponse) {
|
||||
if (task.active) {
|
||||
return "open"
|
||||
}
|
||||
return "inactive"
|
||||
},
|
||||
tasks: function(g: any, playbook: Playbook): Array<TaskWithID> {
|
||||
let taskKeys = alg.topsort(g);
|
||||
let tasks = [] as Array<TaskWithID>;
|
||||
for (const tasksKey in taskKeys) {
|
||||
let taskWithID = {} as TaskWithID;
|
||||
if (playbook.tasks[taskKeys[tasksKey]] === undefined) {
|
||||
continue; // TODO
|
||||
}
|
||||
taskWithID.task = playbook.tasks[taskKeys[tasksKey]];
|
||||
taskWithID.id = taskKeys[tasksKey];
|
||||
tasks.push(taskWithID);
|
||||
}
|
||||
return tasks;
|
||||
},
|
||||
updatePipeline: function () {
|
||||
if (this.playbook) {
|
||||
this.pipeline(this.playbook.yaml);
|
||||
}
|
||||
},
|
||||
pipeline: function(playbookYAML: string) {
|
||||
try {
|
||||
let playbook = yaml.parse(playbookYAML);
|
||||
|
||||
this.error = "";
|
||||
|
||||
let g = new Graph();
|
||||
|
||||
for (const stepKey in playbook.tasks) {
|
||||
g.setNode(stepKey);
|
||||
}
|
||||
|
||||
this.lodash.forEach(playbook.tasks, (task: Task, stepKey: string) => {
|
||||
if ("next" in task) {
|
||||
this.lodash.forEach(task.next, (condition, nextKey) => {
|
||||
g.setEdge(stepKey, nextKey);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let tasks = this.tasks(g, playbook);
|
||||
let elements = [] as Array<any>;
|
||||
this.lodash.forEach(tasks, task => {
|
||||
elements.push({
|
||||
id: task.id,
|
||||
name: task.task.name,
|
||||
next: [],
|
||||
status: "unknown"
|
||||
});
|
||||
});
|
||||
|
||||
this.lodash.forEach(tasks, (task: TaskWithID) => {
|
||||
if ("next" in task.task) {
|
||||
this.lodash.forEach(task.task.next, (condition, nextKey) => {
|
||||
let nextID = this.lodash.findIndex(elements, ["id", nextKey]);
|
||||
let stepID = this.lodash.findIndex(elements, ["id", task.id]);
|
||||
if (nextID !== -1) {
|
||||
// TODO: invalid schema
|
||||
elements[stepID].next.push({index: nextID});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.pipelineData = undefined;
|
||||
this.$nextTick(() => {
|
||||
this.pipelineData = this.lodash.values(elements);
|
||||
})
|
||||
}
|
||||
catch (e: unknown) {
|
||||
console.log(e);
|
||||
this.error = this.lodash.toString(e);
|
||||
}
|
||||
},
|
||||
save() {
|
||||
if (this.playbook === undefined) {
|
||||
return;
|
||||
}
|
||||
if (this.$route.params.id == 'new') {
|
||||
let playbook = this.playbook;
|
||||
// playbook.id = kebabCase(playbook.name);
|
||||
API.createPlaybook(playbook).then(() => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Playbook created" });
|
||||
});
|
||||
} else {
|
||||
API.updatePlaybook(this.$route.params.id, this.playbook).then(() => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Playbook saved" });
|
||||
});
|
||||
}
|
||||
},
|
||||
loadPlaybook() {
|
||||
if (!this.$route.params.id) {
|
||||
return
|
||||
}
|
||||
if (this.$route.params.id == 'new') {
|
||||
this.playbook = { name: "MyPlaybook", yaml: inityaml }
|
||||
} else {
|
||||
API.getPlaybook(this.$route.params.id).then((response) => {
|
||||
this.playbook = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadPlaybook();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.my-code {
|
||||
background: #2d2d2d;
|
||||
color: #ccc;
|
||||
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
|
||||
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.pipeline-node-label {
|
||||
fill: #333 !important;
|
||||
}
|
||||
</style>
|
||||
66
ui/src/views/PlaybookList.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<v-main style="min-height: 100vh;">
|
||||
<List
|
||||
:items="playbooks"
|
||||
routername="Playbook"
|
||||
itemid="id"
|
||||
itemname="name"
|
||||
singular="Playbook"
|
||||
plural="Playbooks"
|
||||
@delete="deletePlaybook"
|
||||
writepermission="engineer:playbook:write"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {PlaybookTemplate} from "../client";
|
||||
import {API} from "../services/api";
|
||||
import List from "../components/List.vue";
|
||||
|
||||
interface State {
|
||||
playbooks: Array<PlaybookTemplate>;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "PlaybookList",
|
||||
components: {List},
|
||||
data: (): State => ({
|
||||
playbooks: [],
|
||||
}),
|
||||
methods: {
|
||||
loadPlaybooks() {
|
||||
API.listPlaybooks().then((response) => {
|
||||
if (response.data) {
|
||||
this.playbooks = response.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
deletePlaybook(name: string) {
|
||||
API.deletePlaybook(name).then(() => {
|
||||
this.loadPlaybooks();
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadPlaybooks();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "playbooks/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.loadPlaybooks()
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
47
ui/src/views/Profile.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<v-main v-if="userdata">
|
||||
<user-data-editor :userdata="userdata" @save="saveUserData"></user-data-editor>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { UserData } from "@/client";
|
||||
import { API } from "@/services/api";
|
||||
import UserDataEditor from "@/components/UserDataEditor.vue";
|
||||
|
||||
interface State {
|
||||
userdata?: UserData;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Profile",
|
||||
data: (): State => ({
|
||||
userdata: undefined,
|
||||
}),
|
||||
components: {
|
||||
UserDataEditor,
|
||||
},
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.loadUserData();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
saveUserData: function(userdata: UserData) {
|
||||
API.updateCurrentUserData(userdata).then(() => {
|
||||
this.$store.dispatch("alertSuccess", { name: "User data saved" });
|
||||
});
|
||||
},
|
||||
loadUserData: function () {
|
||||
API.currentUserData().then((response) => {
|
||||
this.userdata = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadUserData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
89
ui/src/views/Rule.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div v-if="rule !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
|
||||
<h2 v-if="this.$route.params.id === 'new'">New Rule: {{ rule.name }}</h2>
|
||||
<h2 v-else>Edit Rule: {{ rule.name }}</h2>
|
||||
|
||||
<v-text-field label="Name" v-model="rule.name" class="flex-grow-0 flex-shrink-0"></v-text-field>
|
||||
<v-text-field label="Condition" v-model="rule.condition" class="flex-grow-0 flex-shrink-0"></v-text-field>
|
||||
|
||||
<v-subheader class="pl-0 py-0" style="height: 20px; font-size: 12px">
|
||||
Update
|
||||
</v-subheader>
|
||||
<div class="flex-grow-1 flex-shrink-1 overflow-scroll">
|
||||
<Editor v-model="update" lang="json"></Editor>
|
||||
</div>
|
||||
|
||||
<v-row class="px-3 my-6 flex-grow-0 flex-shrink-0">
|
||||
<v-btn v-if="this.$route.params.id === 'new'" color="success" @click="save" outlined>
|
||||
<v-icon>mdi-plus-thick</v-icon>
|
||||
Create
|
||||
</v-btn>
|
||||
<v-btn v-else color="success" outlined @click="save">
|
||||
<v-icon>mdi-content-save</v-icon>
|
||||
Save
|
||||
</v-btn>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import { Rule } from "@/client";
|
||||
import { API } from "@/services/api";
|
||||
import Editor from "../components/Editor.vue";
|
||||
|
||||
interface State {
|
||||
rule?: Rule;
|
||||
update: string;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Rule",
|
||||
components: { Editor },
|
||||
data: (): State => ({
|
||||
rule: undefined,
|
||||
update: "",
|
||||
}),
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.loadRule();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
if (this.rule === undefined) {
|
||||
return;
|
||||
}
|
||||
let rule = this.rule;
|
||||
// rule.id = kebabCase(rule.name);
|
||||
rule.update = JSON.parse(this.update);
|
||||
if (this.$route.params.id == 'new') {
|
||||
API.createRule(rule).then(() => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Rule created" });
|
||||
});
|
||||
} else {
|
||||
API.updateRule(this.$route.params.id, rule).then(() => {
|
||||
this.$store.dispatch("alertSuccess", { name: "Rule saved" });
|
||||
});
|
||||
}
|
||||
},
|
||||
loadRule() {
|
||||
if (!this.$route.params.id) {
|
||||
return
|
||||
}
|
||||
if (this.$route.params.id == 'new') {
|
||||
this.rule = { name: "MyPlaybook", condition: "type == alert", update: { details: { status: "ignored" } } }
|
||||
} else {
|
||||
API.getRule(this.$route.params.id).then((response) => {
|
||||
this.rule = response.data;
|
||||
this.update = JSON.stringify(response.data.update, null, 4)
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadRule();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
63
ui/src/views/RuleList.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<v-main style="min-height: 100vh;">
|
||||
<List
|
||||
:items="rules"
|
||||
routername="Rule"
|
||||
itemid="id"
|
||||
itemname="name"
|
||||
singular="Rule"
|
||||
plural="Rules"
|
||||
@delete="deleteRule"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import {Rule} from "@/client";
|
||||
import {API} from "@/services/api";
|
||||
import List from "../components/List.vue";
|
||||
|
||||
interface State {
|
||||
rules: Array<Rule>;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "RuleList",
|
||||
components: {List},
|
||||
data: (): State => ({
|
||||
rules: [],
|
||||
}),
|
||||
methods: {
|
||||
loadRules() {
|
||||
API.listRules().then((response) => {
|
||||
this.rules = response.data;
|
||||
});
|
||||
},
|
||||
deleteRule(name: string) {
|
||||
API.deleteRule(name).then(() => {
|
||||
this.loadRules();
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadRules();
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "rules/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.loadRules()
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
85
ui/src/views/TaskList.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<v-main>
|
||||
<v-container>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="tasks ? tasks : []"
|
||||
item-key="name"
|
||||
multi-sort
|
||||
class="elevation-1 cards clickable"
|
||||
:loading="loading"
|
||||
:footer-props="{ 'items-per-page-options': [10, 25, 50, 100] }"
|
||||
@click:row="open"
|
||||
>
|
||||
</v-data-table>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {TaskResponse, TaskWithContext} from "@/client";
|
||||
import {API} from "@/services/api";
|
||||
|
||||
interface State {
|
||||
tasks: Array<TaskResponse>;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "TaskList",
|
||||
data: (): State => ({
|
||||
tasks: [],
|
||||
loading: true,
|
||||
}),
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.loadTasks();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
headers() {
|
||||
return [
|
||||
{
|
||||
text: "Ticket",
|
||||
align: "start",
|
||||
value: "ticket_name"
|
||||
},
|
||||
{
|
||||
text: "Playbook",
|
||||
align: "start",
|
||||
value: "playbook_name"
|
||||
},
|
||||
{
|
||||
text: "Task",
|
||||
align: "start",
|
||||
value: "task.name"
|
||||
},
|
||||
{
|
||||
text: "Owner",
|
||||
align: "start",
|
||||
value: "task.owner"
|
||||
}
|
||||
];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(task: TaskWithContext) {
|
||||
this.$router.push({
|
||||
name: "Ticket",
|
||||
params: { id: task.ticket_id.toString(), type: "-" }
|
||||
});
|
||||
},
|
||||
loadTasks() {
|
||||
this.loading = true;
|
||||
API.listTasks().then((reponse) => {
|
||||
this.tasks = reponse.data;
|
||||
this.loading = false;
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadTasks();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
87
ui/src/views/Template.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div v-if="template !== undefined" class="flex-grow-1 flex-column d-flex fill-height pa-8">
|
||||
<v-alert v-if="readonly" type="info">
|
||||
You do not have write access to templates.
|
||||
Changes here cannot be saved.
|
||||
</v-alert>
|
||||
<div class="d-flex" style="align-items: center">
|
||||
<h2 v-if="readonly">Template: {{ template.name }}</h2>
|
||||
<h2 v-else-if="this.$route.params.id === 'new'">New Template: {{ template.name }}</h2>
|
||||
<h2 v-else>Edit Template: {{ template.name }}</h2>
|
||||
</div>
|
||||
|
||||
<v-text-field label="Name" v-model="template.name" class="flex-grow-0 flex-shrink-0" :readonly="readonly"></v-text-field>
|
||||
|
||||
<AdvancedJSONSchemaEditor v-if="schema" @save="save" :schema="schema" :readonly="readonly"></AdvancedJSONSchemaEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import { TicketTemplate } from "@/client";
|
||||
import AdvancedJSONSchemaEditor from "../components/AdvancedJSONSchemaEditor.vue";
|
||||
|
||||
interface State {
|
||||
template?: TicketTemplate,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
schema?: any;
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: "Template",
|
||||
components: { AdvancedJSONSchemaEditor },
|
||||
data: (): State => ({
|
||||
template: undefined,
|
||||
schema: undefined,
|
||||
}),
|
||||
watch: {
|
||||
$route: 'loadTemplate',
|
||||
},
|
||||
computed: {
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("engineer:template:write");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
save(schema) {
|
||||
if (this.template === undefined) {
|
||||
return;
|
||||
}
|
||||
let template = this.template;
|
||||
template.schema = schema;
|
||||
|
||||
if (this.$route.params.id == 'new') {
|
||||
this.$store.dispatch("addTemplate", template).then(() => {
|
||||
this.$router.push({name: "TemplateList" });
|
||||
});
|
||||
} else {
|
||||
this.$store.dispatch("updateTemplate", { id: this.$route.params.id, template: template });
|
||||
}
|
||||
},
|
||||
loadTemplate() {
|
||||
if (!this.$route.params.id) {
|
||||
return
|
||||
}
|
||||
if (this.$route.params.id == 'new') {
|
||||
this.template = { name: "MyTemplate", schema: '{ "type": "object", "name": "Incident" }' }
|
||||
this.schema = { type: "object", name: "Incident" }
|
||||
} else {
|
||||
this.$store.dispatch("getTemplate", this.$route.params.id).then((response: TicketTemplate) => {
|
||||
this.template = response;
|
||||
this.schema = JSON.parse(response.schema);
|
||||
});
|
||||
}
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadTemplate();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
50
ui/src/views/TemplateList.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<v-main style="min-height: 100vh;">
|
||||
<List
|
||||
:items="$store.state.templates.templates"
|
||||
routername="Template"
|
||||
itemid="id"
|
||||
itemname="name"
|
||||
singular="Template"
|
||||
plural="Templates"
|
||||
writepermission="engineer:template:write"
|
||||
@delete="deleteTemplate"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
import List from "../components/List.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "TemplateList",
|
||||
components: {List},
|
||||
methods: {
|
||||
deleteTemplate(title: string) {
|
||||
this.$store.dispatch("deleteTemplate", title).then(() => {
|
||||
this.$router.push({name: "TemplateList"});
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch("listTemplates");
|
||||
|
||||
this.$store.subscribeAction((action, state) => {
|
||||
if (!action.payload || !(this.lodash.has(action.payload, "ids")) || !action.payload["ids"]) {
|
||||
return
|
||||
}
|
||||
let reload = false;
|
||||
Vue.lodash.forEach(action.payload["ids"], (id) => {
|
||||
if (this.lodash.startsWith(id, "templates/")) {
|
||||
reload = true;
|
||||
}
|
||||
});
|
||||
if (reload) {
|
||||
this.$store.dispatch("listTemplates");
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
</script>
|
||||
1626
ui/src/views/Ticket.vue
Normal file
30
ui/src/views/TicketList.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<v-main>
|
||||
<TicketListComponent :type="this.$route.params.type" :query="query" @click="open"></TicketListComponent>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import {TicketResponse} from "@/client";
|
||||
|
||||
import TicketListComponent from "../components/TicketList.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
name: "TicketList",
|
||||
components: {TicketListComponent},
|
||||
props: ['query'],
|
||||
methods: {
|
||||
open: function (ticket: TicketResponse) {
|
||||
if (ticket.id === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: "Ticket",
|
||||
params: {type: this.$route.params.type, id: ticket.id.toString()}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||