Compare commits
	
		
			2 Commits
		
	
	
		
			master
			...
			build-with
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ad88757058 | |||
| 93f0e00b8d | 
| @@ -1,4 +1,4 @@ | ||||
| FROM harbor.k-space.ee/docker.io/library/node AS dev | ||||
| FROM node AS dev | ||||
|  | ||||
| WORKDIR /app | ||||
| EXPOSE 8080 | ||||
|   | ||||
| @@ -1,37 +1,39 @@ | ||||
| --- | ||||
| apiVersion: networking.k8s.io/v1 | ||||
| kind: Ingress | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
|   name: playground | ||||
|   annotations: | ||||
|     kubernetes.io/ingress.class: erkiaas-yeaa8 | ||||
|     kubernetes.io/ingress.class: traefik | ||||
|     cert-manager.io/cluster-issuer: default | ||||
|     traefik.ingress.kubernetes.io/router.entrypoints: websecure | ||||
|     traefik.ingress.kubernetes.io/router.middlewares: traefik-sso@kubernetescrd | ||||
|     traefik.ingress.kubernetes.io/router.tls: "true" | ||||
|     external-dns.alpha.kubernetes.io/target: traefik-yeaa8.codemowers.ee | ||||
|     external-dns.alpha.kubernetes.io/target: traefik.k-space.ee | ||||
| spec: | ||||
|   rules: | ||||
|     - host: logs-yeaa8.codemowers.ee | ||||
|       http: | ||||
|         paths: | ||||
|           - pathType: Prefix | ||||
|             path: "/" | ||||
|             backend: | ||||
|               service: | ||||
|                 name: logmower-frontend | ||||
|                 port: | ||||
|                   number: 8080 | ||||
|   - host: playground.k-space.ee | ||||
|     http: | ||||
|       paths: | ||||
|       - pathType: Prefix | ||||
|         path: "/" | ||||
|         backend: | ||||
|           service: | ||||
|             name: log-viewer-frontend | ||||
|             port: | ||||
|               number: 8080 | ||||
|   tls: | ||||
|     - hosts: | ||||
|         - "*.codemowers.ee" | ||||
|   - hosts: | ||||
|     - playground.k-space.ee | ||||
|     secretName: playground-tls | ||||
| --- | ||||
| apiVersion: v1 | ||||
| kind: Service | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
|   name: log-viewer-frontend | ||||
| spec: | ||||
|   type: ClusterIP | ||||
|   selector: | ||||
|     app: logmower-frontend | ||||
|     app: log-viewer-frontend | ||||
|   ports: | ||||
|     - protocol: TCP | ||||
|       port: 8080 | ||||
| @@ -39,18 +41,18 @@ spec: | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
|   name: log-viewer-frontend | ||||
| spec: | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: logmower-frontend | ||||
|       app: log-viewer-frontend | ||||
|   template: | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: logmower-frontend | ||||
|         app: log-viewer-frontend | ||||
|     spec: | ||||
|       containers: | ||||
|         - name: logmower-frontend | ||||
|           image: harbor.codemowers.eu/eaas/logmower-frontend | ||||
|           ports: | ||||
|             - containerPort: 8080 | ||||
|       - name: log-viewer-frontend | ||||
|         image: harbor.k-space.ee/playground/log-viewer-frontend | ||||
|         ports: | ||||
|         - containerPort: 8080 | ||||
|   | ||||
							
								
								
									
										56
									
								
								k8s/staging/deployment.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								k8s/staging/deployment.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| --- | ||||
