Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
5111897b78 | |||
be79d178ff | |||
97ad29ade0 | |||
f31951c478 | |||
d0c4272f51 | |||
eeb104ee60 | |||
a51fc71990 | |||
c2f53a4703 | |||
3141586477 | |||
c5a76c28ad | |||
b02b20528a | |||
1a89440624 | |||
fb7d8fdd37 | |||
a014b0b531 | |||
693ab863c2 | |||
dde5a13550 | |||
3326e0e9e3 | |||
845773f3f1 | |||
d4052f03a1 | |||
c9cf7ae603 | |||
b2439a7a49 | |||
274620c994 | |||
26e79bbb20 | |||
4b8591f51e | |||
cfcd17d45e | |||
|
7797eb9210 | ||
6cb78c657f | |||
b6f21b8192 | |||
5fe7f45728 | |||
23471d5bb3 |
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@ -0,0 +1,17 @@
|
||||
.kpt-pipeline/
|
||||
k8s/
|
||||
skaffold.yaml
|
||||
README.md
|
||||
.git/
|
||||
node_modules/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.kpt-pipeline
|
12
.drone.yml
12
.drone.yml
@ -5,10 +5,12 @@ name: default
|
||||
|
||||
steps:
|
||||
- name: backend
|
||||
image: harbor.k-space.ee/k-space/drone-kaniko
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: ${DRONE_REPO}
|
||||
repo: harbor.k-space.ee/${DRONE_REPO}
|
||||
registry: harbor.k-space.ee
|
||||
mtu: 1300
|
||||
storage_driver: vfs
|
||||
context: backend/
|
||||
dockerfile: backend/Dockerfile
|
||||
username:
|
||||
@ -16,10 +18,12 @@ steps:
|
||||
password:
|
||||
from_secret: docker_password
|
||||
- name: frontend
|
||||
image: harbor.k-space.ee/k-space/drone-kaniko
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: ${DRONE_REPO}-frontend
|
||||
repo: harbor.k-space.ee/${DRONE_REPO}-frontend
|
||||
registry: harbor.k-space.ee
|
||||
mtu: 1300
|
||||
storage_driver: vfs
|
||||
context: frontend/
|
||||
dockerfile: frontend/Dockerfile
|
||||
username:
|
||||
|
@ -1,5 +1,5 @@
|
||||
# pull official node image
|
||||
FROM node
|
||||
FROM node AS dev
|
||||
|
||||
# define /app as working directory
|
||||
WORKDIR /app
|
||||
@ -13,4 +13,8 @@ RUN npm install
|
||||
COPY . /app
|
||||
|
||||
# launch node server
|
||||
ENTRYPOINT node server.js
|
||||
ENTRYPOINT npm run dev
|
||||
|
||||
# production
|
||||
FROM dev AS prod
|
||||
ENTRYPOINT npm run start
|
640
backend/package-lock.json
generated
640
backend/package-lock.json
generated
@ -13,6 +13,9 @@
|
||||
"express": "^4.17.2",
|
||||
"minio": "^7.0.26",
|
||||
"mongodb": "^4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.20"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
@ -40,6 +43,12 @@
|
||||
"integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
@ -52,6 +61,19 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
@ -89,6 +111,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@ -108,6 +136,15 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/block-stream2": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz",
|
||||
@ -141,6 +178,28 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/brorand": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||
@ -269,6 +328,33 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
@ -278,6 +364,12 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -609,6 +701,18 @@
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
@ -647,6 +751,20 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
@ -680,6 +798,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
@ -699,6 +829,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
@ -801,6 +940,12 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@ -858,6 +1003,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-boolean-object": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
|
||||
@ -898,6 +1055,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-generator-function": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
|
||||
@ -912,6 +1078,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-negative-zero": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
|
||||
@ -923,6 +1101,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number-object": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
|
||||
@ -1121,6 +1308,18 @@
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
@ -1210,6 +1409,73 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "2.0.20",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
|
||||
"integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^3.2.7",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^5.7.1",
|
||||
"simple-update-notifier": "^1.0.7",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@ -1302,6 +1568,18 @@
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@ -1314,6 +1592,12 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
|
||||
@ -1412,6 +1696,18 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
@ -1462,6 +1758,15 @@
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.17.2",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
|
||||
@ -1534,6 +1839,27 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz",
|
||||
"integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"semver": "~7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier/node_modules/semver": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
|
||||
"integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
@ -1610,6 +1936,18 @@
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
|
||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/through2": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
|
||||
@ -1619,6 +1957,18 @@
|
||||
"readable-stream": "2 || 3"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@ -1627,6 +1977,18 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
|
||||
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"nopt": "~1.0.10"
|
||||
},
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
|
||||
@ -1664,6 +2026,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
@ -1823,6 +2191,12 @@
|
||||
"integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
|
||||
"optional": true
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
@ -1832,6 +2206,16 @@
|
||||
"negotiator": "0.6.2"
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
@ -1865,11 +2249,23 @@
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
||||
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw=="
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"block-stream2": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz",
|
||||
@ -1900,6 +2296,25 @@
|
||||
"type-is": "~1.6.18"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"brorand": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||
@ -2005,6 +2420,22 @@
|
||||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
}
|
||||
},
|
||||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
@ -2014,6 +2445,12 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -2299,6 +2736,15 @@
|
||||
"strnum": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
@ -2328,6 +2774,13 @@
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
@ -2352,6 +2805,15 @@
|
||||
"get-intrinsic": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
@ -2365,6 +2827,12 @@
|
||||
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
|
||||
"integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
@ -2432,6 +2900,12 @@
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"dev": true
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@ -2474,6 +2948,15 @@
|
||||
"has-bigints": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-boolean-object": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
|
||||
@ -2496,6 +2979,12 @@
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-generator-function": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
|
||||
@ -2504,11 +2993,26 @@
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"is-negative-zero": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
|
||||
"integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"is-number-object": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
|
||||
@ -2652,6 +3156,15 @@
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
@ -2726,6 +3239,56 @@
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||
},
|
||||
"nodemon": {
|
||||
"version": "2.0.20",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
|
||||
"integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^3.2.7",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^5.7.1",
|
||||
"simple-update-notifier": "^1.0.7",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"abbrev": "1"
|
||||
}
|
||||
},
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@ -2794,6 +3357,12 @@
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@ -2803,6 +3372,12 @@
|
||||
"ipaddr.js": "1.9.1"
|
||||
}
|
||||
},
|
||||
"pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"dev": true
|
||||
},
|
||||
"public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
|
||||
@ -2881,6 +3456,15 @@
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
@ -2914,6 +3498,12 @@
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"send": {
|
||||
"version": "0.17.2",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
|
||||
@ -2976,6 +3566,23 @@
|
||||
"object-inspect": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"simple-update-notifier": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz",
|
||||
"integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "~7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
|
||||
"integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
@ -3035,6 +3642,15 @@
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
|
||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"through2": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
|
||||
@ -3044,11 +3660,29 @@
|
||||
"readable-stream": "2 || 3"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
|
||||
},
|
||||
"touch": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
|
||||
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nopt": "~1.0.10"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
|
||||
@ -3077,6 +3711,12 @@
|
||||
"which-boxed-primitive": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"dev": true
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
|
@ -5,8 +5,8 @@
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node server.js",
|
||||
"build": "cd frontend && npm install && npm run build"
|
||||
"dev": "nodemon server.js -e ejs,js,css,html,jpg,png,scss",
|
||||
"prod": "node.js server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@ -16,5 +16,8 @@
|
||||
"express": "^4.17.2",
|
||||
"minio": "^7.0.26",
|
||||
"mongodb": "^4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.20"
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,12 @@
|
||||
const { MongoClient } = require("mongodb");
|
||||
const { MongoClient, MongoClientOptions } = require("mongodb");
|
||||
const express = require('express');
|
||||
const minio = require('minio');
|
||||
|
||||
/*============== VARIABLE DECLARATION ==============*/
|
||||
// Mongo set-up variables
|
||||
const mongoCollection = process.env.MONGO_COLLECTION || 'eventlog';
|
||||
const mongoUri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/default?replicaSet=rs0';
|
||||
const mongoCollection = process.env.MONGO_COLLECTION || 'log';
|
||||
const mongoUri = process.env.MONGODB_HOST || 'mongodb://127.0.0.1:27017/default?replicaSet=rs0';
|
||||
|
||||
// Minio set-up variables
|
||||
const minioAccessKey = process.env.MINIO_ACCESS_KEY || 'kspace-mugshot';
|
||||
const minioSecretKey = process.env.MINIO_SECRET_KEY || '2mSI6HdbJ8';
|
||||
const minioHostname = process.env.MINIO_HOSTNAME || '127.0.0.1';
|
||||
const minioPort = process.env.MINIO_PORT || 9000;
|
||||
const minioScheme = process.env.MINIO_SCHEME || 'http';
|
||||
const minioBucket = process.env.MINIO_BUCKET || 'kspace-mugshot';
|
||||
console.info("Using bucket:", minioBucket);
|
||||
const historyNumber = parseInt(process.env.HISTORY_AMOUNT) || 10;
|
||||
const historyNumber = parseInt(process.env.HISTORY_AMOUNT) || 50;
|
||||
|
||||
// Stream set-up variables
|
||||
let changeStream;
|
||||
@ -24,8 +15,10 @@ const pipeline = [];
|
||||
const PORT = process.env.PORT || 3002;
|
||||
|
||||
// Create Mongo client
|
||||
const mongoClient = new MongoClient(mongoUri);
|
||||
|
||||
const mongoOptions = {
|
||||
readPreference: 'secondaryPreferred'
|
||||
}
|
||||
const mongoClient = new MongoClient(mongoUri, mongoOptions);
|
||||
|
||||
/*============== CODE ==============*/
|
||||
async function run() {
|
||||
@ -38,63 +31,47 @@ async function run() {
|
||||
|
||||
changeStream = collection.watch(pipeline, options);
|
||||
console.log("Started watching changes in database");
|
||||
console.log("Minio hostname:", minioHostname);
|
||||
console.log("Minio port:", minioPort);
|
||||
console.log("Minio protocol:", minioScheme);
|
||||
|
||||
const filterOptions = {
|
||||
'kubernetes.namespace': await collection.distinct('kubernetes.namespace'),
|
||||
'kubernetes.pod.name': await collection.distinct('kubernetes.pod.name'),
|
||||
'kubernetes.container.name': await collection.distinct('kubernetes.container.name')
|
||||
}
|
||||
|
||||
const writeMessage = (response, blob) => {
|
||||
const id = blob._id || null
|
||||
const message = `id: ${id}\nevent: message\ndata: ${JSON.stringify(blob)}\n\n`
|
||||
response.write(message)
|
||||
}
|
||||
|
||||
// Triggers on GET at /event route
|
||||
app.get('/events', async function (request, response) {
|
||||
let minioClient = new minio.Client({
|
||||
endPoint: minioHostname,
|
||||
port: parseInt(minioPort),
|
||||
useSSL: minioScheme == 'https',
|
||||
accessKey: minioAccessKey,
|
||||
secretKey: minioSecretKey
|
||||
});
|
||||
|
||||
async function wrapEvent(doc) {
|
||||
let arr = [];
|
||||
let blob;
|
||||
if (doc && doc.screenshot_count) {
|
||||
for (let i = 1; i <= doc.screenshot_count ; i++) {
|
||||
arr.push({
|
||||
url: await minioClient.presignedUrl('GET', minioBucket,
|
||||
`${doc.camera}/${doc._id}/${i}.jpg`, 60 * 60)
|
||||
});
|
||||
}
|
||||
} else if (doc && doc.screenshots) {
|
||||
for (let j = 0; j < doc.screenshots.length; j++) {
|
||||
let path = doc.screenshots[j];
|
||||
arr.push({
|
||||
url: await minioClient.presignedUrl('GET', minioBucket,
|
||||
`thumb/${path}`, 60 * 60),
|
||||
orig: await minioClient.presignedUrl('GET', minioBucket,
|
||||
`${path}`, 60 * 60)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (arr.length > 0) {
|
||||
blob = JSON.stringify({...doc, screenshots: [...arr]});
|
||||
} else {
|
||||
blob = JSON.stringify({...doc});
|
||||
}
|
||||
return `event: log-entry\ndata: ${blob}\n\n`
|
||||
}
|
||||
|
||||
// Notify SSE to React
|
||||
// Notify SSE to React
|
||||
const header = { 'Content-Type': 'text/event-stream', 'Connection': 'keep-alive' };
|
||||
response.writeHead(200, "OK", header);
|
||||
|
||||
const historyCursor = collection.find().sort({$natural:-1}).limit(historyNumber);
|
||||
const message = `id: 1\nevent: filters\ndata: ${JSON.stringify(filterOptions)}\n\n`
|
||||
response.write(message)
|
||||
|
||||
historyCursor.forEach(async (document) => {
|
||||
response.write(await wrapEvent(document));
|
||||
const historyCursor = collection.find()
|
||||
.sort({$natural:-1})
|
||||
.limit(historyNumber).toArray().then((res) => {
|
||||
res.reverse().forEach((document) => {
|
||||
writeMessage(response, document)
|
||||
})
|
||||
});
|
||||
|
||||
const changeListener = async (change) => {
|
||||
// Ignore events without fullDocument, e.g. deletes.
|
||||
if (change.fullDocument) {
|
||||
writeMessage(response, change.fullDocument)
|
||||
}
|
||||
}
|
||||
changeStream.on("change", changeListener);
|
||||
response.on('close', () => {
|
||||
changeStream.removeListener("change", changeListener)
|
||||
})
|
||||
|
||||
changeStream.on("change", async(data) => {
|
||||
response.write(await wrapEvent(data.fullDocument));
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(PORT);
|
||||
|
@ -1,5 +1,17 @@
|
||||
./node_modules
|
||||
./build
|
||||
.git
|
||||
*.md
|
||||
.gitignore
|
||||
.kpt-pipeline/
|
||||
k8s/
|
||||
skaffold.yaml
|
||||
README.md
|
||||
.git/
|
||||
node_modules/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.kpt-pipeline
|
||||
|
29
frontend/.gitignore
vendored
Normal file
29
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.kpt-pipeline
|
@ -1,39 +1,22 @@
|
||||
# pull official base image
|
||||
FROM node AS builder
|
||||
FROM node AS dev
|
||||
|
||||
# set working directory
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
|
||||
|
||||
# install app dependencies
|
||||
#copies package.json and package-lock.json to Docker environment
|
||||
COPY package.json ./
|
||||
|
||||
# Installs all node packages
|
||||
COPY package* ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT ["npm", "run", "dev"]
|
||||
|
||||
# Copies everything over to Docker environment
|
||||
COPY . ./
|
||||
# builder
|
||||
FROM dev AS builder
|
||||
RUN npm run build
|
||||
|
||||
#Stage 2
|
||||
#######################################
|
||||
#pull the official nginx:1.19.0 base image
|
||||
FROM nginx
|
||||
|
||||
#copies React to the container directory
|
||||
# Set working directory to nginx resources directory
|
||||
# serve
|
||||
FROM nginx AS prod
|
||||
WORKDIR /usr/share/nginx/html
|
||||
# Remove default nginx static resources
|
||||
RUN rm -rf ./*
|
||||
RUN apt-get install bash
|
||||
|
||||
# Copies configuration files
|
||||
COPY ./default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copies static resources from builder stage
|
||||
COPY --from=builder /app/build .
|
||||
|
||||
# Containers run nginx with global directives and daemon off
|
||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=builder /app/dist .
|
||||
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
67
frontend/README.md
Normal file
67
frontend/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
# log-viewer microfrontend (WIP)
|
||||
This is an experimental microfrontend to view logs coming from camtiler, testing microfrontends concept and developing
|
||||
Javascript/Node application directly on Kubernetes cluster using Skaffold (hot-reloading source files works!)
|
||||
|
||||
Currently the application itself is a really minimalistic frontend based on Vue.js 3 framework.
|
||||
|
||||
## Getting started
|
||||
0. Have access with kubectl to desired Kubernetes cluster
|
||||
0. Have local Docker daemon ready along with access to your image registry (building in-cluster with Kaniko is currently not tested)
|
||||
1. Get Skaffold 2.0.0-beta*: https://github.com/GoogleContainerTools/skaffold/releases
|
||||
2. Run `skaffold dev --namespace {desired K8S namespace}`
|
||||
|
||||
And you should be good to go. Skaffold would create a deployment, build the container and upload it to your registry
|
||||
and deploy it.
|
||||
|
||||
## Good to know
|
||||
### Skaffold
|
||||
All Skaffold configuration is in skaffold.yml. There we have:
|
||||
1. App/deployment name (metadata)
|
||||
2. Build artifacts - artifact that Skaffold would build and use, either in case of development or also actual deploy
|
||||
3. Profiles - similar to `npm` commands/profiles, you can have many different actions (run `skaffold {action}`).
|
||||
We only have `dev` which will build and deploy the `log-viewer-frontend` container
|
||||
(in manner how it's defined in Kubernetes manifest), and then enable `manual sync`, which defines which
|
||||
changed files will be copied to the container when it's running - change in everything else will trigger
|
||||
rebuilding the container.
|
||||
|
||||
### Hot-reload vs rebuilding the container
|
||||
Currently the files that will be copied are fine-tuned as they are known to work well with Vue.js hot-reload feature
|
||||
(eg actual frontend code). Other files, such as framework configuration files (`vite.config.js`, `vue.config.js`)
|
||||
will trigger rebuilding and more importantly, restarting the container, to provide stability. It might not be necessary
|
||||
to restart the container, this is just testing at this point. You can try it by introducing less explicit `sync`
|
||||
config in `skaffold.yml`.
|
||||
|
||||
Change in `packages*` files will also trigger rebuilding and restarting the container, with the difference of
|
||||
caching the result of the `npm install` command - `node_modules` directory. So in case of changing framework config,
|
||||
the container will be quickly rebuilt and restarted, but when changing packages in `package.json`, `npm install`
|
||||
will also be ran when re-building the container.
|
||||
|
||||
### Dockerfile
|
||||
This is a really simple Dockerfile based on the official Node Docker image.
|
||||
Only extra stuff it does is:
|
||||
1. exposing the port for reference
|
||||
2. changing workdir(?)
|
||||
3. running `npm install` on-demand
|
||||
4. copying other code into the container
|
||||
5. defining the run command (important!)
|
||||
|
||||
We also have the `.dockerignore` to filter out files that never need to make into the container, such as IDE
|
||||
metadata directories, Git, readme etc.
|
||||
|
||||
With the current config, your local Docker daemon will be used to build the image and upload it to your image registry.
|
||||
Building in-cluster with Kaniko should be supported (https://skaffold.dev/docs/pipeline-stages/builders/docker/)
|
||||
but currently not tested.
|
||||
|
||||
### Kubernetes
|
||||
The Kubernetes manifest(s) are supposed to be in the `k8s/` directory.
|
||||
Skaffold will pick them up automatically from there, apply them (also cleaning up after itself),
|
||||
and match the container images from it's manifest and Kubernetes manifest, so it knows when to make the Kubernetes
|
||||
redeploy the image.
|
||||
|
||||
Here we have a simple deployment, where `https://playground.k-space.ee/` takes us to the (development) frontend
|
||||
container and `https://playground.k-space.ee/events` gets data from the `camtiler log-backend`.
|
||||
|
||||
The actual production usage may vary a lot in case of frontend - one would usually not run a
|
||||
Node.js server to serve frontend assets, unless it's a SSR frontend (Nuxt, Next frameworks).
|
||||
But for Node.js backends, it's pretty close to the standard.
|
||||
|
@ -1,16 +0,0 @@
|
||||
server {
|
||||
listen 3003;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location /events {
|
||||
proxy_buffering off;
|
||||
proxy_pass http://127.0.0.1:3002/events;
|
||||
}
|
||||
|
||||
|
||||
}
|
13
frontend/index.html
Normal file
13
frontend/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Log Viewer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
9
frontend/nginx.conf
Normal file
9
frontend/nginx.conf
Normal file
@ -0,0 +1,9 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
}
|
27815
frontend/package-lock.json
generated
27815
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,40 +1,31 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.1",
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-hooks-sse": "^2.0.0",
|
||||
"react-scripts": "5.0.0",
|
||||
"web-vitals": "^2.1.3"
|
||||
},
|
||||
"name": "@k-space/log-viewer",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vite build",
|
||||
"dev": "vite --port 8080 --host",
|
||||
"preview": "vite preview --port 3003"
|
||||
},
|
||||
"proxy": "http://localhost:3002",
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
"dependencies": {
|
||||
"@ag-grid-community/core": "^28.2.0",
|
||||
"@mdi/font": "5.9.55",
|
||||
"@vue/cli-service": "^5.0.8",
|
||||
"ag-grid-vue3": "^28.2.0",
|
||||
"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",
|
||||
"vue": "^3.2.39",
|
||||
"vuetify": "^3.0.0-beta.0",
|
||||
"webfontloader": "^1.0.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^3.0.3",
|
||||
"vite": "^3.0.9",
|
||||
"vue-cli-plugin-vuetify": "~2.5.8",
|
||||
"webpack-plugin-vuetify": "^2.0.0-alpha.0"
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.2 KiB |
@ -1,41 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="Event logging"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>Event log</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.4 KiB |
@ -1,25 +0,0 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
15
frontend/src/App.vue
Normal file
15
frontend/src/App.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<script setup>
|
||||
import LogViewer from './components/LogViewer.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LogViewer />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app1',
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
</style>
|
1
frontend/src/assets/logo.svg
Normal file
1
frontend/src/assets/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
After Width: | Height: | Size: 308 B |
15
frontend/src/assets/main.css
Normal file
15
frontend/src/assets/main.css
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
div#app {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.screenshots-drawer {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ag-theme-material {
|
||||
--ag-value-change-value-highlight-background-color: #f9ff99;
|
||||
}
|
29
frontend/src/components/ComboboxFilter.js
Normal file
29
frontend/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 !== ''
|
||||
},
|
||||
},
|
||||
};
|
83
frontend/src/components/ExamineLogModal.vue
Normal file
83
frontend/src/components/ExamineLogModal.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<v-dialog
|
||||
v-model="examineLog"
|
||||
width="50wv"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-text style="height: 70vh">
|
||||
<ag-grid-vue
|
||||
style="width: 100%; height: 100%;"
|
||||
class="ag-theme-material"
|
||||
@grid-ready="onGridReady"
|
||||
:columnDefs="columnDefs"
|
||||
:row-data="examineLogContent"
|
||||
:supress-horisontal-scroll="true"
|
||||
:enable-scrolling="true"
|
||||
:enableCellTextSelection="true"
|
||||
:ensureDomOrder="true"
|
||||
></ag-grid-vue>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" block @click="closeModal">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 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'
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AgGridVue,
|
||||
VCard,
|
||||
VCardText,
|
||||
VCardActions,
|
||||
VBtn,
|
||||
VDialog,
|
||||
VTable,
|
||||
ScreenshotCell: ScreenshotCell
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columnDefs: [
|
||||
{
|
||||
field: 'key',
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
field: 'value',
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
resizable: true
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
props: {
|
||||
examineLogContent: Array,
|
||||
closeModal: Function
|
||||
},
|
||||
computed: {
|
||||
examineLog() {
|
||||
return !!this.examineLogContent
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onGridReady(params) {
|
||||
params.api.sizeColumnsToFit()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
173
frontend/src/components/LogViewer.vue
Normal file
173
frontend/src/components/LogViewer.vue
Normal file
@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<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"
|
||||
:pagination="true"
|
||||
:paginationAutoPageSize=true
|
||||
:row-data="null"
|
||||
row-selection="single"
|
||||
:onRowSelected="openExamineLog"
|
||||
:supress-horisontal-scroll="true"
|
||||
:enable-scrolling="true"
|
||||
></ag-grid-vue>
|
||||
<ExamineLogModal :examine-log-content="examineLogContent" :close-modal="closeExamineLog" />
|
||||
</div>
|
||||
</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 ScreenshotCell from "./ScreenshotCell.js";
|
||||
import ExamineLogModal from "./ExamineLogModal.vue";
|
||||
import ComboboxFilter from "./ComboboxFilter.js";
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ExamineLogModal,
|
||||
AgGridVue,
|
||||
ComboboxFilter,
|
||||
ScreenshotCell: ScreenshotCell
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
examineLogContent: null,
|
||||
gridApi: null,
|
||||
gridColumnApi: null,
|
||||
defaultColDef: {
|
||||
width: 50,
|
||||
initialPinned: true,
|
||||
resizable: true,
|
||||
enableCellChangeFlash: true
|
||||
},
|
||||
currentRowCount: 0,
|
||||
comboBoxOptions: {},
|
||||
viewRowCount: 20,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
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() {
|
||||
this.setupStream()
|
||||
},
|
||||
methods: {
|
||||
setupStream() {
|
||||
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;
|
||||
},
|
||||
handleReceiveMessage (event) {
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
},
|
||||
openExamineLog (row) {
|
||||
const selectedRow = row.data
|
||||
row.node.setSelected(false)
|
||||
this.examineLog = true
|
||||
const flattened = flattenObj(selectedRow)
|
||||
const pairs = [];
|
||||
Object.keys(flattened).map((key) => {
|
||||
pairs.push({
|
||||
key: key,
|
||||
value: flattened[key]
|
||||
})
|
||||
})
|
||||
this.examineLogContent = pairs
|
||||
},
|
||||
closeExamineLog () {
|
||||
this.examineLogContent = null
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
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>
|
30
frontend/src/components/ScreenshotCell.js
Normal file
30
frontend/src/components/ScreenshotCell.js
Normal file
@ -0,0 +1,30 @@
|
||||
export default {
|
||||
template: `<div>
|
||||
<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,3 +0,0 @@
|
||||
body {
|
||||
background-color: #eafaf9;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useSSE, SSEProvider } from 'react-hooks-sse';
|
||||
import './App.css';
|
||||
import EventList from '../eventList/EventList.js';
|
||||
|
||||
|
||||
import './App.css';
|
||||
|
||||
|
||||
const Component = () => {
|
||||
const event = useSSE('log-entry')
|
||||
const [events, setEvents] = useState([])
|
||||
|
||||
useEffect(() =>{
|
||||
console.info(event);
|
||||
if (event) {
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
if (events[j].timestamp <= event.timestamp) {
|
||||
if (events[j]._id == event._id) {
|
||||
setEvents([...events.slice(0, j), event, ...events.slice(j+1)]);
|
||||
return;
|
||||
} else {
|
||||
setEvents([...events.slice(0, j), event, ...events.slice(j)]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setEvents([event, ...events]);
|
||||
}
|
||||
}, [event])
|
||||
return <EventList data={events} />
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
||||
<SSEProvider endpoint="/events" >
|
||||
<Component />
|
||||
|
||||
|
||||
</SSEProvider>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default App;
|
@ -1,18 +0,0 @@
|
||||
.eventDiv {
|
||||
background-color: aliceblue;
|
||||
border: 2px solid #26A69A;
|
||||
border-radius: 15px;
|
||||
text-align: left;
|
||||
padding: 5px;
|
||||
max-width: fit-content;
|
||||
font-family: apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||
color: #092a26;
|
||||
margin: 7px 0px;
|
||||
}
|
||||
|
||||
.eventPic {
|
||||
border-radius: 15px;
|
||||
border: 1px groove #d5f6f2;
|
||||
max-width:100%;
|
||||
max-height:100%;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import React from "react";
|
||||
import "./Event.css";
|
||||
|
||||
function Event(props) {
|
||||
|
||||
let imgArray = [];
|
||||
|
||||
if (props.data.hasOwnProperty('screenshots')) {
|
||||
props.data.screenshots.forEach(element => {
|
||||
imgArray = [...imgArray, (<a href={element.orig} target="_blank"><img src={element.url} className="eventPic"></img></a>)]
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="eventDiv">
|
||||
{JSON.stringify(props.data.source)}
|
||||
<br></br>
|
||||
{[...imgArray]}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Event;
|
@ -1,11 +0,0 @@
|
||||
.eventListUl {
|
||||
background-color: #c1f1ec;
|
||||
max-width: 75%;
|
||||
padding: 5px;
|
||||
border: 5px solid #26A69A;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.eventListLi {
|
||||
list-style: none;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import React from 'react';
|
||||
import Event from '../event/Event.js';
|
||||
import './EventList.css';
|
||||
|
||||
function EventList(props) {
|
||||
return (
|
||||
<ul className="eventListUl">
|
||||
{props.data.map((event) => {
|
||||
return <li className="eventListLi"><Event data={event} /></li>
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default EventList;
|
@ -1,3 +0,0 @@
|
||||
body {
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './components/app/App.js';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
10
frontend/src/main.js
Normal file
10
frontend/src/main.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import vuetify from './plugins/vuetify'
|
||||
import { loadFonts } from './plugins/webfontloader'
|
||||
import './assets/main.css'
|
||||
loadFonts()
|
||||
|
||||
createApp(App)
|
||||
.use(vuetify)
|
||||
.mount('#app')
|
@ -1,13 +0,0 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
3
frontend/src/set-public-path.js
Normal file
3
frontend/src/set-public-path.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { setPublicPath } from "systemjs-webpack-interop";
|
||||
|
||||
setPublicPath("app1");
|
@ -1,5 +0,0 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
14
frontend/src/stores/counter.js
Normal file
14
frontend/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 }
|
||||
})
|
26
frontend/vite.config.js
Normal file
26
frontend/vite.config.js
Normal file
@ -0,0 +1,26 @@
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default {
|
||||
resolve: {
|
||||
alias: {
|
||||
vue: 'vue/dist/vue.esm-bundler.js'
|
||||
}
|
||||
},
|
||||
rollupOptions: {
|
||||
input: 'src/main.js',
|
||||
format: 'system',
|
||||
preserveEntrySignatures: true
|
||||
},
|
||||
plugins: [vue({
|
||||
template: {
|
||||
transformAssetUrls: {
|
||||
base: '/src'
|
||||
}
|
||||
}
|
||||
})],
|
||||
pluginOptions: {
|
||||
vuetify: {
|
||||
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader
|
||||
}
|
||||
}
|
||||
}
|
43
frontend/vue.config.js
Normal file
43
frontend/vue.config.js
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const EventHooksPlugin = require('event-hooks-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
publicPath: '/logs',
|
||||
chainWebpack: (config) => {
|
||||
config.devServer.headers({
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
});
|
||||
config.devServer.set('port', 8080);
|
||||
config.devServer.set('hot', true);
|
||||
|
||||
config.output.filename('[name].js');
|
||||
config.output.publicPath('/logs');
|
||||
|
||||
config.externals([
|
||||
'vue',
|
||||
'vue-router'
|
||||
]);
|
||||
},
|
||||
lintOnSave: true,
|
||||
filenameHashing: false,
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
new EventHooksPlugin({
|
||||
done: () => {
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
const buildDir = path.join(__dirname, '/dist');
|
||||
fs.unlinkSync(`${buildDir}/index.html`);
|
||||
}
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
|
||||
pluginOptions: {
|
||||
vuetify: {
|
||||
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader
|
||||
}
|
||||
}
|
||||
};
|
102
k8s/dev/deployment.yaml
Normal file
102
k8s/dev/deployment.yaml
Normal file
@ -0,0 +1,102 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: playground
|
||||
annotations:
|
||||
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.k-space.ee
|
||||
spec:
|
||||
rules:
|
||||
- host: playground.k-space.ee
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: log-viewer-frontend
|
||||
port:
|
||||
number: 8080
|
||||
- pathType: Prefix
|
||||
path: "/events"
|
||||
backend:
|
||||
service:
|
||||
name: log-viewer-backend
|
||||
port:
|
||||
number: 3002
|
||||
tls:
|
||||
- hosts:
|
||||
- playground.k-space.ee
|
||||
secretName: playground-tls
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: log-viewer-frontend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: log-viewer-frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: log-viewer-backend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: log-viewer-backend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 3002
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: log-viewer-frontend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: log-viewer-frontend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: log-viewer-frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: log-viewer-frontend
|
||||
image: harbor.k-space.ee/playground/log-viewer-frontend
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: log-viewer-backend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: log-viewer-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: log-viewer-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: log-viewer-backend
|
||||
image: harbor.k-space.ee/playground/log-viewer-backend
|
||||
ports:
|
||||
- containerPort: 3002
|
||||
env:
|
||||
- name: MONGODB_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mongodb-application-readwrite
|
||||
key: connectionString.standard
|
102
k8s/staging/deployment.yaml
Normal file
102
k8s/staging/deployment.yaml
Normal file
@ -0,0 +1,102 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: playground
|
||||
annotations:
|
||||
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.k-space.ee
|
||||
spec:
|
||||
rules:
|
||||
- host: playground.k-space.ee
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: log-viewer-frontend
|
||||
port:
|
||||
number: 8080
|
||||
- pathType: Prefix
|
||||
path: "/events"
|
||||
backend:
|
||||
service:
|
||||
name: log-viewer-backend
|
||||
port:
|
||||
number: 3002
|
||||
tls:
|
||||
- hosts:
|
||||
- playground.k-space.ee
|
||||
secretName: playground-tls
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: log-viewer-frontend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: log-viewer-frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: log-viewer-backend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: log-viewer-backend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 3002
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: log-viewer-frontend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: log-viewer-frontend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: log-viewer-frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: log-viewer-frontend
|
||||
image: harbor.k-space.ee/playground/log-viewer-frontend
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: log-viewer-backend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: log-viewer-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: log-viewer-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: log-viewer-backend
|
||||
image: harbor.k-space.ee/playground/log-viewer-backend
|
||||
ports:
|
||||
- containerPort: 3002
|
||||
env:
|
||||
- name: MONGODB_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mongodb-application-readwrite
|
||||
key: connectionString.standard
|
56
skaffold.yaml
Normal file
56
skaffold.yaml
Normal file
@ -0,0 +1,56 @@
|
||||
apiVersion: skaffold/v3alpha1
|
||||
kind: Config
|
||||
metadata:
|
||||
name: log-viewer-backend
|
||||
|
||||
build:
|
||||
artifacts:
|
||||
- image: harbor.k-space.ee/playground/log-viewer-backend
|
||||
context: backend
|
||||
docker:
|
||||
dockerfile: Dockerfile
|
||||
- image: harbor.k-space.ee/playground/log-viewer-frontend
|
||||
context: frontend
|
||||
docker:
|
||||
dockerfile: Dockerfile
|
||||
|
||||
deploy:
|
||||
kubectl: {}
|
||||
|
||||
manifests:
|
||||
rawYaml:
|
||||
- k8s/staging/deployment.yaml
|
||||
|
||||
profiles:
|
||||
- name: dev
|
||||
activation:
|
||||
- command: dev
|
||||
build:
|
||||
artifacts:
|
||||
- image: harbor.k-space.ee/playground/log-viewer-backend
|
||||
context: backend
|
||||
docker:
|
||||
target: dev
|
||||
sync:
|
||||
manual:
|
||||
- src: '**/*.js'
|
||||
dest: .
|
||||
- image: harbor.k-space.ee/playground/log-viewer-frontend
|
||||
context: frontend
|
||||
docker:
|
||||
target: dev
|
||||
sync:
|
||||
manual:
|
||||
- src: 'src/**/*.vue'
|
||||
dest: .
|
||||
- src: 'src/**/*.js'
|
||||
dest: .
|
||||
- src: 'src/**/*.css'
|
||||
dest: .
|
||||
- src: 'src/**/*.svg'
|
||||
dest: .
|
||||
- src: 'index.html'
|
||||
dest: .
|
||||
manifests:
|
||||
rawYaml:
|
||||
- k8s/dev/deployment.yaml
|
Loading…
Reference in New Issue
Block a user