| apiVersion: networking.k8s.io/v1 | ||||
| kind: Ingress | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
|   annotations: | ||||
|     kubernetes.io/ingress.class: traefik | ||||
|     traefik.ingress.kubernetes.io/router.entrypoints: websecure | ||||
|     traefik.ingress.kubernetes.io/router.tls: "true" | ||||
|     external-dns.alpha.kubernetes.io/target: traefik-veebkolm.codemowers.ee | ||||
| spec: | ||||
|   rules: | ||||
|     - host: playground-veebkolm.codemowers.ee | ||||
|       http: | ||||
|         paths: | ||||
|           - pathType: Prefix | ||||
|             path: "/" | ||||
|             backend: | ||||
|               service: | ||||
|                 name: logmower-frontend | ||||
|                 port: | ||||
|                   number: 8080 | ||||
|   tls: | ||||
|     - hosts: | ||||
|         - "*.playground-veebkolm.codemowers.ee" | ||||
| --- | ||||
| apiVersion: v1 | ||||
| kind: Service | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
| spec: | ||||
|   type: ClusterIP | ||||
|   selector: | ||||
|     app: logmower-frontend | ||||
|   ports: | ||||
|     - protocol: TCP | ||||
|       port: 8080 | ||||
| --- | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
| spec: | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: logmower-frontend | ||||
|   template: | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: logmower-frontend | ||||
|     spec: | ||||
|       containers: | ||||
|       - name: logmower-frontend | ||||
|         image: harbor.k-space.ee/playground/log-viewer-frontend | ||||
|         ports: | ||||
|         - containerPort: 8080 | ||||
							
								
								
									
										570
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										570
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -10,28 +10,21 @@ | ||||
|       "dependencies": { | ||||
|         "@ag-grid-community/core": "^28.2.0", | ||||
|         "@mdi/font": "5.9.55", | ||||
|         "@meforma/vue-toaster": "^1.3.0", | ||||
|         "@vue/cli-service": "^5.0.8", | ||||
|         "ag-grid-vue3": "^28.2.0", | ||||
|         "ansi-to-html": "^0.7.2", | ||||
|         "core-js": "^3.25.1", | ||||
|         "event-hooks-webpack-plugin": "^2.2.0", | ||||
|         "pinia": "^2.0.21", | ||||
|         "roboto-fontface": "*", | ||||
|         "single-spa-vue": "^2.5.1", | ||||
|         "systemjs-webpack-interop": "^2.3.7", | ||||
|         "v-calendar": "next", | ||||
|         "v-viewer": "^3.0.11", | ||||
|         "vue": "^3.2.39", | ||||
|         "vue-select": "beta", | ||||
|         "vuetify": "^3.0.0-beta.0", | ||||
|         "vuex": "next", | ||||
|         "webfontloader": "^1.0.0" | ||||
|       }, | ||||
|       "devDependencies": { | ||||
|         "@vitejs/plugin-vue": "^3.0.3", | ||||
|         "vite": "^3.0.9", | ||||
|         "vite-plugin-dynamic-import": "^1.2.4", | ||||
|         "vue-cli-plugin-vuetify": "~2.5.8", | ||||
|         "webpack-plugin-vuetify": "^2.0.0-alpha.0" | ||||
|       } | ||||
| @@ -587,15 +580,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/@mdi/font/-/font-5.9.55.tgz", | ||||
|       "integrity": "sha512-jswRF6q3eq8NWpWiqct6q+6Fg/I7nUhrxYJfiEM8JJpap0wVJLQdbKtyS65GdlK7S7Ytnx3TTi/bmw+tBhkGmg==" | ||||
|     }, | ||||
|     "node_modules/@meforma/vue-toaster": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/@meforma/vue-toaster/-/vue-toaster-1.3.0.tgz", | ||||
|       "integrity": "sha512-jH0zOA/jTiT+UKHO9n5hjPTLkIfg7d66X4fnd7ssIbcXpZOoe+J8IY6Kf3nRW5iVD6/tkjeyp+tjVK8zk6zASg==", | ||||
|       "dependencies": { | ||||
|         "stylus": "~0.54.8", | ||||
|         "stylus-loader": "~3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@node-ipc/js-queue": { | ||||
|       "version": "2.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", | ||||
| @@ -649,15 +633,6 @@ | ||||
|       "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@popperjs/core": { | ||||
|       "version": "2.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.4.0.tgz", | ||||
|       "integrity": "sha512-NMrDy6EWh9TPdSRiHmHH2ye1v5U0gBD7pRYwSwJvomx7Bm4GG04vu63dYiVzebLOx2obPpJugew06xVP0Nk7hA==", | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/popperjs" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@sideway/address": { | ||||
|       "version": "4.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", | ||||
| @@ -833,11 +808,6 @@ | ||||
|       "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/@types/lodash": { | ||||
|       "version": "4.14.189", | ||||
|       "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.189.tgz", | ||||
|       "integrity": "sha512-kb9/98N6X8gyME9Cf7YaqIMvYGnBSWqEci6tiettE6iJWH1XdJz/PO8LB0GtLCG7x8dU3KWhZT+lA1a35127tA==" | ||||
|     }, | ||||
|     "node_modules/@types/mime": { | ||||
|       "version": "3.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", | ||||
| @@ -1648,20 +1618,6 @@ | ||||
|         "url": "https://github.com/chalk/ansi-styles?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ansi-to-html": { | ||||
|       "version": "0.7.2", | ||||
|       "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", | ||||
|       "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", | ||||
|       "dependencies": { | ||||
|         "entities": "^2.2.0" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "ansi-to-html": "bin/ansi-to-html" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/any-promise": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", | ||||
| @@ -1734,17 +1690,6 @@ | ||||
|         "node": ">= 4.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/atob": { | ||||
|       "version": "2.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", | ||||
|       "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", | ||||
|       "bin": { | ||||
|         "atob": "bin/atob.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 4.5.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/autoprefixer": { | ||||
|       "version": "10.4.8", | ||||
|       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.8.tgz", | ||||
| @@ -2470,17 +2415,6 @@ | ||||
|         "semver": "bin/semver" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/css": { | ||||
|       "version": "2.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", | ||||
|       "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", | ||||
|       "dependencies": { | ||||
|         "inherits": "^2.0.3", | ||||
|         "source-map": "^0.6.1", | ||||
|         "source-map-resolve": "^0.5.2", | ||||
|         "urix": "^0.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/css-declaration-sorter": { | ||||
|       "version": "6.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", | ||||
| @@ -2576,14 +2510,6 @@ | ||||
|         "url": "https://opencollective.com/webpack" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/css-parse": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", | ||||
|       "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", | ||||
|       "dependencies": { | ||||
|         "css": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/css-select": { | ||||
|       "version": "4.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", | ||||
| @@ -2731,26 +2657,6 @@ | ||||
|       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/date-fns": { | ||||
|       "version": "2.29.3", | ||||
|       "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", | ||||
|       "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", | ||||
|       "engines": { | ||||
|         "node": ">=0.11" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/date-fns" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/date-fns-tz": { | ||||
|       "version": "1.3.7", | ||||
|       "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.7.tgz", | ||||
|       "integrity": "sha512-1t1b8zyJo+UI8aR+g3iqr5fkUHWpd58VBx8J/ZSQ+w7YrGlw80Ag4sA86qkfCXRBLmMc4I2US+aPMd4uKvwj5g==", | ||||
|       "peerDependencies": { | ||||
|         "date-fns": ">=2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/debug": { | ||||
|       "version": "2.6.9", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
| @@ -2775,14 +2681,6 @@ | ||||
|         "callsite": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/decode-uri-component": { | ||||
|       "version": "0.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", | ||||
|       "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", | ||||
|       "engines": { | ||||
|         "node": ">=0.10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/deepmerge": { | ||||
|       "version": "1.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", | ||||
| @@ -3513,9 +3411,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/file-loader/node_modules/loader-utils": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|       "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|       "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "big.js": "^5.2.2", | ||||
| @@ -4528,9 +4426,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/loader-utils": { | ||||
|       "version": "1.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", | ||||
|       "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", | ||||
|       "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "big.js": "^5.2.2", | ||||
|         "emojis-list": "^3.0.0", | ||||
| @@ -4558,11 +4457,6 @@ | ||||
|       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/lodash.clonedeep": { | ||||
|       "version": "4.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", | ||||
|       "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" | ||||
|     }, | ||||
|     "node_modules/lodash.defaultsdeep": { | ||||
|       "version": "4.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", | ||||
| @@ -5165,9 +5059,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/null-loader/node_modules/loader-utils": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|       "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|       "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "big.js": "^5.2.2", | ||||
| @@ -6492,12 +6386,6 @@ | ||||
|         "node": ">=4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/resolve-url": { | ||||
|       "version": "0.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", | ||||
|       "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", | ||||
|       "deprecated": "https://github.com/lydell/resolve-url#deprecated" | ||||
|     }, | ||||
|     "node_modules/restore-cursor": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", | ||||
| @@ -6636,11 +6524,6 @@ | ||||
|       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/sax": { | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", | ||||
|       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" | ||||
|     }, | ||||
|     "node_modules/schema-utils": { | ||||
|       "version": "3.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", | ||||
| @@ -6974,19 +6857,6 @@ | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/source-map-resolve": { | ||||
|       "version": "0.5.3", | ||||
|       "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", | ||||
|       "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", | ||||
|       "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", | ||||
|       "dependencies": { | ||||
|         "atob": "^2.1.2", | ||||
|         "decode-uri-component": "^0.2.0", | ||||
|         "resolve-url": "^0.2.1", | ||||
|         "source-map-url": "^0.4.0", | ||||
|         "urix": "^0.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/source-map-support": { | ||||
|       "version": "0.5.21", | ||||
|       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", | ||||
| @@ -6997,12 +6867,6 @@ | ||||
|         "source-map": "^0.6.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/source-map-url": { | ||||
|       "version": "0.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", | ||||
|       "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", | ||||
|       "deprecated": "See https://github.com/lydell/source-map-url#deprecated" | ||||
|     }, | ||||
|     "node_modules/sourcemap-codec": { | ||||
|       "version": "1.4.8", | ||||
|       "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", | ||||
| @@ -7219,80 +7083,6 @@ | ||||
|         "postcss": "^8.2.15" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/stylus": { | ||||
|       "version": "0.54.8", | ||||
|       "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz", | ||||
|       "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==", | ||||
|       "dependencies": { | ||||
|         "css-parse": "~2.0.0", | ||||
|         "debug": "~3.1.0", | ||||
|         "glob": "^7.1.6", | ||||
|         "mkdirp": "~1.0.4", | ||||
|         "safer-buffer": "^2.1.2", | ||||
|         "sax": "~1.2.4", | ||||
|         "semver": "^6.3.0", | ||||
|         "source-map": "^0.7.3" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "stylus": "bin/stylus" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/stylus-loader": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", | ||||
|       "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", | ||||
|       "dependencies": { | ||||
|         "loader-utils": "^1.0.2", | ||||
|         "lodash.clonedeep": "^4.5.0", | ||||
|         "when": "~3.6.x" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "stylus": ">=0.52.4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/stylus/node_modules/debug": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", | ||||
|       "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", | ||||
|       "dependencies": { | ||||
|         "ms": "2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/stylus/node_modules/mkdirp": { | ||||
|       "version": "1.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", | ||||
|       "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", | ||||
|       "bin": { | ||||
|         "mkdirp": "bin/cmd.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/stylus/node_modules/ms": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" | ||||
|     }, | ||||
|     "node_modules/stylus/node_modules/semver": { | ||||
|       "version": "6.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||||
|       "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", | ||||
|       "bin": { | ||||
|         "semver": "bin/semver.js" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/stylus/node_modules/source-map": { | ||||
|       "version": "0.7.4", | ||||
|       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", | ||||
|       "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", | ||||
|       "engines": { | ||||
|         "node": ">= 8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/supports-color": { | ||||
|       "version": "7.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | ||||
| @@ -7471,9 +7261,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/thread-loader/node_modules/loader-utils": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|       "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|       "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "big.js": "^5.2.2", | ||||
|         "emojis-list": "^3.0.0", | ||||
| @@ -7625,12 +7416,6 @@ | ||||
|         "punycode": "^2.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/urix": { | ||||
|       "version": "0.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", | ||||
|       "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", | ||||
|       "deprecated": "Please see https://github.com/lydell/urix#deprecated" | ||||
|     }, | ||||
|     "node_modules/util-deprecate": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | ||||
| @@ -7661,33 +7446,6 @@ | ||||
|         "uuid": "dist/bin/uuid" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/v-calendar": { | ||||
|       "version": "3.0.0-alpha.8", | ||||
|       "resolved": "https://registry.npmjs.org/v-calendar/-/v-calendar-3.0.0-alpha.8.tgz", | ||||
|       "integrity": "sha512-T23H5UbK0EomrwArlF/jrT2LFbV/lu+Bp9JroZ1paN6rPoaMyvE+HrLxvAmUgi+pODrdTURDMzM3+WPgeFKEBQ==", | ||||
|       "dependencies": { | ||||
|         "@popperjs/core": "2.4.0", | ||||
|         "@types/lodash": "^4.14.165", | ||||
|         "date-fns": "^2.16.1", | ||||
|         "date-fns-tz": "^1.0.12", | ||||
|         "lodash": "^4.17.20" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "vue": "^3.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/v-viewer": { | ||||
|       "version": "3.0.11", | ||||
|       "resolved": "https://registry.npmjs.org/v-viewer/-/v-viewer-3.0.11.tgz", | ||||
|       "integrity": "sha512-E8LOdAxhzuktt4HB3PswVCccQ1Q1sYHYnLsS6zaJISpb5EvmAFs5sYNfXnDLFxVb5DQ82v4ZlGxkYlseXwWRJw==", | ||||
|       "dependencies": { | ||||
|         "lodash": "^4.17.21", | ||||
|         "viewerjs": "^1.9.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "vue": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/validate-npm-package-license": { | ||||
|       "version": "3.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", | ||||
| @@ -7707,11 +7465,6 @@ | ||||
|         "node": ">= 0.8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/viewerjs": { | ||||
|       "version": "1.11.1", | ||||
|       "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.1.tgz", | ||||
|       "integrity": "sha512-/VQ2zalHLZJOGIwlxOBtxagLZwNvU3Bf+nm692XlhNFxjBXRxpCVn+GeqmRFg9jK1Y2+Wf8PPGxZgTDN4pHXww==" | ||||
|     }, | ||||
|     "node_modules/vite": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.0.tgz", | ||||
| @@ -7754,15 +7507,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/vite-plugin-dynamic-import": { | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/vite-plugin-dynamic-import/-/vite-plugin-dynamic-import-1.2.4.tgz", | ||||
|       "integrity": "sha512-R6spqDhDm8VxaUNyEkybh9PM262ReO8WXJ6rjtyJ/H8Y4b+pq2uM9Xz5DMu7N7OxUGlqo9HSzT3VjhpbySXrng==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "fast-glob": "~3.2.12" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/vue": { | ||||
|       "version": "3.2.39", | ||||
|       "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.39.tgz", | ||||
| @@ -7863,9 +7607,10 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/vue-loader/node_modules/loader-utils": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|       "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|       "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "big.js": "^5.2.2", | ||||
|         "emojis-list": "^3.0.0", | ||||
| @@ -7875,14 +7620,6 @@ | ||||
|         "node": ">=8.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/vue-select": { | ||||
|       "version": "4.0.0-beta.5", | ||||
|       "resolved": "https://registry.npmjs.org/vue-select/-/vue-select-4.0.0-beta.5.tgz", | ||||
|       "integrity": "sha512-W9alTe9NwVn2GR9QFW5CbrX47yghEaJCpUVs9JTv9Q7CWmsNPp5kIlETdke4aFHphZvyjDUlyvH/7/8XzfVZkw==", | ||||
|       "peerDependencies": { | ||||
|         "vue": "3.x" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/vue-style-loader": { | ||||
|       "version": "4.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", | ||||
| @@ -7932,17 +7669,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/vuex": { | ||||
|       "version": "4.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", | ||||
|       "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==", | ||||
|       "dependencies": { | ||||
|         "@vue/devtools-api": "^6.0.0-beta.11" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "vue": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/watchpack": { | ||||
|       "version": "2.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", | ||||
| @@ -8255,9 +7981,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/webpack-plugin-vuetify/node_modules/loader-utils": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|       "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|       "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "big.js": "^5.2.2", | ||||
| @@ -8340,11 +8066,6 @@ | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/when": { | ||||
|       "version": "3.6.4", | ||||
|       "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", | ||||
|       "integrity": "sha512-d1VUP9F96w664lKINMGeElWdhhb5sC+thXM+ydZGU3ZnaE09Wv6FaS+mpM9570kcDs/xMfcXJBTLsMdHEFYY9Q==" | ||||
|     }, | ||||
|     "node_modules/which": { | ||||
|       "version": "1.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", | ||||
| @@ -8870,15 +8591,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/@mdi/font/-/font-5.9.55.tgz", | ||||
|       "integrity": "sha512-jswRF6q3eq8NWpWiqct6q+6Fg/I7nUhrxYJfiEM8JJpap0wVJLQdbKtyS65GdlK7S7Ytnx3TTi/bmw+tBhkGmg==" | ||||
|     }, | ||||
|     "@meforma/vue-toaster": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/@meforma/vue-toaster/-/vue-toaster-1.3.0.tgz", | ||||
|       "integrity": "sha512-jH0zOA/jTiT+UKHO9n5hjPTLkIfg7d66X4fnd7ssIbcXpZOoe+J8IY6Kf3nRW5iVD6/tkjeyp+tjVK8zk6zASg==", | ||||
|       "requires": { | ||||
|         "stylus": "~0.54.8", | ||||
|         "stylus-loader": "~3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "@node-ipc/js-queue": { | ||||
|       "version": "2.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", | ||||
| @@ -8915,11 +8627,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", | ||||
|       "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" | ||||
|     }, | ||||
|     "@popperjs/core": { | ||||
|       "version": "2.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.4.0.tgz", | ||||
|       "integrity": "sha512-NMrDy6EWh9TPdSRiHmHH2ye1v5U0gBD7pRYwSwJvomx7Bm4GG04vu63dYiVzebLOx2obPpJugew06xVP0Nk7hA==" | ||||
|     }, | ||||
|     "@sideway/address": { | ||||
|       "version": "4.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", | ||||
| @@ -9066,11 +8773,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", | ||||
|       "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" | ||||
|     }, | ||||
|     "@types/lodash": { | ||||
|       "version": "4.14.189", | ||||
|       "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.189.tgz", | ||||
|       "integrity": "sha512-kb9/98N6X8gyME9Cf7YaqIMvYGnBSWqEci6tiettE6iJWH1XdJz/PO8LB0GtLCG7x8dU3KWhZT+lA1a35127tA==" | ||||
|     }, | ||||
|     "@types/mime": { | ||||
|       "version": "3.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", | ||||
| @@ -9683,14 +9385,6 @@ | ||||
|         "color-convert": "^2.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "ansi-to-html": { | ||||
|       "version": "0.7.2", | ||||
|       "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", | ||||
|       "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", | ||||
|       "requires": { | ||||
|         "entities": "^2.2.0" | ||||
|       } | ||||
|     }, | ||||
|     "any-promise": { | ||||
|       "version": "1.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", | ||||
| @@ -9733,11 +9427,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", | ||||
|       "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" | ||||
|     }, | ||||
|     "atob": { | ||||
|       "version": "2.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", | ||||
|       "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" | ||||
|     }, | ||||
|     "autoprefixer": { | ||||
|       "version": "10.4.8", | ||||
|       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.8.tgz", | ||||
| @@ -10207,17 +9896,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "css": { | ||||
|       "version": "2.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", | ||||
|       "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", | ||||
|       "requires": { | ||||
|         "inherits": "^2.0.3", | ||||
|         "source-map": "^0.6.1", | ||||
|         "source-map-resolve": "^0.5.2", | ||||
|         "urix": "^0.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "css-declaration-sorter": { | ||||
|       "version": "6.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", | ||||
| @@ -10265,14 +9943,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "css-parse": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", | ||||
|       "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", | ||||
|       "requires": { | ||||
|         "css": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "css-select": { | ||||
|       "version": "4.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", | ||||
| @@ -10369,17 +10039,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", | ||||
|       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" | ||||
|     }, | ||||
|     "date-fns": { | ||||
|       "version": "2.29.3", | ||||
|       "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", | ||||
|       "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" | ||||
|     }, | ||||
|     "date-fns-tz": { | ||||
|       "version": "1.3.7", | ||||
|       "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.7.tgz", | ||||
|       "integrity": "sha512-1t1b8zyJo+UI8aR+g3iqr5fkUHWpd58VBx8J/ZSQ+w7YrGlw80Ag4sA86qkfCXRBLmMc4I2US+aPMd4uKvwj5g==", | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "debug": { | ||||
|       "version": "2.6.9", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
| @@ -10404,11 +10063,6 @@ | ||||
|         "callsite": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "decode-uri-component": { | ||||
|       "version": "0.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", | ||||
|       "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" | ||||
|     }, | ||||
|     "deepmerge": { | ||||
|       "version": "1.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", | ||||
| @@ -10907,9 +10561,9 @@ | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|           "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|           "version": "2.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|           "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
| @@ -11569,9 +11223,9 @@ | ||||
|       "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" | ||||
|     }, | ||||
|     "loader-utils": { | ||||
|       "version": "1.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", | ||||
|       "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", | ||||
|       "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", | ||||
|       "requires": { | ||||
|         "big.js": "^5.2.2", | ||||
|         "emojis-list": "^3.0.0", | ||||
| @@ -11591,11 +11245,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", | ||||
|       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" | ||||
|     }, | ||||
|     "lodash.clonedeep": { | ||||
|       "version": "4.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", | ||||
|       "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" | ||||
|     }, | ||||
|     "lodash.defaultsdeep": { | ||||
|       "version": "4.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", | ||||
| @@ -11994,9 +11643,9 @@ | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|           "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|           "version": "2.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|           "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
| @@ -12815,11 +12464,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", | ||||
|       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" | ||||
|     }, | ||||
|     "resolve-url": { | ||||
|       "version": "0.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", | ||||
|       "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" | ||||
|     }, | ||||
|     "restore-cursor": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", | ||||
| @@ -12894,11 +12538,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | ||||
|       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" | ||||
|     }, | ||||
|     "sax": { | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", | ||||
|       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" | ||||
|     }, | ||||
|     "schema-utils": { | ||||
|       "version": "3.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", | ||||
| @@ -13137,18 +12776,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", | ||||
|       "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" | ||||
|     }, | ||||
|     "source-map-resolve": { | ||||
|       "version": "0.5.3", | ||||
|       "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", | ||||
|       "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", | ||||
|       "requires": { | ||||
|         "atob": "^2.1.2", | ||||
|         "decode-uri-component": "^0.2.0", | ||||
|         "resolve-url": "^0.2.1", | ||||
|         "source-map-url": "^0.4.0", | ||||
|         "urix": "^0.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "source-map-support": { | ||||
|       "version": "0.5.21", | ||||
|       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", | ||||
| @@ -13158,11 +12785,6 @@ | ||||
|         "source-map": "^0.6.0" | ||||
|       } | ||||
|     }, | ||||
|     "source-map-url": { | ||||
|       "version": "0.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", | ||||
|       "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" | ||||
|     }, | ||||
|     "sourcemap-codec": { | ||||
|       "version": "1.4.8", | ||||
|       "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", | ||||
| @@ -13319,61 +12941,6 @@ | ||||
|         "postcss-selector-parser": "^6.0.4" | ||||
|       } | ||||
|     }, | ||||
|     "stylus": { | ||||
|       "version": "0.54.8", | ||||
|       "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz", | ||||
|       "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==", | ||||
|       "requires": { | ||||
|         "css-parse": "~2.0.0", | ||||
|         "debug": "~3.1.0", | ||||
|         "glob": "^7.1.6", | ||||
|         "mkdirp": "~1.0.4", | ||||
|         "safer-buffer": "^2.1.2", | ||||
|         "sax": "~1.2.4", | ||||
|         "semver": "^6.3.0", | ||||
|         "source-map": "^0.7.3" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "debug": { | ||||
|           "version": "3.1.0", | ||||
|           "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", | ||||
|           "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", | ||||
|           "requires": { | ||||
|             "ms": "2.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "mkdirp": { | ||||
|           "version": "1.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", | ||||
|           "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" | ||||
|         }, | ||||
|         "ms": { | ||||
|           "version": "2.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|           "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" | ||||
|         }, | ||||
|         "semver": { | ||||
|           "version": "6.3.0", | ||||
|           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||||
|           "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" | ||||
|         }, | ||||
|         "source-map": { | ||||
|           "version": "0.7.4", | ||||
|           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", | ||||
|           "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "stylus-loader": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", | ||||
|       "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", | ||||
|       "requires": { | ||||
|         "loader-utils": "^1.0.2", | ||||
|         "lodash.clonedeep": "^4.5.0", | ||||
|         "when": "~3.6.x" | ||||
|       } | ||||
|     }, | ||||
|     "supports-color": { | ||||
|       "version": "7.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | ||||
| @@ -13476,9 +13043,9 @@ | ||||
|           "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|           "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|           "version": "2.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|           "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
|             "emojis-list": "^3.0.0", | ||||
| @@ -13573,11 +13140,6 @@ | ||||
|         "punycode": "^2.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "urix": { | ||||
|       "version": "0.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", | ||||
|       "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" | ||||
|     }, | ||||
|     "util-deprecate": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | ||||
| @@ -13598,27 +13160,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", | ||||
|       "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" | ||||
|     }, | ||||
|     "v-calendar": { | ||||
|       "version": "3.0.0-alpha.8", | ||||
|       "resolved": "https://registry.npmjs.org/v-calendar/-/v-calendar-3.0.0-alpha.8.tgz", | ||||
|       "integrity": "sha512-T23H5UbK0EomrwArlF/jrT2LFbV/lu+Bp9JroZ1paN6rPoaMyvE+HrLxvAmUgi+pODrdTURDMzM3+WPgeFKEBQ==", | ||||
|       "requires": { | ||||
|         "@popperjs/core": "2.4.0", | ||||
|         "@types/lodash": "^4.14.165", | ||||
|         "date-fns": "^2.16.1", | ||||
|         "date-fns-tz": "^1.0.12", | ||||
|         "lodash": "^4.17.20" | ||||
|       } | ||||
|     }, | ||||
|     "v-viewer": { | ||||
|       "version": "3.0.11", | ||||
|       "resolved": "https://registry.npmjs.org/v-viewer/-/v-viewer-3.0.11.tgz", | ||||
|       "integrity": "sha512-E8LOdAxhzuktt4HB3PswVCccQ1Q1sYHYnLsS6zaJISpb5EvmAFs5sYNfXnDLFxVb5DQ82v4ZlGxkYlseXwWRJw==", | ||||
|       "requires": { | ||||
|         "lodash": "^4.17.21", | ||||
|         "viewerjs": "^1.9.0" | ||||
|       } | ||||
|     }, | ||||
|     "validate-npm-package-license": { | ||||
|       "version": "3.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", | ||||
| @@ -13633,11 +13174,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", | ||||
|       "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" | ||||
|     }, | ||||
|     "viewerjs": { | ||||
|       "version": "1.11.1", | ||||
|       "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.1.tgz", | ||||
|       "integrity": "sha512-/VQ2zalHLZJOGIwlxOBtxagLZwNvU3Bf+nm692XlhNFxjBXRxpCVn+GeqmRFg9jK1Y2+Wf8PPGxZgTDN4pHXww==" | ||||
|     }, | ||||
|     "vite": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.0.tgz", | ||||
| @@ -13651,15 +13187,6 @@ | ||||
|         "rollup": "~2.78.0" | ||||
|       } | ||||
|     }, | ||||
|     "vite-plugin-dynamic-import": { | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/vite-plugin-dynamic-import/-/vite-plugin-dynamic-import-1.2.4.tgz", | ||||
|       "integrity": "sha512-R6spqDhDm8VxaUNyEkybh9PM262ReO8WXJ6rjtyJ/H8Y4b+pq2uM9Xz5DMu7N7OxUGlqo9HSzT3VjhpbySXrng==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "fast-glob": "~3.2.12" | ||||
|       } | ||||
|     }, | ||||
|     "vue": { | ||||
|       "version": "3.2.39", | ||||
|       "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.39.tgz", | ||||
| @@ -13715,9 +13242,9 @@ | ||||
|           "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|           "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|           "version": "2.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|           "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
|             "emojis-list": "^3.0.0", | ||||
| @@ -13726,12 +13253,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "vue-select": { | ||||
|       "version": "4.0.0-beta.5", | ||||
|       "resolved": "https://registry.npmjs.org/vue-select/-/vue-select-4.0.0-beta.5.tgz", | ||||
|       "integrity": "sha512-W9alTe9NwVn2GR9QFW5CbrX47yghEaJCpUVs9JTv9Q7CWmsNPp5kIlETdke4aFHphZvyjDUlyvH/7/8XzfVZkw==", | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "vue-style-loader": { | ||||
|       "version": "4.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", | ||||
| @@ -13752,14 +13273,6 @@ | ||||
|       "integrity": "sha512-CgDyKCIBZ0ogKUxRw3gNswx9GA6eSSp7otZcJapWJCVuon/RooQPQjf3bDuRb5ZpJ55NkX13ugjl2nq+b0U8SA==", | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "vuex": { | ||||
|       "version": "4.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", | ||||
|       "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==", | ||||
|       "requires": { | ||||
|         "@vue/devtools-api": "^6.0.0-beta.11" | ||||
|       } | ||||
|     }, | ||||
|     "watchpack": { | ||||
|       "version": "2.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", | ||||
| @@ -13970,9 +13483,9 @@ | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", | ||||
|           "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", | ||||
|           "version": "2.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", | ||||
|           "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
| @@ -14027,11 +13540,6 @@ | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "when": { | ||||
|       "version": "3.6.4", | ||||
|       "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", | ||||
|       "integrity": "sha512-d1VUP9F96w664lKINMGeElWdhhb5sC+thXM+ydZGU3ZnaE09Wv6FaS+mpM9570kcDs/xMfcXJBTLsMdHEFYY9Q==" | ||||
|     }, | ||||
|     "which": { | ||||
|       "version": "1.3.1", | ||||
|       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", | ||||
|   | ||||
| @@ -10,28 +10,21 @@ | ||||
|   "dependencies": { | ||||
|     "@ag-grid-community/core": "^28.2.0", | ||||
|     "@mdi/font": "5.9.55", | ||||
|     "@meforma/vue-toaster": "^1.3.0", | ||||
|     "@vue/cli-service": "^5.0.8", | ||||
|     "ag-grid-vue3": "^28.2.0", | ||||
|     "ansi-to-html": "^0.7.2", | ||||
|     "core-js": "^3.25.1", | ||||
|     "event-hooks-webpack-plugin": "^2.2.0", | ||||
|     "pinia": "^2.0.21", | ||||
|     "roboto-fontface": "*", | ||||
|     "single-spa-vue": "^2.5.1", | ||||
|     "systemjs-webpack-interop": "^2.3.7", | ||||
|     "v-calendar": "next", | ||||
|     "v-viewer": "^3.0.11", | ||||
|     "vue": "^3.2.39", | ||||
|     "vue-select": "beta", | ||||
|     "vuetify": "^3.0.0-beta.0", | ||||
|     "vuex": "next", | ||||
|     "webfontloader": "^1.0.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@vitejs/plugin-vue": "^3.0.3", | ||||
|     "vite": "^3.0.9", | ||||
|     "vite-plugin-dynamic-import": "^1.2.4", | ||||
|     "vue-cli-plugin-vuetify": "~2.5.8", | ||||
|     "webpack-plugin-vuetify": "^2.0.0-alpha.0" | ||||
|   } | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| apiVersion: skaffold/v3alpha1 | ||||
| kind: Config | ||||
| metadata: | ||||
|   name: logmower-frontend | ||||
|   name: log-viewer-backend | ||||
|  | ||||
| build: | ||||
|   cluster: {} | ||||
|   artifacts: | ||||
|   - image: harbor.codemowers.eu/erkiaas/logmower-frontend | ||||
|   - image: harbor.k-space.ee/playground/log-viewer-frontend | ||||
|     docker: | ||||
|       dockerfile: Dockerfile | ||||
|  | ||||
| @@ -22,9 +23,9 @@ profiles: | ||||
|       - command: dev | ||||
|     build: | ||||
|       artifacts: | ||||
|         - image: harbor.k-space.ee/playground/logmower-frontend | ||||
|           docker: | ||||
|             target: prod | ||||
|         - image: harbor.k-space.ee/playground/log-viewer-frontend | ||||
|           kaniko: | ||||
|             target: dev | ||||
|           sync: | ||||
|             manual: | ||||
|               - src: 'src/**/*.vue' | ||||
| @@ -39,4 +40,4 @@ profiles: | ||||
|                 dest: . | ||||
|     manifests: | ||||
|       rawYaml: | ||||
|         - k8s/dev/deployment-camtiler.yaml | ||||
|         - k8s/dev/deployment.yaml | ||||
|   | ||||
| @@ -1,51 +1,15 @@ | ||||
|  | ||||
| div#app { | ||||
|   width: 100%; | ||||
|   height: 100vh; | ||||
|   font-family: 'Roboto Mono'; | ||||
| } | ||||
|  | ||||
| .screenshots-drawer { | ||||
|   position: fixed; | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
| } | ||||
|  | ||||
| .screenshots-drawer img { | ||||
|   margin-right: 0; | ||||
|   flex-direction: column; | ||||
| } | ||||
|  | ||||
| .ag-theme-material { | ||||
|   --ag-value-change-value-highlight-background-color: #f9ff99; | ||||
| } | ||||
|  | ||||
| .ag-popup-child .ag-filter { | ||||
|   width: 300px; | ||||
|   height: 390px; | ||||
| } | ||||
|  | ||||
| .app-title { | ||||
|   font-family: 'Montserrat'; | ||||
|   text-transform: capitalize; | ||||
| } | ||||
|  | ||||
| .vc-container { | ||||
|   font-family: 'Roboto Mono' !important; | ||||
| } | ||||
|  | ||||
| :root { | ||||
|   --vs-font-size: 1em!important; | ||||
| } | ||||
|  | ||||
| .ag-overlay-panel { | ||||
|   display: flex; | ||||
|   width: 100%; | ||||
|   height: calc(100% - 56px); | ||||
|   margin-top: 56px; | ||||
| } | ||||
|  | ||||
| .ag-theme-material { | ||||
|   --ag-font-family: 'Roboto Mono'!important; | ||||
| } | ||||
|  | ||||
| .v--default-css .c-toast { | ||||
|   font-family: 'Roboto Mono'!important; | ||||
| } | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/components/ComboboxFilter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/components/ComboboxFilter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| export default { | ||||
|     template: ` | ||||
|       <select v-model="filter" class="v-select"> | ||||
|         <option value=""> </option> | ||||
|         <option v-for="option in params.options" :value="option"> | ||||
|            {{ option }} | ||||
|         </option> | ||||
|       </select> | ||||
|     `, | ||||
|     data: function () { | ||||
|         return { | ||||
|             filter: '', | ||||
|         }; | ||||
|     }, | ||||
|     methods: { | ||||
|         updateFilter() { | ||||
|             this.params.filterChangedCallback(); | ||||
|         }, | ||||
|  | ||||
|         doesFilterPass(params) { | ||||
|             const value = this.params.field.split('.').reduce((a, b) => a[b], params.data); | ||||
|             return value === this.filter; | ||||
|         }, | ||||
|  | ||||
|         isFilterActive() { | ||||
|             return this.filter !== '' | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
| @@ -2,8 +2,6 @@ | ||||
|   <v-dialog | ||||
|       v-model="examineLog" | ||||
|       width="50wv" | ||||
|       @click.outside="close" | ||||
|       transition="false" | ||||
|   > | ||||
|     <v-card> | ||||
|       <v-card-text style="height: 70vh"> | ||||
| @@ -17,11 +15,10 @@ | ||||
|             :enable-scrolling="true" | ||||
|             :enableCellTextSelection="true" | ||||
|             :ensureDomOrder="true" | ||||
|             @cell-clicked="copyText" | ||||
|           ></ag-grid-vue> | ||||
|         ></ag-grid-vue> | ||||
|       </v-card-text> | ||||
|       <v-card-actions> | ||||
|         <v-btn color="primary" block @click="closeModal" transition="false">Close</v-btn> | ||||
|         <v-btn color="primary" block @click="closeModal">Close</v-btn> | ||||
|       </v-card-actions> | ||||
|     </v-card> | ||||
|   </v-dialog> | ||||
| @@ -31,14 +28,14 @@ | ||||
| import { AgGridVue } from "ag-grid-vue3"; | ||||
| import "ag-grid-community/styles//ag-grid.css"; | ||||
| import "ag-grid-community/styles//ag-theme-material.css"; | ||||
| import ScreenshotCell from "./ScreenshotCell.js"; | ||||
| import { VCard, VCardText, VCardActions } from 'vuetify/components/VCard' | ||||
| import { VDialog } from 'vuetify/components/VDialog' | ||||
| import { VBtn } from 'vuetify/components/VBtn' | ||||
| import { VTable } from 'vuetify/components/VTable' | ||||
| import ValueRenderer from "./ValueRenderer"; | ||||
| 
 | ||||
| 
 | ||||
| export default { | ||||
|   name: "ExamineLogModal", | ||||
|   components: { | ||||
|     AgGridVue, | ||||
|     VCard, | ||||
| @@ -47,7 +44,7 @@ export default { | ||||
|     VBtn, | ||||
|     VDialog, | ||||
|     VTable, | ||||
|     ValueRenderer | ||||
|     ScreenshotCell: ScreenshotCell | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
| @@ -56,15 +53,13 @@ export default { | ||||
|           field: 'key', | ||||
|           sortable: true, | ||||
|           filter: 'agTextColumnFilter', | ||||
|           resizable: true, | ||||
|           width: 10, | ||||
|           resizable: true | ||||
|         }, | ||||
|         { | ||||
|           field: 'value', | ||||
|           sortable: true, | ||||
|           filter: 'agTextColumnFilter', | ||||
|           resizable: true, | ||||
|           cellRenderer: 'ValueRenderer' | ||||
|           resizable: true | ||||
|         }, | ||||
|       ] | ||||
|     } | ||||
| @@ -82,18 +77,6 @@ export default { | ||||
|     onGridReady(params) { | ||||
|       params.api.sizeColumnsToFit() | ||||
|     }, | ||||
|     close (e) { | ||||
|       if (e.target.className === "v-overlay__scrim") { | ||||
|         this.closeModal() | ||||
|       } | ||||
|     }, | ||||
|     copyText(e) { | ||||
|       navigator.clipboard.writeText(e.value); | ||||
|       this.$toast.success(`Value copied to clipboard`, { | ||||
|         position: "top-right", | ||||
|       }); | ||||
|       setTimeout(this.$toast.clear, 3000); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @@ -1,53 +0,0 @@ | ||||
| <template> | ||||
|   <v-select | ||||
|       v-model="filterValue" | ||||
|       :options="options" | ||||
|       :placeholder="placeholder" | ||||
|       @open="updateOptions" | ||||
|   ></v-select> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import vSelect from "vue-select" | ||||
|  | ||||
| export default { | ||||
|   name: "Combobox", | ||||
|   components: { | ||||
|     vSelect | ||||
|   }, | ||||
|   props: { | ||||
|     field: { | ||||
|     }, | ||||
|     changeValue: { | ||||
|     }, | ||||
|     filter: { | ||||
|     }, | ||||
|     placeholder: { | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       options: [] | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     filterValue: { | ||||
|       get() { | ||||
|         return this.filter | ||||
|       }, | ||||
|       set(newValue) { | ||||
|         this.changeValue(newValue) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     updateOptions() { | ||||
|       this.options = this.$store.state.filterOptions[this.field] ?? [] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
|  | ||||
| </style> | ||||
| @@ -1,51 +0,0 @@ | ||||
| import Combobox from "./Combobox.vue"; | ||||
|  | ||||
| export default { | ||||
|     // This is a helper component to translate between ag-grid's custom filter logic and a regular Vue component | ||||
|     // https://www.ag-grid.com/vue-data-grid/component-filter/#custom-filter-interface-3 | ||||
|     components: { | ||||
|       Combobox | ||||
|     }, | ||||
|     template: `<Combobox | ||||
|         :field="params.field" | ||||
|         :filter="filter" | ||||
|         :change-value="updateFilter" | ||||
|         :placeholder="placeholder" | ||||
|     />`, | ||||
|     mounted() { | ||||
|         this.params.api.sizeColumnsToFit() | ||||
|     }, | ||||
|     data: function () { | ||||
|         return { | ||||
|             filter: '', | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|       placeholder() { | ||||
|           let parentColumnName = this.params.column.userProvidedColDef.filterParams.parentColumn | ||||
|           if (parentColumnName) { | ||||
|               let filterInstance = this.params.api.getFilterInstance(parentColumnName) | ||||
|               if (!filterInstance.filter || filterInstance.filter === '') { | ||||
|                   let displayName = filterInstance.params.column.userProvidedColDef.headerName | ||||
|                   return `Please select ${displayName} first` | ||||
|               } | ||||
|           } | ||||
|           return '' | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|         updateFilter(value) { | ||||
|             this.filter = value | ||||
|             this.params.filterChangedCallback(); | ||||
|         }, | ||||
|  | ||||
|         doesFilterPass(params) { | ||||
|             const value = this.params.field.split('.').reduce((a, b) => a[b], params.data); | ||||
|             return value === this.filter; | ||||
|         }, | ||||
|  | ||||
|         isFilterActive() { | ||||
|             return this.filter !== '' && this.filter | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
| @@ -1,96 +0,0 @@ | ||||
| <template> | ||||
|   <v-date-picker mode="dateTime" v-model="dateRange" locale="et" :is24hr="true" is-range timezone="UTC"> | ||||
|     <template v-slot="{ inputValue, inputEvents }"> | ||||
|       <div class="flex justify-center items-center align-center"> | ||||
|         <input | ||||
|             :value="inputValue.start" | ||||
|             v-on="inputEvents.start" | ||||
|             class="border px-2 py-1 w-32 rounded focus:outline-none focus:border-indigo-300" | ||||
|         /> | ||||
|         <svg | ||||
|             class="mx-2" | ||||
|             fill="none" | ||||
|             viewBox="0 0 24 24" | ||||
|             stroke="currentColor" | ||||
|             width="20" | ||||
|         > | ||||
|           <path | ||||
|               stroke-linecap="round" | ||||
|               stroke-linejoin="round" | ||||
|               stroke-width="2" | ||||
|               d="M14 5l7 7m0 0l-7 7m7-7H3" | ||||
|           /> | ||||
|         </svg> | ||||
|         <input | ||||
|             :value="inputValue.end" | ||||
|             v-on="inputEvents.end" | ||||
|             class="border px-2 py-1 w-32 rounded focus:outline-none focus:border-indigo-300" | ||||
|         /> | ||||
|         <v-icon class="ml-2" @click="clearDates">mdi-close</v-icon> | ||||
|       </div> | ||||
|     </template> | ||||
|   </v-date-picker> | ||||
| </template> | ||||
|  | ||||
|  | ||||
| <script> | ||||
| import {mapActions, mapGetters} from "vuex"; | ||||
| import { VIcon } from 'vuetify/components/VIcon' | ||||
| import { VBtn } from 'vuetify/components/VBtn' | ||||
|  | ||||
|  | ||||
| export default { | ||||
|   name: "Datepicker", | ||||
|   components: { | ||||
|     VIcon, | ||||
|     VBtn | ||||
|   }, | ||||
|   props: { | ||||
|     refresh: {} | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters([ | ||||
|       'filterQuery', | ||||
|     ]), | ||||
|     dateRange: { | ||||
|       get() { | ||||
|         return { | ||||
|           start: this.filterQuery.from ? new Date(this.filterQuery.from) : null, | ||||
|           end: this.filterQuery.to ? new Date(this.filterQuery.to) : null, | ||||
|         } | ||||
|       }, | ||||
|       set(value) { | ||||
|         if (value) { | ||||
|           let toDate = new Date(value.end); | ||||
|           toDate.setSeconds(59, 999); | ||||
|           this.setFilterQueryTimeRange({ | ||||
|             from: (new Date(value.start).getTime()), | ||||
|             to: (toDate.getTime()), | ||||
|           }) | ||||
|           this.refresh() | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions({ | ||||
|       setFilterQueryTimeRange: 'setFilterQueryTimeRange', | ||||
|     }), | ||||
|     clearDates () { | ||||
|       this.setFilterQueryTimeRange({ | ||||
|         from: null, | ||||
|         to: null, | ||||
|       }) | ||||
|       this.refresh() | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
|  | ||||
| </style> | ||||
| @@ -1,52 +0,0 @@ | ||||
| import { VRow, VCol } from 'vuetify/components/VGrid' | ||||
| import { VIcon } from 'vuetify/components/VIcon' | ||||
| import 'ansi-to-html' | ||||
| import Convert from "ansi-to-html"; | ||||
|  | ||||
|  | ||||
| export default { | ||||
|     template: `<v-row> | ||||
|       <v-col> | ||||
|         <v-icon v-if="icon" :color="color" class="mr-2">{{ icon }}</v-icon> | ||||
|         <span v-html="message"></span> | ||||
|       </v-col> | ||||
|     </v-row>`, | ||||
|     components: { | ||||
|         VRow, | ||||
|         VCol, | ||||
|         VIcon | ||||
|     }, | ||||
|     setup(props) { | ||||
|         let message = props.params.value | ||||
|         let converter = new Convert() | ||||
|         message = converter.toHtml(message) | ||||
|         let level = props.params.data.level | ||||
|         let icons = { | ||||
|             'emergency': 'mdi-alert-circle', | ||||
|             'alert': 'mdi-alert-circle', | ||||
|             'critical': 'mdi-alert-circle', | ||||
|             'error': 'mdi-alert-circle', | ||||
|             'warning': 'mdi-alert-circle', | ||||
|             'notice': 'mdi-alert-circle', | ||||
|             'info': 'mdi-information', | ||||
|             'debug': 'mdi-information', | ||||
|         } | ||||
|         let colors = { | ||||
|             'emergency': 'red', | ||||
|             'alert': 'red', | ||||
|             'critical': 'red', | ||||
|             'error': 'red', | ||||
|             'warning': 'orange', | ||||
|             'notice': 'orange', | ||||
|             'info': 'green', | ||||
|             'debug': 'green', | ||||
|         } | ||||
|         let color = colors[level] ?? null | ||||
|         let icon = icons[level] ?? null | ||||
|         return { | ||||
|             message, | ||||
|             color, | ||||
|             icon | ||||
|         }; | ||||
|     }, | ||||
| }; | ||||
| @@ -1,46 +0,0 @@ | ||||
| const config = { | ||||
|     defaultColDef: { | ||||
|         width: 120, | ||||
|         initialPinned: true, | ||||
|         resizable: true, | ||||
|         enableCellChangeFlash: true | ||||
|     }, | ||||
|     columnDefs: [ | ||||
|         { | ||||
|             field: '@timestamp', | ||||
|             width: 140, | ||||
|             sortable: true | ||||
|         }, | ||||
|         { | ||||
|             field: 'source', | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|             filter: 'ComboboxFilter', | ||||
|             filterParams: { | ||||
|                 options: [], | ||||
|                 field: 'source', | ||||
|                 parentColumn: null, | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             field: 'event', | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|         }, | ||||
|         { | ||||
|             field: 'started', | ||||
|             width: 140, | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|         }, | ||||
|         { | ||||
|             field: 'finished', | ||||
|             width: 140, | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|         }, | ||||
|         { | ||||
|             field: 'screenshots', | ||||
|             cellRenderer: 'ScreenshotRenderer', | ||||
|             width: 450, | ||||
|         }, | ||||
|     ], | ||||
| } | ||||
|  | ||||
| export default config | ||||
| @@ -1,58 +0,0 @@ | ||||
| import ComboboxFilter from "../Filter/ComboboxFilter"; | ||||
|  | ||||
| const config = { | ||||
|     defaultColDef: { | ||||
|         width: 120, | ||||
|         initialPinned: true, | ||||
|         resizable: true, | ||||
|         enableCellChangeFlash: true | ||||
|     }, | ||||
|     columnDefs: [ | ||||
|         { | ||||
|             field: '@timestamp', | ||||
|             width: 120, | ||||
|             sortable: true | ||||
|         }, | ||||
|         { | ||||
|             field: 'kubernetes.namespace', | ||||
|             headerName: 'namespace', | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|             filter: ComboboxFilter, | ||||
|             filterParams: { | ||||
|                 options: [], | ||||
|                 field: 'kubernetes.namespace', | ||||
|                 parentColumn: null, | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             field: 'kubernetes.pod.name', | ||||
|             headerName: 'pod', | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|             filter: ComboboxFilter, | ||||
|             filterParams: { | ||||
|                 options: [], | ||||
|                 field: 'kubernetes.pod.name', | ||||
|                 parentColumn: 'kubernetes.namespace', | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             field: 'kubernetes.container.name', | ||||
|             headerName: 'container', | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|             filter: ComboboxFilter, | ||||
|             filterParams: { | ||||
|                 options: [], | ||||
|                 field: 'kubernetes.container.name', | ||||
|                 parentColumn: 'kubernetes.pod.name', | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             field: 'message', | ||||
|             tooltipValueGetter: (params) => params.value, | ||||
|             cellRenderer: 'MessageWithLevelRenderer', | ||||
|             width: 500, | ||||
|         }, | ||||
|     ], | ||||
| } | ||||
|  | ||||
| export default config | ||||
| @@ -1,7 +0,0 @@ | ||||
| export default { | ||||
|     template: ` | ||||
|       <div class="ag-overlay-loading-center"> | ||||
|         Loading | ||||
|       </div> | ||||
|     `, | ||||
| }; | ||||
| @@ -1,85 +0,0 @@ | ||||
| <template> | ||||
|   <v-tooltip :text="`Last ping from server received at ${secondsFromLastPing} seconds ago`" location="bottom"> | ||||
|     <template v-slot:activator="{ props }"> | ||||
|       <v-icon :color="(secondsFromLastPing > pingThreshold || secondsFromLastPing === null) ? 'red' : 'green'" v-bind="props" class="mr-6">mdi-server</v-icon> | ||||
|     </template> | ||||
|   </v-tooltip> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { VTooltip } from 'vuetify/components/VTooltip' | ||||
| import { VIcon } from 'vuetify/components/VIcon' | ||||
| import {mapGetters} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "ConnectionMonitor", | ||||
|   components: { | ||||
|     VTooltip, | ||||
|     VIcon | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       pingThreshold: 10, | ||||
|       pingError: false, | ||||
|       secondsFromLastPing: null, | ||||
|       setupStreamInterval: null, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters([ | ||||
|       'lastPingReceived' | ||||
|     ]) | ||||
|   }, | ||||
|   mounted() { | ||||
|     // window.setInterval(() => { | ||||
|     //   this.monitorServerConnection() | ||||
|     // }, 10000) | ||||
|     window.setInterval(() => { | ||||
|       this.secondsFromLastPing = Math.floor(((new Date()).getTime() - this.lastPingReceived) / 1000) | ||||
|       this.pingError = this.secondsFromLastPing > this.pingThreshold | ||||
|     }, 1000) | ||||
|   }, | ||||
|   watch: { | ||||
|     pingError(error) { | ||||
|       if (error) { | ||||
|         this.$toast.error(`Connection with server lost, attempting to reconnect...`, { | ||||
|           position: "top-right", | ||||
|           duration: false, | ||||
|         }); | ||||
|         this.setupStreamInterval = window.setInterval(() => { | ||||
|           this.$emit('setupStream') | ||||
|         }, 3000) | ||||
|       } else { | ||||
|         window.clearTimeout(this.setupStreamInterval); | ||||
|         this.$toast.clear(); | ||||
|         this.$toast.success(`Connection with server reestablished`, { | ||||
|           position: "top-right", | ||||
|         }); | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     monitorServerConnection () { | ||||
|       if (this.secondsFromLastPing > this.pingThreshold) { | ||||
|         this.pingError = true; | ||||
|         this.$toast.error(`Connection with server lost, attempting to reconnect...`, { | ||||
|           position: "top-right", | ||||
|         }); | ||||
|         this.setupStream(); | ||||
|       } else { | ||||
|         if (this.pingError) { | ||||
|           this.$toast.success(`Connection with server reestablished`, { | ||||
|             position: "top-right", | ||||
|           }); | ||||
|           setTimeout(this.$toast.clear, 3000); | ||||
|         } | ||||
|         this.pingError = false; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
|  | ||||
| </style> | ||||
| @@ -1,59 +0,0 @@ | ||||
| <template> | ||||
|   <v-row no-gutters> | ||||
|     <v-col cols="12" sm="5" class="d-flex justify-start flex-wrap" > | ||||
|       <Datepicker class="ma-2" :refresh="refreshFilterState" /> | ||||
|     </v-col> | ||||
|     <v-col cols="12" sm="2" class="d-flex justify-center flex-wrap"> | ||||
|       <h1 class="app-title"> {{ title }} </h1> | ||||
|     </v-col> | ||||
|     <v-col cols="12" sm="5" class="d-flex justify-end flex-wrap align-center"> | ||||
|       <ConnectionMonitor @setup-stream="setupStream" /> | ||||
|       <v-btn | ||||
|           color="blue-grey" | ||||
|           class="ma-2" | ||||
|           :prepend-icon="streaming ? 'mdi-pause' :'mdi-play'" | ||||
|           @click="toggleFilterQueryStreaming" | ||||
|       > | ||||
|         Stream new lines | ||||
|       </v-btn> | ||||
|     </v-col> | ||||
|   </v-row> | ||||
| </template> | ||||
| <script> | ||||
| import { VRow, VCol } from 'vuetify/components/VGrid' | ||||
| import { VBtn } from 'vuetify/components/VBtn' | ||||
| import Datepicker from "../Grid/Main/Filter/Datepicker.vue"; | ||||
| import {mapActions, mapGetters} from "vuex"; | ||||
| import ConnectionMonitor from "./ConnectionMonitor.vue"; | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     ConnectionMonitor, | ||||
|     Datepicker, | ||||
|     VRow, | ||||
|     VCol, | ||||
|     VBtn | ||||
|   }, | ||||
|   props: { | ||||
|     refreshFilterState: Function, | ||||
|     title: String | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters([ | ||||
|       'streaming' | ||||
|     ]), | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions({ | ||||
|       toggleFilterQueryStreaming: 'toggleFilterQueryStreaming', | ||||
|     }), | ||||
|     setupStream () { | ||||
|       this.$emit('setupStream') | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
|  | ||||
| </style> | ||||
| @@ -1,14 +1,11 @@ | ||||
| <template> | ||||
|   <div style="height: 100%; width: 100%;" v-resize="onResize"> | ||||
|     <Header :refresh-filter-state="refreshFilterState" :title="backend" @setup-stream="setupStream" /> | ||||
|     <ag-grid-vue | ||||
|       v-if="columnDefs" | ||||
|       style="width: 100%; height: calc(100% - 52px);" | ||||
|   <div style="height: 100%; width: 100%"> | ||||
|   <ag-grid-vue | ||||
|       style="width: 100%; height: 100%;" | ||||
|       class="ag-theme-material" | ||||
|       @grid-ready="onGridReady" | ||||
|       :defaultColDef="defaultColDef" | ||||
|       :columnDefs="columnDefs" | ||||
|       :getRowId="params => params.data._id" | ||||
|       :pagination="true" | ||||
|       :paginationAutoPageSize=true | ||||
|       :row-data="null" | ||||
| @@ -16,12 +13,8 @@ | ||||
|       :onRowSelected="openExamineLog" | ||||
|       :supress-horisontal-scroll="true" | ||||
|       :enable-scrolling="true" | ||||
|       :isExternalFilterPresent="() => {return true}" | ||||
|       :doesExternalFilterPass="doesExternalFilterPass" | ||||
|       :loadingOverlayComponent="'loadingOverlay'" | ||||
|     ></ag-grid-vue> | ||||
|     <ExamineLogModal v-if="backend === 'logmower'" :examine-log-content="examineLogContent" :close-modal="closeExamineLog" /> | ||||
|     <ExamineCamModal v-if="backend === 'camtiler'" :examine-log-content="examineLogContent" :close-modal="closeExamineLog" /> | ||||
|     <ExamineLogModal :examine-log-content="examineLogContent" :close-modal="closeExamineLog" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @@ -29,243 +22,123 @@ | ||||
| import { AgGridVue } from "ag-grid-vue3"; | ||||
| import "ag-grid-community/styles//ag-grid.css"; | ||||
| import "ag-grid-community/styles//ag-theme-material.css"; | ||||
| import { Resize } from 'vuetify/directives'; | ||||
| import ExamineLogModal from "./Modal/ExamineLogModal.vue"; | ||||
| import ExamineCamModal from "./Modal/ExamineCamModal.vue"; | ||||
| import ComboboxFilter from "./Grid/Main/Filter/ComboboxFilter.js"; | ||||
| import MessageWithLevelRenderer from "./Grid/Main/MessageWithLevelRenderer"; | ||||
| import ScreenshotRenderer from "./Grid/Main/ScreenshotRenderer"; | ||||
| import flattenObj from "../helpers/flattenObj"; | ||||
| import parseEventData from "../helpers/parseEventData"; | ||||
| import {mapActions, mapGetters} from 'vuex'; | ||||
| import loadingOverlay from "./Grid/Main/loadingOverlay"; | ||||
| import Header from "./Header/Header.vue"; | ||||
| import ScreenshotCell from "./ScreenshotCell.js"; | ||||
| import ExamineLogModal from "./ExamineLogModal.vue"; | ||||
| import ComboboxFilter from "./ComboboxFilter.js"; | ||||
|  | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     Header, | ||||
|     ExamineLogModal, // TODO: dynamic loading | ||||
|     ExamineCamModal, | ||||
|     ExamineLogModal, | ||||
|     AgGridVue, | ||||
|     ComboboxFilter, | ||||
|     MessageWithLevelRenderer, | ||||
|     ScreenshotRenderer, | ||||
|     loadingOverlay | ||||
|   }, | ||||
|   directives: { | ||||
|     Resize | ||||
|     ScreenshotCell: ScreenshotCell | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       examineLogContent: null, | ||||
|       gridApi: null, | ||||
|       gridColumnApi: null, | ||||
|       defaultColDef: { | ||||
|         width: 50, | ||||
|         initialPinned: true, | ||||
|         resizable: true, | ||||
|         enableCellChangeFlash: true | ||||
|       }, | ||||
|       currentRowCount: 0, | ||||
|       comboBoxOptions: {}, | ||||
|       es: null, | ||||
|       initialFilter: null, | ||||
|       defaultColDef: null, | ||||
|       columnDefs: null, | ||||
|       backend: 'logmower' | ||||
|       viewRowCount: 20, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters([ | ||||
|       'filterQuery', | ||||
|       'streaming' | ||||
|     ]), | ||||
|   }, | ||||
|   watch: { | ||||
|     filterQuery() { | ||||
|       if (this.backend) { | ||||
|         this.setupStream() | ||||
|       } | ||||
|     }, | ||||
|     streaming() { | ||||
|       if (this.backend) { | ||||
|         this.setupStream() | ||||
|       } | ||||
|     }, | ||||
|     columnDefs() { | ||||
|       return [ | ||||
|         { | ||||
|           field: '@timestamp', | ||||
|           width: 70, | ||||
|           sortable: true | ||||
|         }, | ||||
|         { | ||||
|           field: 'kubernetes.namespace', | ||||
|           headerName: 'namespace', | ||||
|           tooltipValueGetter: (params) => params.value, | ||||
|           filter: ComboboxFilter, | ||||
|           filterParams: { | ||||
|             options: this.comboBoxOptions['kubernetes.namespace'], | ||||
|             field: 'kubernetes.namespace', | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           field: 'kubernetes.pod.name', | ||||
|           headerName: 'pod', | ||||
|           tooltipValueGetter: (params) => params.value, | ||||
|           filter: ComboboxFilter, | ||||
|           filterParams: { | ||||
|             options: this.comboBoxOptions['kubernetes.pod.name'], | ||||
|             field: 'kubernetes.pod.name', | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           field: 'kubernetes.container.name', | ||||
|           headerName: 'container', | ||||
|           tooltipValueGetter: (params) => params.value, | ||||
|           filter: ComboboxFilter, | ||||
|           filterParams: { | ||||
|             options: this.comboBoxOptions['kubernetes.container.name'], | ||||
|             field: 'kubernetes.container.name', | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           field: 'message', | ||||
|           tooltipValueGetter: (params) => params.value, | ||||
|           width: 500, | ||||
|         }, | ||||
|         { | ||||
|           field: 'stream', | ||||
|         }, | ||||
|       ]; | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     fetch('/events/backend') | ||||
|         .then((response) => response.text()) | ||||
|         .then((response) => { | ||||
|           this.backend = response // TODO handle bad gateway etc | ||||
|           import(`./Grid/Main/configs/${response}.js`) | ||||
|               .then(module => { | ||||
|                 this.defaultColDef = module.default.defaultColDef | ||||
|                 this.columnDefs = module.default.columnDefs | ||||
|               }).catch(err => { | ||||
|                 console.error(err) | ||||
|                 this.$toast.error(`Backend '${response}' not supported`, { | ||||
|                 position: "top-right", | ||||
|             }); | ||||
|           }).then(() => { | ||||
|             let queryParams = new URLSearchParams(window.location.search); | ||||
|             queryParams = Object.fromEntries(queryParams); | ||||
|             this.initialFilter = queryParams | ||||
|             queryParams['initial'] = true | ||||
|             queryParams['from'] && (queryParams['from'] = Number(queryParams['from'])) | ||||
|             queryParams['to'] && (queryParams['to'] = Number(queryParams['to'])) | ||||
|             this.setFilterQuery(queryParams) | ||||
|           }); | ||||
|       }) | ||||
|     this.setupStream() | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions({ | ||||
|       setFilterOptions: 'setFilterOptions', | ||||
|       setFilterQuery: 'setFilterQuery', | ||||
|       setLastPingReceived: 'setLastPingReceived', | ||||
|     }), | ||||
|     onResize () { | ||||
|       if (this.gridApi) { | ||||
|         this.gridApi.sizeColumnsToFit() | ||||
|       } | ||||
|     }, | ||||
|     refreshFilterState() { | ||||
|       this.gridApi.onFilterChanged(); | ||||
|     }, | ||||
|     setupStream() { | ||||
|       this.es && this.es.close(); | ||||
|       let url = new URL('/events', window.location.href); | ||||
|       for (const key in this.filterQuery) { | ||||
|         url.searchParams.append(key, this.filterQuery[key]); | ||||
|       } | ||||
|       if (url.searchParams.keys().next()) { | ||||
|         let es = new EventSource(url.toString()); | ||||
|         es.onmessage = (e) => this.handleReceiveMessage(e) | ||||
|         es.addEventListener("ping", (e) => this.handleReceivePing()) | ||||
|         es.addEventListener("filters", (e) => this.handleReceiveFilters(e)) | ||||
|         es.addEventListener("timeout", (e) => this.handleReceiveTimeout(e)) | ||||
|         es.addEventListener("completed", (e) => this.handleAllReceived(e)) | ||||
|         this.es = es | ||||
|         if (this.gridApi) { | ||||
|           this.gridApi.showLoadingOverlay(); | ||||
|         } | ||||
|       } | ||||
|       url.searchParams.delete('initial') | ||||
|       if (url.searchParams.get('streaming') === 'false') { | ||||
|         url.searchParams.delete('streaming') | ||||
|       } | ||||
|       window.history.replaceState({}, '', `${location.pathname}?${url.searchParams.toString()}`); | ||||
|       let es = new EventSource('/events'); | ||||
|       es.onmessage = (e) => this.handleReceiveMessage(e) | ||||
|       es.addEventListener("filters", (e) => this.handleReceiveFilters(e)) | ||||
|     }, | ||||
|     onGridReady(params) { | ||||
|       this.gridApi = params.api; | ||||
|       this.gridColumnApi = params.columnApi; | ||||
|       this.gridColumnApi.applyColumnState({ | ||||
|         state: [{ | ||||
|             colId: '@timestamp', | ||||
|             sort: 'desc' | ||||
|           }] | ||||
|       }); | ||||
|  | ||||
|       for (let k in this.initialFilter) { | ||||
|         let filterInstance = params.api.getFilterInstance(k); | ||||
|         if (filterInstance) { | ||||
|           filterInstance.updateFilter(this.initialFilter[k]); | ||||
|         } | ||||
|       } | ||||
|       params.api.onFilterChanged(); | ||||
|       this.initialFilter = null | ||||
|  | ||||
|       this.gridApi.addGlobalListener((type, event) => { | ||||
|         if (type === 'filterChanged') { | ||||
|           let changedColumn = event.columns[0] ? (event.columns[0].colId) : null | ||||
|           let query = {} | ||||
|           let gridColumns = event.columnApi.columnModel.gridColumns | ||||
|           gridColumns.map((column) => { | ||||
|             // Reset child column filter if parent changed | ||||
|             let parentColumn = column?.colDef?.filterParams?.parentColumn | ||||
|             if (parentColumn && changedColumn === parentColumn) { | ||||
|               let filterInstance = this.gridApi.getFilterInstance(column.colId); | ||||
|               column.filterActive = null | ||||
|               filterInstance.updateFilter(null) | ||||
|               this.gridApi.onFilterChanged(); | ||||
|             } | ||||
|             if (column.filterActive) { | ||||
|               query[column.colId] = column.filterActive | ||||
|             } | ||||
|           }) | ||||
|           query['streaming'] = this.streaming | ||||
|           this.filterQuery.from && (query['from'] = this.filterQuery.from) | ||||
|           this.filterQuery.to && (query['to'] = this.filterQuery.to) | ||||
|           this.setFilterQuery(query) | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     handleReceiveMessage (event) { | ||||
|       const eventData = parseEventData(event.data); | ||||
|       if (!this.gridApi.getRowNode(eventData._id)) { | ||||
|         this.gridApi.applyTransactionAsync({ | ||||
|           add: [eventData] | ||||
|         }, (res) => { | ||||
|           const rowNode = res.add[0] | ||||
|           this.gridApi.flashCells({ rowNodes: [rowNode]}); | ||||
|         }) | ||||
|       } | ||||
|       const eventData = this.parseEventData(event.data); | ||||
|       const res = this.gridApi.applyTransaction({ | ||||
|         add: [eventData] | ||||
|       }); | ||||
|       const rowNode = res.add[0] | ||||
|       this.gridApi.flashCells({ rowNodes: [rowNode]}); | ||||
|       this.gridApi.sizeColumnsToFit() | ||||
|     }, | ||||
|     handleReceiveFilters (event) { | ||||
|       let data = parseEventData(event.data); | ||||
|       let opts = this.comboBoxOptions | ||||
|       for (let k in data) { | ||||
|         if (!(k in opts)) { | ||||
|           opts[k] = [] | ||||
|         } | ||||
|         // TODO: proper merging | ||||
|         if ((data[k].parentKey) || (opts[k].length === 0)) { | ||||
|           opts[k].push(data[k]) | ||||
|       this.comboBoxOptions = this.parseEventData(event.data); | ||||
|     }, | ||||
|     parseEventData (eventData) { | ||||
|       try { | ||||
|         let json = JSON.parse(eventData) | ||||
|         if (!json.message) { | ||||
|           json.message = JSON.stringify(json.json) | ||||
|         } | ||||
|         return json | ||||
|       } catch (e) { | ||||
|         console.error(e, eventData) | ||||
|       } | ||||
|       this.comboBoxOptions = opts | ||||
|  | ||||
|       let correctOptions = {}; | ||||
|       for (let column in opts) { | ||||
|           correctOptions[column] = [] | ||||
|           let columnDef = this.columnDefs.find((columnDef) => { | ||||
|             return columnDef.field === column | ||||
|           }); | ||||
|           let parentColumnName = columnDef?.filterParams?.parentColumn; | ||||
|           let possibleColumnOptions = opts[column].filter((k) => { | ||||
|             return k.parentKey === parentColumnName | ||||
|           }) | ||||
|           if (possibleColumnOptions.length === 1) { | ||||
|             correctOptions[column] = possibleColumnOptions[0].options | ||||
|           } else if (possibleColumnOptions.length > 1) { | ||||
|             let filterInstance = this.gridApi.getFilterInstance(parentColumnName) | ||||
|             possibleColumnOptions.forEach((opt) => { | ||||
|               if (filterInstance && (opt.parentValue === filterInstance.filter)) { | ||||
|                 correctOptions[column] = opt.options | ||||
|               } | ||||
|             }) | ||||
|          } | ||||
|       } | ||||
|       this.gridApi.sizeColumnsToFit() | ||||
|  | ||||
|       this.setFilterOptions(correctOptions) | ||||
|     }, | ||||
|     handleReceiveTimeout () { | ||||
|       this.$toast.warning(`Not all rows were loaded. Please use more precise filtering`, { | ||||
|         position: "top-right", | ||||
|       }); | ||||
|       setTimeout(this.$toast.clear, 3000); | ||||
|       this.gridApi.hideOverlay(); | ||||
|     }, | ||||
|     handleAllReceived () { | ||||
|       this.gridApi.hideOverlay(); | ||||
|     }, | ||||
|     handleReceivePing () { | ||||
|       this.setLastPingReceived() | ||||
|     }, | ||||
|     doesExternalFilterPass(node) { | ||||
|       if (node.data && this.filterQuery.from && this.filterQuery.to) { | ||||
|         let ts = new Date(node.data['@timestamp']).getTime() | ||||
|         return (ts >= this.filterQuery.from && ts <= this.filterQuery.to) | ||||
|       } | ||||
|       return true; | ||||
|     }, | ||||
|     openExamineLog (row) { | ||||
|       const selectedRow = row.data | ||||
|       row.node.setSelected(false) | ||||
|       this.examineLog = true | ||||
|       const flattened = flattenObj(selectedRow) | ||||
|       const pairs = []; | ||||
|       Object.keys(flattened).map((key) => { | ||||
| @@ -282,5 +155,19 @@ export default { | ||||
|   }, | ||||
| } | ||||
|  | ||||
|  | ||||
| const flattenObj = (ob) => { | ||||
|   let result = {}; | ||||
|   for (const i in ob) { | ||||
|     if ((typeof ob[i]) === 'object' && !Array.isArray(ob[i])) { | ||||
|       const temp = flattenObj(ob[i]); | ||||
|       for (const j in temp) { | ||||
|         result[i + '.' + j] = temp[j]; | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       result[i] = ob[i]; | ||||
|     } | ||||
|   } | ||||
|   return result; | ||||
| }; | ||||
| </script> | ||||
|   | ||||
| @@ -1,155 +0,0 @@ | ||||
| <template> | ||||
|   <v-dialog | ||||
|       v-model="examineLog" | ||||
|       width="50wv" | ||||
|       @click.outside="close" | ||||
|       transition="false" | ||||
|   > | ||||
|     <v-card> | ||||
|       <v-card-text :style="{ height: gridHeight + 'px' }"> | ||||
|         <ag-grid-vue | ||||
|             v-if="examineLogContent" | ||||
|             style="width: 100%; height: 100%;" | ||||
|             class="ag-theme-material" | ||||
|             @grid-ready="onGridReady" | ||||
|             :columnDefs="columnDefs" | ||||
|             :row-data="examineLogContent.filter((val) => {return val.key !== 'screenshots'})" | ||||
|             :supress-horisontal-scroll="true" | ||||
|             :enable-scrolling="true" | ||||
|             :enableCellTextSelection="true" | ||||
|             :ensureDomOrder="true" | ||||
|             @cell-clicked="copyText" | ||||
|           ></ag-grid-vue> | ||||
|       </v-card-text> | ||||
|       <v-card-text v-if="screenshots.length"> | ||||
|         <h5>Screenshots</h5> | ||||
|         <br> | ||||
|         <viewer :images="screenshots" class="screenshots" :style="{ height: screenshotsHeight + 'px' }"> | ||||
|           <img v-for="screenshot in screenshots" :src="screenshot.orig"/> | ||||
|         </viewer> | ||||
|       </v-card-text> | ||||
|       <v-card-actions> | ||||
|         <v-btn color="primary" block @click="closeModal" transition="false">Close</v-btn> | ||||
|       </v-card-actions> | ||||
|     </v-card> | ||||
|   </v-dialog> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { AgGridVue } from "ag-grid-vue3"; | ||||
| import "ag-grid-community/styles//ag-grid.css"; | ||||
| import "ag-grid-community/styles//ag-theme-material.css"; | ||||
| import { VCard, VCardText, VCardActions } from 'vuetify/components/VCard' | ||||
| import { VDialog } from 'vuetify/components/VDialog' | ||||
| import { VBtn } from 'vuetify/components/VBtn' | ||||
| import { VTable } from 'vuetify/components/VTable' | ||||
| import ValueRenderer from "./ValueRenderer"; | ||||
|  | ||||
| export default { | ||||
|   name: "ExamineCamModal", | ||||
|   components: { | ||||
|     AgGridVue, | ||||
|     VCard, | ||||
|     VCardText, | ||||
|     VCardActions, | ||||
|     VBtn, | ||||
|     VDialog, | ||||
|     VTable, | ||||
|     ValueRenderer | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columnDefs:  [ | ||||
|         { | ||||
|           field: 'key', | ||||
|           sortable: true, | ||||
|           filter: 'agTextColumnFilter', | ||||
|           resizable: true, | ||||
|           width: 10, | ||||
|         }, | ||||
|         { | ||||
|           field: 'value', | ||||
|           sortable: true, | ||||
|           filter: 'agTextColumnFilter', | ||||
|           resizable: true, | ||||
|           cellRenderer: 'ValueRenderer' | ||||
|         }, | ||||
|       ], | ||||
|       screenshots: [] | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     examineLogContent: Array, | ||||
|     closeModal: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     examineLog() { | ||||
|       return !!this.examineLogContent | ||||
|     }, | ||||
|     gridHeight() { | ||||
|       const computed = ((this.examineLogContent ? this.examineLogContent.length : 0) + 1) * 50 | ||||
|       const max = window.innerHeight * 0.5 | ||||
|       const min = window.innerHeight * 0.2 | ||||
|       return (computed < max ? (computed > min ? computed : min) : max); | ||||
|     }, | ||||
|     screenshotsHeight() { | ||||
|       return (window.innerHeight * 0.8) - this.gridHeight | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     examineLogContent(content, oldContent) { | ||||
|       if (content && oldContent) { | ||||
|         return | ||||
|       } | ||||
|       let screenshots = this.examineLogContent && this.examineLogContent.find((elem) => { | ||||
|         return elem.key === 'screenshots' | ||||
|       }) || null | ||||
|       if (screenshots) { | ||||
|         let id = this.examineLogContent.find((elem) => { | ||||
|           return elem.key === '_id' | ||||
|         }).value | ||||
|         fetch('/events/details/' + id) | ||||
|             .then((response) => response.json()) | ||||
|             .then((response) => { | ||||
|               this.screenshots = response.screenshots | ||||
|             }); | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     onGridReady(params) { | ||||
|       params.api.sizeColumnsToFit() | ||||
|     }, | ||||
|     close (e) { | ||||
|       if (e.target.className === "v-overlay__scrim") { | ||||
|         this.closeModal() | ||||
|       } | ||||
|     }, | ||||
|     copyText(e) { | ||||
|       navigator.clipboard.writeText(e.value); | ||||
|       this.$toast.success(`Value copied to clipboard`, { | ||||
|         position: "top-right", | ||||
|       }); | ||||
|       setTimeout(this.$toast.clear, 3000); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| .screenshots { | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
|   flex-wrap: wrap; | ||||
|   overflow-y: auto; | ||||
|   height: 500px; | ||||
| } | ||||
| .screenshots img { | ||||
|   width: auto; | ||||
|   height: 150px; | ||||
|   cursor: pointer; | ||||
|   margin-right: 20px; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
| </style> | ||||
| @@ -1,27 +0,0 @@ | ||||
| import { VRow, VCol } from 'vuetify/components/VGrid' | ||||
| import 'ansi-to-html' | ||||
| import Convert from "ansi-to-html"; | ||||
|  | ||||
| export default { | ||||
|     template: `<v-row> | ||||
|       <v-col> | ||||
|         <span v-html="message"></span> | ||||
|       </v-col> | ||||
|     </v-row>`, | ||||
|     components: { | ||||
|         VRow, | ||||
|         VCol, | ||||
|     }, | ||||
|     setup(props) { | ||||
|         let message; | ||||
|         if (props.params.data.key === 'message') { | ||||
|             let parser = new Convert() | ||||
|             message = parser.toHtml(props.params.value) | ||||
|         } else { | ||||
|             message = props.params.value | ||||
|         } | ||||
|         return { | ||||
|             message | ||||
|         } | ||||
|     }, | ||||
| }; | ||||
| @@ -1,20 +1,30 @@ | ||||
| export default { | ||||
|     template: `<div>
 | ||||
|       <div class="screenshots-drawer"> | ||||
|         <img v-for="screenshot in screenshots" :src="screenshot.thumb"/> | ||||
|       <a @click="openDrawer">View screenshots</a> | ||||
|       <div v-if="drawerOpen" class="screenshots-drawer"> | ||||
|         <img v-for="screenshot in screenshots" :src="screenshot.orig"/> | ||||
|       </div> | ||||
|     </div>`, | ||||
|     data: function () { | ||||
|         return { | ||||
|             screenshots: [], | ||||
|             drawerOpen: false, | ||||
|         }; | ||||
|     }, | ||||
|     beforeMount() { | ||||
|         this.updateImage(this.params); | ||||
|         this.updateImage(this.params); | ||||
|     }, | ||||
|     methods: { | ||||
|         updateImage(params) { | ||||
|             this.screenshots = params.value | ||||
|             this.value = params.value; | ||||
|         }, | ||||
|         refresh(params) { | ||||
|             this.updateImage(params); | ||||
|         }, | ||||
|         openDrawer () { | ||||
|             this.drawerOpen = true | ||||
|         } | ||||
|     }, | ||||
| }; | ||||
| }; | ||||
| @@ -1,17 +0,0 @@ | ||||
| const flattenObj = (ob) => { | ||||
|     let result = {}; | ||||
|     for (const i in ob) { | ||||
|         if ((typeof ob[i]) === 'object' && !Array.isArray(ob[i])) { | ||||
|             const temp = flattenObj(ob[i]); | ||||
|             for (const j in temp) { | ||||
|                 result[i + '.' + j] = temp[j]; | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             result[i] = ob[i]; | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| }; | ||||
|  | ||||
| export default flattenObj; | ||||
| @@ -1,30 +0,0 @@ | ||||
| const parseEventData = (eventData) => { | ||||
|     try { | ||||
|         let json = JSON.parse(eventData) | ||||
|         let message; | ||||
|         if (json.json && json.json.message) { | ||||
|             message = json.json.message | ||||
|         } else if (json.message) { | ||||
|             message = json.message | ||||
|         } else if (json.json) { | ||||
|             message = JSON.stringify(json.json) | ||||
|         } | ||||
|         if (message) { | ||||
|             json.message = message | ||||
|         } | ||||
|         let level; | ||||
|         if (json.log && json.log.level) { | ||||
|             level = json.log.level | ||||
|         } else if (json.stream) { | ||||
|             level = json.stream === 'stderr' ? 'error' : 'info' | ||||
|         } | ||||
|         if (level) { | ||||
|             json.level = level | ||||
|         } | ||||
|         return json | ||||
|     } catch (e) { | ||||
|         console.error(e, eventData) | ||||
|     } | ||||
| }; | ||||
|  | ||||
| export default parseEventData; | ||||
							
								
								
									
										22
									
								
								src/main.js
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/main.js
									
									
									
									
									
								
							| @@ -1,26 +1,10 @@ | ||||
| import { createApp } from 'vue' | ||||
| import store from "./stores"; | ||||
| import App from './App.vue' | ||||
| import vuetify from './plugins/vuetify' | ||||
| import Toaster from "@meforma/vue-toaster"; | ||||
| import VCalendar from 'v-calendar'; | ||||
| import VueViewer from 'v-viewer' | ||||
| import { loadFonts } from './plugins/webfontloader' | ||||
| import './assets/main.css' | ||||
| import 'vue-select/dist/vue-select.css'; | ||||
| import 'v-calendar/dist/style.css'; | ||||
| import 'viewerjs/dist/viewer.css' | ||||
| loadFonts() | ||||
|  | ||||
| const app = createApp(App); | ||||
| app.use(store); | ||||
| app.use(vuetify); | ||||
| app.use(Toaster); | ||||
| app.use(VCalendar, {}); | ||||
| app.use(VueViewer, { | ||||
|     defaultOptions: { | ||||
|         zIndex: 9999 | ||||
|     } | ||||
| }) | ||||
| app.mount("#app"); | ||||
|  | ||||
| createApp(App) | ||||
|   .use(vuetify) | ||||
|   .mount('#app') | ||||
|   | ||||
| @@ -5,13 +5,11 @@ | ||||
|  */ | ||||
|  | ||||
| export async function loadFonts () { | ||||
|   const webFontLoader = await import('webfontloader') | ||||
|   const webFontLoader = await import(/* webpackChunkName: "webfontloader" */'webfontloader') | ||||
|  | ||||
|   webFontLoader.load({ | ||||
|     google: { | ||||
|       families: [ | ||||
|           'Montserrat', 'Roboto Mono', | ||||
|       ], | ||||
|       families: ['Roboto:100,300,400,500,700,900&display=swap'], | ||||
|     }, | ||||
|   }) | ||||
| } | ||||
|   | ||||
							
								
								
									
										14
									
								
								src/stores/counter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/stores/counter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| import { ref, computed } from 'vue' | ||||
| import { defineStore } from 'pinia' | ||||
|  | ||||
| export const useCounterStore = defineStore('counter', () => { | ||||
|   const count = ref(0) | ||||
|   const doubleCount = computed(() => count.value * 2) | ||||
|   function increment() { | ||||
|     count.value++ | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
|   return { count, doubleCount, increment } | ||||
| }) | ||||
| @@ -1,71 +0,0 @@ | ||||
| import { createStore } from "vuex" | ||||
|  | ||||
| const store = createStore({ | ||||
|   state: { | ||||
|     filterOptions: {}, | ||||
|     filterQuery: {}, | ||||
|     lastPingReceived: null, | ||||
|   }, | ||||
|   getters: { | ||||
|     streaming (state) { | ||||
|       return state.filterQuery['streaming'] ?? false | ||||
|     }, | ||||
|     filterQuery (state) { | ||||
|       return state.filterQuery | ||||
|     }, | ||||
|     lastPingReceived (state) { | ||||
|       return state.lastPingReceived | ||||
|     }, | ||||
|   }, | ||||
|   actions: { | ||||
|     setFilterOptions(context, payload) { | ||||
|       context.commit("SET_FILTER_OPTIONS", payload); | ||||
|     }, | ||||
|     setFilterQuery(context, payload) { | ||||
|       context.commit("SET_FILTER_QUERY", payload); | ||||
|     }, | ||||
|     toggleFilterQueryStreaming(context) { | ||||
|       context.commit("TOGGLE_FILTER_QUERY_STREAMING"); | ||||
|     }, | ||||
|     setFilterQueryTimeRange({commit, state}, {from, to}) { | ||||
|       let query = state.filterQuery | ||||
|       query.from = from | ||||
|       query.to = to | ||||
|       query.streaming = false | ||||
|       commit("SET_FILTER_QUERY", query); | ||||
|     }, | ||||
|     setLastPingReceived(context) { | ||||
|       context.commit("SET_LAST_PING_RECEIVED"); | ||||
|     }, | ||||
|   }, | ||||
|   mutations: { | ||||
|     SET_FILTER_OPTIONS(state, payload) { | ||||
|       state.filterOptions = payload | ||||
|     }, | ||||
|     SET_FILTER_QUERY(state, payload) { | ||||
|       let query = payload | ||||
|       if (Object.keys(state.filterOptions).length) { | ||||
|         query['initial'] = false | ||||
|       } | ||||
|       state.filterQuery = query | ||||
|     }, | ||||
|     TOGGLE_FILTER_QUERY_STREAMING(state) { | ||||
|       let query = state.filterQuery | ||||
|       let streaming = (query['streaming'] === undefined) ? false : query['streaming'] | ||||
|       query['streaming'] = !(streaming) | ||||
|       query['initial'] = false | ||||
|  | ||||
|       if (!streaming) { | ||||
|         delete query['from'] | ||||
|         delete query['to'] | ||||
|       } | ||||
|  | ||||
|       state.filterQuery = query | ||||
|     }, | ||||
|     SET_LAST_PING_RECEIVED(state) { | ||||
|       state.lastPingReceived = (new Date()).getTime() | ||||
|     } | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| export default store | ||||
| @@ -1,12 +1,9 @@ | ||||
| import vue from '@vitejs/plugin-vue' | ||||
| import dynamicImport from 'vite-plugin-dynamic-import' | ||||
| import * as path from "path"; | ||||
|  | ||||
| export default { | ||||
|   resolve: { | ||||
|     alias: { | ||||
|       vue: 'vue/dist/vue.esm-bundler.js', | ||||
|       '@': path.join(__dirname, 'src/components/Grid/Main/configs'), | ||||
|       vue: 'vue/dist/vue.esm-bundler.js' | ||||
|     } | ||||
|   }, | ||||
|   rollupOptions: { | ||||
| @@ -14,24 +11,16 @@ export default { | ||||
|     format: 'system', | ||||
|     preserveEntrySignatures: true | ||||
|   }, | ||||
|   plugins: [ | ||||
|       vue({ | ||||
|         template: { | ||||
|           transformAssetUrls: { | ||||
|             base: '/src' | ||||
|           } | ||||
|         }, | ||||
|       }), | ||||
|       dynamicImport(/* options */) | ||||
|   ], | ||||
|   plugins: [vue({ | ||||
|     template: { | ||||
|       transformAssetUrls: { | ||||
|         base: '/src' | ||||
|       } | ||||
|     } | ||||
|   })], | ||||
|   pluginOptions: { | ||||
|     vuetify: { | ||||
|       // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader | ||||
|     } | ||||
|   }, | ||||
|   optimizeDeps: { | ||||
|     exclude: [ | ||||
|       "@meforma/vue-toaster" | ||||
|     ] | ||||
|   }, | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user