Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 16d0733a41
build(deps): bump ssri from 6.0.1 to 6.0.2
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-30 00:57:06 +00:00
58 changed files with 1387 additions and 2363 deletions

View File

@ -77,8 +77,7 @@ local task_build(version, arch) = {
], ],
}, },
environment: { environment: {
DOCKERAUTH: { from_variable: 'harbor-auth' }, DOCKERAUTH: { from_variable: 'dockerauth' },
DOCKERURL: { from_variable: 'harbor-url' },
}, },
shell: '/busybox/sh', shell: '/busybox/sh',
working_dir: '/workspace', working_dir: '/workspace',
@ -91,13 +90,13 @@ local task_build(version, arch) = {
cat << EOF > /kaniko/.docker/config.json cat << EOF > /kaniko/.docker/config.json
{ {
"auths": { "auths": {
"$DOCKERURL": { "auth" : "$DOCKERAUTH" } "https://index.docker.io/v1/": { "auth" : "$DOCKERAUTH" }
} }
} }
EOF EOF
|||, |||,
}, },
{ type: 'run', command: '/kaniko/executor --destination $DOCKERURL/tux/agola-web:$AGOLA_GIT_TAG' }, { type: 'run', command: '/kaniko/executor --destination sorintlab/agola-web:$AGOLA_GIT_TAG' },
], ],
depends: ['checkout code and save to workspace'], depends: ['checkout code and save to workspace'],
when: { when: {

View File

@ -1,3 +0,0 @@
module.exports = {
singleQuote: true,
};

View File

@ -1,4 +1,4 @@
FROM node:12-alpine AS web_build FROM node:lts-alpine AS web_build
WORKDIR /agola-web WORKDIR /agola-web

View File

@ -1,3 +1,5 @@
module.exports = { module.exports = {
presets: ['@vue/cli-plugin-babel/preset'], presets: [
}; '@vue/cli-plugin-babel/preset'
]
}

View File

@ -2,8 +2,12 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"*": ["types/*"] "*": [
"types/*"
]
} }
}, },
"include": ["./src/**/*"] "include": [
"./src/**/*"
]
} }

49
package-lock.json generated
View File

@ -1977,13 +1977,6 @@
"yallist": "^2.1.2" "yallist": "^2.1.2"
} }
}, },
"prettier": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"dev": true,
"optional": true
},
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@ -9856,10 +9849,11 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "2.5.1", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"dev": true "dev": true,
"optional": true
}, },
"pretty-error": { "pretty-error": {
"version": "2.1.2", "version": "2.1.2",
@ -11416,9 +11410,9 @@
} }
}, },
"ssri": { "ssri": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"figgy-pudding": "^3.5.1" "figgy-pudding": "^3.5.1"
@ -12658,11 +12652,10 @@
} }
}, },
"vue-loader-v16": { "vue-loader-v16": {
"version": "npm:vue-loader@16.1.2", "version": "npm:vue-loader@16.2.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.1.2.tgz", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz",
"integrity": "sha512-8QTxh+Fd+HB6fiL52iEVLKqE9N1JSlMXLR92Ijm6g8PZrwIxckgpqjPDWRP5TWxdiPaHR+alUWsnu1ShQOwt+Q==", "integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"chalk": "^4.1.0", "chalk": "^4.1.0",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
@ -12674,17 +12667,15 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"color-convert": "^2.0.1" "color-convert": "^2.0.1"
} }
}, },
"chalk": { "chalk": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
@ -12695,7 +12686,6 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"color-name": "~1.1.4" "color-name": "~1.1.4"
} }
@ -12704,29 +12694,25 @@
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true, "dev": true
"optional": true
}, },
"emojis-list": { "emojis-list": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"dev": true, "dev": true
"optional": true
}, },
"has-flag": { "has-flag": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true, "dev": true
"optional": true
}, },
"loader-utils": { "loader-utils": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"big.js": "^5.2.2", "big.js": "^5.2.2",
"emojis-list": "^3.0.0", "emojis-list": "^3.0.0",
@ -12738,7 +12724,6 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"has-flag": "^4.0.0" "has-flag": "^4.0.0"
} }

View File

@ -29,7 +29,6 @@
"eslint": "^6.7.2", "eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2", "eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.14.1", "node-sass": "^4.14.1",
"prettier": "2.5.1",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"tailwindcss": "^1.9.6", "tailwindcss": "^1.9.6",
"vue-template-compiler": "^2.6.12" "vue-template-compiler": "^2.6.12"

View File

@ -1,3 +1,6 @@
module.exports = { module.exports = {
plugins: [require('tailwindcss')('tailwind.js'), require('autoprefixer')()], "plugins": [
}; require('tailwindcss')('tailwind.js'),
require('autoprefixer')(),
]
}

View File

@ -1,139 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1940 1240.1947"
xml:space="preserve"
id="svg2"
version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
id="clipPath18"
clipPathUnits="userSpaceOnUse"><path
id="path16"
d="M 0,930.146 H 1454.995 V 0 H 0 Z" /></clipPath></defs><g
transform="matrix(1.3333333,0,0,-1.3333333,0,1240.1947)"
id="g10"><g
id="g12"><g
clip-path="url(#clipPath18)"
id="g14"><g
transform="translate(183.6719,292.4514)"
id="g20"><path
id="path22"
style="fill:#23261f;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -5.566,1.016 -12.144,1.523 -17.202,1.523 -41.494,0 -70.84,-45.537 -70.84,-84.502 0,-24.794 12.651,-36.425 27.324,-36.425 16.699,0 40.479,14.668 52.114,78.427 z m -18.218,-185.186 c 1.016,14.678 2.027,29.346 2.53,44.024 h -1.011 c -22.261,-39.473 -55.152,-50.098 -83.487,-50.098 -46.547,0 -83.486,34.912 -83.486,92.598 0,85 57.681,168.486 191.768,168.486 33.393,0 69.824,-7.08 93.608,-14.668 L 75.391,-72.861 c -5.059,-27.315 -10.625,-77.92 -9.615,-112.325 z" /></g><g
transform="translate(496.377,290.9377)"
id="g24"><path
id="path26"
style="fill:#f37021;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -5.059,2.021 -15.181,3.037 -23.276,3.037 -38.453,0 -66.28,-35.42 -66.28,-77.422 0,-27.314 15.176,-37.939 31.368,-37.939 18.72,0 39.975,15.176 48.574,62.236 z m -172.031,-205.937 c 14.673,-8.096 52.114,-13.155 73.364,-13.155 33.398,0 60.718,11.133 69.824,57.178 l 2.027,10.117 h -1.011 c -19.229,-19.736 -38.457,-28.838 -67.803,-28.838 -53.633,0 -90.571,40.479 -90.571,96.133 0,80.957 59.707,155.84 180.132,155.84 39.97,0 71.845,-5.557 103.725,-17.705 L 61.226,-149.268 C 53.13,-192.783 38.96,-238.32 5.059,-263.613 c -29.849,-21.758 -68.814,-27.324 -103.218,-27.324 -39.468,0 -72.862,6.064 -93.101,16.699 z" /></g><g
transform="translate(716.4942,210.9963)"
id="g28"><path
id="path30"
style="fill:#f37021;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,-27.832 14.673,-41.494 36.934,-41.494 38.96,0 55.151,49.59 55.151,81.973 0,23.271 -10.117,42.5 -35.923,42.5 C 13.657,82.979 0,27.314 0,0 m 186.704,45.029 c 0,-100.693 -72.353,-154.834 -163.433,-154.834 -61.728,0 -117.89,33.907 -117.89,108.789 0,86.524 65.268,152.295 161.914,152.295 66.284,0 119.409,-39.97 119.409,-106.25" /></g><g
transform="translate(1267.0167,292.4514)"
id="g32"><path
id="path34"
style="fill:#23261f;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -5.566,1.016 -12.144,1.523 -17.202,1.523 -41.494,0 -70.84,-45.537 -70.84,-84.502 0,-24.794 12.651,-36.425 27.324,-36.425 16.695,0 40.479,14.668 52.114,78.427 z m -18.218,-185.186 c 1.016,14.678 2.027,29.346 2.534,44.024 h -1.015 c -22.261,-39.473 -55.152,-50.098 -83.487,-50.098 -46.547,0 -83.486,34.912 -83.486,92.598 0,85 57.681,168.486 191.768,168.486 33.393,0 69.824,-7.08 93.603,-14.668 L 75.391,-72.861 c -5.059,-27.315 -10.625,-77.92 -9.615,-112.325 z" /></g><g
transform="translate(1007.8321,485.4104)"
id="g36"><path
id="path38"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 0.19,0.01 -0.049,-0.049 Z" /></g><g
transform="translate(989.9092,606.8997)"
id="g40"><path
id="path42"
style="fill:#23261f;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C -120.383,-88.113 -319.265,-165.833 -401.267,-16.353 -299.682,-163.98 -112.424,-68.142 -18.081,-1.025 -6.823,19.741 17.4,55.164 40.047,82.378 18.616,70.146 4.612,65.154 -7.153,62.026 -40.51,34.409 -86.895,2.563 -136.719,-18.523 -207.5,-44.832 -279.499,-56.338 -337.634,-3.811 -244.57,-76.453 -109.912,-14.675 -26.325,57.705 -4.424,99.998 10.018,124.617 29.549,152.261 10.264,138.137 -6.042,129.307 -20.083,125.183 -76.719,61.135 -150.21,13.137 -232.268,8.337 c -68.095,-3.984 -99.204,54.339 -99.204,91.228 0,23.243 8.255,43.433 23.108,59.039 -10.991,-4.786 -20.93,-11.622 -32.414,-20.113 l -3.98,1.846 c -0.488,7.168 0.532,12.725 2.417,17.139 -1.806,-1.905 -3.457,-3.809 -5.01,-5.606 -3.169,-3.662 -5.908,-6.826 -8.891,-8.799 l -2.915,0.108 c -2.388,1.855 -3.74,4.258 -4.024,7.148 -0.464,4.658 2.012,9.844 5.205,14.58 -7.841,-5.469 -15.952,-12.129 -22.314,-17.607 l -4.131,1.914 c 0.049,7.91 5.386,19.433 14.697,30.166 -19.721,-12.109 -27.373,-20.166 -33.828,-26.953 -1.958,-2.071 -3.813,-4.024 -5.844,-5.928 l -4.18,1.406 c -1.782,10.635 8.052,25.742 16.582,36.162 -13.008,-8.232 -21.343,-18.134 -26.348,-30.996 l -4.8,0.508 c -2.866,17.891 4.996,41.104 14.19,56.631 -18.589,-15.615 -27.559,-41.24 -28.247,-53.75 l -4.59,-1.231 c -8.936,13.68 -7.734,34.454 -2.295,54.498 -86.121,-127.256 -26.094,-359.712 176.633,-359.712 91.819,0 178.68,41.882 250.693,88.994 C -7.067,-42.283 25.01,-6.182 47.781,17.515 23.862,4.661 10.815,1.519 0,0" /></g><g
transform="translate(1183.4816,907.4319)"
id="g44"><path
id="path46"
style="fill:#344026;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 10.742,-2.139 -9.8,-4.892 c -26.594,-13.303 -50.908,-40.786 -63.191,-69.214 19.109,17.314 39.422,32.187 64.891,45.464 33.962,17.705 119.355,30.21 178.532,3.613 -8.892,7.122 -18.718,12.478 -28.967,16.675 C 62.131,36.023 -5.61,16.27 -29.907,7.454 -35.762,5.33 -41.294,2.915 -46.685,0.364 -31.294,3.186 -15.654,3.101 0,0" /></g><g
transform="translate(1044.7511,785.3127)"
id="g48"><path
id="path50"
style="fill:#2c3324;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 -11.265,-15.283 c -22.846,-31.004 -37.514,-54.517 -59.37,-96.011 6.316,5.84 12.32,11.709 17.881,17.554 C -0.657,-39.004 31.24,1.909 64.38,34.453 73.425,65.771 98.132,98.33 126.724,116.367 104.87,118.74 83.093,114.741 62.119,104.824 14.924,71.05 -15.928,18.87 -61.299,-37.202 c -2.327,-2.876 -4.741,-5.679 -7.132,-8.499 14.984,5.994 32.601,17.095 53.597,33.855 z" /></g><g
transform="translate(1239.6876,847.8518)"
id="g52"><path
id="path54"
style="fill:#344026;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 12.124,-2.539 0.63,-7.148 c -19.185,-7.708 -45.747,-32.369 -65.816,-55.538 9.771,6.565 20.611,13.372 32.959,20.562 C 62.803,13.203 184.395,-70.83 215.308,-162.795 211.784,42.71 37.505,50.327 -40.052,13.247 -50.063,8.459 -59.432,3.32 -68.33,-2.122 -42.964,2.703 -13.563,2.837 0,0" /></g><g
transform="translate(1055.7618,710.8987)"
id="g56"><path
id="path58"
style="fill:#2c3324;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 -11.899,-13.184 C -33.69,-37.31 -59.487,-73.45 -74.163,-97.935 c 5.444,4.029 10.556,7.93 15.188,11.595 83.667,66.208 99.221,101.687 155.574,144.775 16.995,23.621 48.147,57.075 73.982,72.639 -21.219,1.336 -54.165,-1.504 -74.438,-9.219 C 46.812,86.462 11.193,40.356 -39.868,-11.863 -46.24,-18.379 -54.202,-25.84 -63.34,-33.782 c 11.875,4.143 26.716,10.991 48.267,24.397 z" /></g><g
transform="translate(1209.3556,785.9988)"
id="g60"><path
id="path62"
style="fill:#344026;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -15.853,-5.701 -30.916,-13.997 -45.428,-23.853 35.667,7.618 80.918,3.731 101.004,-15.7 l 4.82,-4.668 -6.495,-1.66 c -23.842,-6.104 -73.03,-35.66 -104.221,-60.215 179.168,60.813 361.748,-163.777 32.778,-275.713 273.064,14.668 288.47,219.917 219.446,319.136 C 150.84,10.732 61.823,22.234 0,0" /></g><g
transform="translate(1145.837,748.9065)"
id="g64"><path
id="path66"
style="fill:#2c3324;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -42.053,-33.196 -79.553,-77.856 -117.131,-110.996 -9.046,-7.976 -19.007,-16.074 -29.588,-24.136 11.287,2.793 26.387,8.753 51.82,23.931 l 18.339,10.947 -15.317,-14.892 c -17.767,-17.259 -51.006,-53.809 -71.685,-78.426 71.036,48.352 126.089,99.568 154.786,115.408 25.747,25.029 84.956,63.081 117.461,74.521 C 83.838,13.372 31.489,12.952 0,0" /></g><g
transform="translate(922.336,756.0208)"
id="g68"><path
id="path70"
style="fill:#f37021;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -0.944,3.213 -2.446,6.333 -4.963,7.632 -1.048,0.542 -2.832,1.396 -5.029,2.471 -8.653,4.238 -23.135,11.328 -27.905,14.228 l 1.298,2.129 c 4.673,-2.842 19.654,-10.176 27.705,-14.111 2.207,-1.084 4.006,-1.922 5.049,-2.481 8.062,-4.316 7.471,-14.895 7.93,-18.186 0.552,-3.87 0.869,-8.42 1.079,-13.882 28.781,28.97 9.24,69.143 -20.732,86.275 -5.992,-2.471 -26.058,-24.2 -35.43,-40.2 C -35.451,17.944 -19.395,10.659 -2.866,1.726 -2.146,1.338 -1.105,0.703 0,0" /></g><g
transform="translate(931.3506,781.8118)"
id="g72"><path
id="path74"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,-3.041 -2.466,-5.507 -5.507,-5.507 -3.041,0 -5.507,2.466 -5.507,5.507 0,3.042 2.466,5.507 5.507,5.507 C -2.466,5.507 0,3.042 0,0" /></g><g
transform="translate(770.9083,907.6028)"
id="g76"><path
id="path78"
style="fill:#23261f;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -36.182,4.995 -72.246,3.169 -111.885,22.544 5.066,-14.751 5.674,-26.777 31.446,-32.749 -40.45,-1.69 -74.317,-13.486 -101.663,-32.192 -0.098,-0.181 -0.295,-0.44 -0.427,-0.65 -6.707,-4.634 -13.13,-9.565 -19.048,-14.985 -6.936,-6.353 -13.399,-13.15 -19.248,-20.445 -7.075,-19.008 -11.509,-41.513 -6.143,-57.251 3.721,16.895 15.952,44.493 40.908,57.1 l 2.964,-3.926 c -9.336,-10.088 -20.688,-34.082 -21.587,-54.15 7.608,13.35 19.629,23.35 37.818,31.699 l 2.617,-4.219 c -5.923,-4.785 -21.86,-23.632 -25,-36.738 0.356,0.371 0.713,0.742 1.074,1.123 8.745,9.209 19.629,20.664 57.788,40.723 l 2.466,-4.346 c -17.197,-10.508 -27.9,-25.986 -31.313,-36.65 9.311,7.744 20.722,16.455 30.009,21.162 l 3.033,-3.848 -1.05,-1.221 c -4.087,-4.736 -12.588,-14.58 -11.963,-20.859 0.083,-0.889 0.351,-1.66 0.815,-2.344 1.934,1.67 3.975,4.024 6.26,6.66 6.524,7.54 14.644,16.924 28.789,21.075 l 2.124,-4.463 c -1.138,-0.781 -2.358,-1.553 -3.623,-2.354 -7.29,-4.59 -15.459,-9.746 -16.011,-24.023 13.902,10.112 26.133,17.69 41.006,21.89 0.742,0.581 1.56,1.103 2.324,1.669 10.391,7.701 23.079,13.501 37.371,17.544 l -0.137,0.264 c -0.337,0.01 -0.705,-0.034 -1.045,-0.029 0.098,0.005 0.223,0.044 0.32,0.044 0.244,0 0.486,-0.005 0.725,-0.015 13.379,3.75 28.348,5.747 44.648,5.747 28.387,0 60.833,-6.059 96.068,-19.497 9.372,16.001 29.438,37.73 35.429,40.2 C 130.324,-45.493 53.034,-5.508 0,0" /></g><g
transform="translate(1070.84,479.7854)"
id="g80"><path
id="path82"
style="fill:#f37021;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C 1.24,0.234 2.378,0.693 3.584,1.182 5.537,1.963 7.771,2.72 10.91,2.966 7.59,6.064 6.647,7.534 7.187,8.74 7.383,9.17 7.9,9.873 9.463,9.717 12.995,9.302 20.148,6.736 26.904,-0.073 24.57,3.474 21.392,7.012 18.112,9.497 14.224,12.446 6.081,18.574 1.157,18.784 -1.033,18.879 -3.523,16.868 -4.155,14.863 -5.423,10.85 -13.374,6.487 -20.433,3.445 -12.879,0.996 -2.386,-0.503 0,0" /></g><g
transform="translate(1114.5607,456.2746)"
id="g84"><path
id="path86"
style="fill:#f37021;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -0.027,0.186 -0.063,0.376 -0.107,0.568 -0.074,0.33 -0.169,0.662 -0.287,0.999 -0.114,0.337 -0.251,0.679 -0.41,1.026 -0.314,0.695 -0.705,1.408 -1.172,2.143 -0.929,1.47 -2.145,3.02 -3.598,4.639 -1.094,1.211 -2.322,2.466 -3.672,3.74 l -0.017,-0.014 c -0.151,0.168 -0.332,0.297 -0.488,0.461 -1.17,1.086 -2.407,2.185 -3.745,3.281 -7.461,5.535 -16.397,7.219 -17.661,7.244 -3.57,-0.039 -5.86,-0.84 -8.052,-1.719 -1.255,-0.508 -2.559,-1.025 -4.033,-1.318 -3.953,-0.735 -20.145,1.963 -27.256,5.903 -9.617,4.453 -18.823,11.582 -31.196,24.507 -16.675,16.97 -22.93,31.606 -26.234,43.403 -5.703,-3.955 -11.452,-7.832 -17.233,-11.604 l -0.047,-0.031 c 5.752,-10.123 18.968,-24.908 29.3,-33.79 l -1.631,-1.894 c -10.428,8.96 -23.74,23.896 -29.744,34.331 -2.788,-1.804 -5.583,-3.579 -8.381,-5.33 3.291,-4.514 7.175,-8.96 11.476,-13.203 11.654,-11.562 25.56,-22.072 37.354,-33.747 0.096,-0.093 0.188,-0.186 0.283,-0.279 0.008,-0.097 0.018,-0.195 0.025,-0.293 0.642,-8.244 -8.76,-7.041 -17.561,-6.215 -5.352,0.544 -11.048,1.071 -14.261,0.009 -4.767,-2.702 -7.126,-5.1 -7.36,-7.373 -0.122,-1.137 0.28,-2.251 1.144,-3.361 0.433,-0.555 0.98,-1.111 1.636,-1.67 0.33,-0.279 0.684,-0.559 1.065,-0.84 0.381,-0.281 0.789,-0.562 1.218,-0.845 5.671,-3.625 15.083,-7.535 23.435,-10.015 0.945,-0.217 2.01,0.185 3.047,0.779 -5.801,2.403 -12.046,5.987 -14.743,9.859 -1.172,1.689 -1.602,3.339 -1.284,4.912 l 2.451,-0.508 c -0.181,-0.869 0.122,-1.875 0.888,-2.969 2.525,-3.636 9.161,-7.224 14.973,-9.49 1.136,1.214 1.912,2.522 1.57,3.191 -1.494,3.052 -1.215,5.152 0.865,6.321 2.172,1.228 6.276,1.35 12.172,0.193 3.02,0.977 4.986,3.259 6.104,7.114 0.871,-0.281 1.74,-0.561 2.604,-0.844 -3.608,-12.886 1.649,-19.906 11.763,-24.94 2.078,-0.356 3.848,-0.529 5.57,-0.654 -1.844,3.828 -3.003,7.348 -1.851,9.539 0.391,0.742 1.226,1.66 2.988,1.826 5.681,0.645 11.314,-2.598 14.658,-7.632 0.787,0.591 1.555,1.221 2.266,1.936 0.371,3.928 -2.161,6.992 -6.245,10.027 -0.02,0.015 -0.005,0.034 -0.024,0.049 -0.376,0.22 -0.801,0.483 -1.167,0.698 -8.418,4.942 -15.064,8.848 -18.531,16.826 l 2.295,0.996 c 3.14,-7.236 9.478,-10.957 17.5,-15.664 0.564,-0.329 1.206,-0.727 1.789,-1.071 0.257,-0.01 0.498,0.026 0.762,-0.049 3.655,-1.051 7.659,-1.099 12.293,-0.281 2.048,1.938 4.072,2.549 6.203,1.943 2.103,-0.598 4.046,-2.285 5.862,-5.11 2.891,-2.808 5.611,-3.306 7.408,-3.278 3.916,0.099 6.989,2.599 6.955,5.849 -0.02,2.603 -1.936,5.42 -5.293,8.072 0.18,0.363 0.354,0.722 0.522,1.079 9.268,-5.706 14.642,-10.469 17.442,-14.564 1.899,-2.858 2.449,-5.378 1.399,-8.071 1.489,0.266 2.646,0.95 3.337,1.936 0.345,0.496 0.574,1.067 0.669,1.706 0.049,0.321 0.066,0.66 0.047,1.014 C 0.044,-0.369 0.026,-0.186 0,0" /></g><g
transform="translate(869.2452,786.0159)"
id="g88"><path
id="path90"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -33.083,12.197 -64.68,18.374 -93.975,18.374 -16.191,0 -31.422,-1.929 -45.287,-5.737 l -0.086,0.005 c -7.39,0 -15.993,-3.052 -25.954,-6.582 -1.36,-0.484 -2.801,-0.967 -4.202,-1.456 14.397,19.629 20.96,19.751 27.402,19.742 1.714,-0.039 3.492,-0.039 5.411,0.293 l 0.283,2.373 c -11.87,5.205 -23.316,-0.703 -34.38,-6.407 -2.9,-1.494 -5.669,-2.929 -8.389,-4.121 4.077,15.205 21.958,21.192 25.655,22.276 l -0.206,2.441 c -10.615,1.27 -24.301,-1.406 -37.426,-7.217 11.303,13.33 25.508,19.434 41.269,17.764 1.455,-0.205 2.93,-0.43 4.458,-0.693 l 0.464,2.451 c -1.465,0.303 -2.969,0.537 -4.58,0.723 -36.519,5.019 -51.807,-1.758 -70.43,-13.956 13.672,21.221 40.005,23.467 40.284,23.487 l -0.03,2.5 c -20.512,0.967 -36.65,-1.338 -51.982,-15.332 6.719,15.058 18.071,23.476 34.555,25.693 l -0.073,2.49 c -28.535,2.129 -51.279,-11.816 -59.59,-26.787 -1.679,4.824 -1.503,9.551 0.523,14.102 4.238,9.502 15.386,15.781 21.836,17.685 9.951,2.823 20.078,2.979 27.739,2.705 2.437,-0.166 4.893,-0.322 7.383,-0.459 l 0.161,2.5 c -2.051,0.147 -4.575,0.332 -7.441,0.45 -0.035,0.009 -0.069,0.009 -0.098,0.009 -23.694,1.534 -46.191,2.979 -72.993,-17.587 1.218,1.518 2.263,2.861 2.964,3.93 27.902,18.833 60.925,29.17 98.169,30.728 l 36.858,1.538 -35.94,8.33 c -16.631,3.852 -21.116,9.927 -24.307,18.696 26.775,-10.923 51.968,-13.232 76.426,-15.478 8.713,-0.801 17.721,-1.626 26.675,-2.857 C -46.501,111.177 23.665,72.925 32.007,36.509 23.47,30.186 8.623,13.35 0,0" /></g><g
transform="translate(839.5167,833.345)"
id="g92"><path
id="path94"
style="fill:#f37021;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -3.06,-6.934 -1.943,-14.6 2.16,-20.356 1.014,-0.616 1.953,-1.06 2.749,-1.177 6.151,-0.874 22.806,3.12 33.143,5.239 0.7,1.69 1.105,3.413 1.343,5.147 -8.326,8.051 -12.933,18.764 -19.307,21.718 -1.196,0.557 -3.037,0.982 -5.254,1.333 C 8.479,10.605 2.817,6.387 0,0" /></g><g
transform="translate(870.0899,821.116)"
id="g96"><path
id="path98"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -2.328,-5.278 -8.495,-7.669 -13.774,-5.341 -5.279,2.329 -7.67,8.496 -5.341,13.775 2.329,5.278 8.496,7.67 13.774,5.34 C -0.062,11.446 2.329,5.279 0,0" /></g><g
transform="translate(883.7061,818.179)"
id="g100"><path
id="path102"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C -1.751,1.206 -3.315,2.583 -4.795,4.019 -5.032,2.285 -5.437,0.562 -6.138,-1.128 -3.696,-0.625 -1.497,-0.195 0,0" /></g><g
transform="translate(839.5167,833.345)"
id="g104"><path
id="path106"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C 2.817,6.387 8.479,10.605 14.834,11.904 2.715,13.813 -22.202,13.115 -33.896,14.771 -22.588,6.855 -6.538,-15.068 2.16,-20.356 -1.943,-14.6 -3.06,-6.934 0,0" /></g><g
transform="translate(1074.8829,462.2951)"
id="g108"><path
id="path110"
style="fill:#23261f;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -0.098,0.039 -2.373,-1.572 -3.96,-2.07 -1.587,-0.493 -3.828,-0.547 -5.615,-0.616 1.457,-2.797 1.299,-6.547 -0.357,-9.502 -1.655,-2.954 -6.562,-3.271 -6.562,-3.271 0,0 -9.004,7.471 -12.256,7.559 1.509,-3.301 2.148,-9.048 2.148,-9.048 0,0 -5.752,-3.023 -10.798,-1.621 -6.223,1.728 -16.418,11.274 -17.439,19.243 -0.391,-0.166 -0.796,-0.313 -1.216,-0.449 L -58.55,0.068 c -4.077,0.791 -6.391,0.782 -7.607,0.635 0.005,-0.019 0.014,-0.029 0.019,-0.039 0.918,-1.816 1.28,-4.873 -2.422,-8.818 l -3.432,-2.705 c -2.373,-1.368 -4.531,-1.846 -6.646,-1.319 -1.469,0.435 -2.927,0.948 -4.389,1.441 l -65.879,-344.292 h 90.063 L 7.773,-6.88 C 3.137,-4.424 0.603,-0.171 0,0" /></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,9 +1,7 @@
<template> <template>
<div id="app"> <div id="app">
<nav class="bg-gray-800 p-3 text-white"> <nav class="bg-gray-800 p-3 text-white">
<div <div class="container flex items-center justify-between flex-wrap bg-gray-800">
class="container flex items-center justify-between flex-wrap bg-gray-800"
>
<div class="mr-6"> <div class="mr-6">
<router-link <router-link
class="font-semibold flex items-center flex-shrink-0 text-xl tracking-tight" class="font-semibold flex items-center flex-shrink-0 text-xl tracking-tight"
@ -30,12 +28,12 @@
</div> </div>
<div <div
class="w-full block flex-grow lg:flex lg:items-center lg:w-auto" class="w-full block flex-grow lg:flex lg:items-center lg:w-auto"
:class="{ hidden: !navActive }" :class="{'hidden' : !navActive}"
> >
<div class="text-sm lg:flex-grow"></div> <div class="text-sm lg:flex-grow"></div>
<div v-if="user" class="relative mr-3"> <div v-if="user" class="relative mr-3">
<button <button
v-click-outside="() => (createDropdownActive = false)" v-click-outside="() => createDropdownActive = false"
@click="createDropdownActive = !createDropdownActive" @click="createDropdownActive = !createDropdownActive"
class="relative flex items-center focus:outline-none" class="relative flex items-center focus:outline-none"
> >
@ -51,8 +49,7 @@
<router-link <router-link
class="block px-4 py-2 hover:bg-blue-500 hover:text-white" class="block px-4 py-2 hover:bg-blue-500 hover:text-white"
to="/neworganization" to="/neworganization"
>New Organization</router-link >New Organization</router-link>
>
</li> </li>
</ul> </ul>
</div> </div>
@ -60,11 +57,11 @@
<div v-if="user" class="relative"> <div v-if="user" class="relative">
<div class="flex"> <div class="flex">
<button <button
v-click-outside="() => (userDropdownActive = false)" v-click-outside="() => userDropdownActive = false"
@click="userDropdownActive = !userDropdownActive" @click="userDropdownActive = !userDropdownActive"
class="relative flex items-center focus:outline-none" class="relative flex items-center focus:outline-none"
> >
{{ user.username }} {{user.username}}
<i class="mdi mdi-chevron-down"></i> <i class="mdi mdi-chevron-down"></i>
</button> </button>
</div> </div>
@ -75,7 +72,7 @@
<ul> <ul>
<li class="block px-4 py-2 border-b"> <li class="block px-4 py-2 border-b">
Logged as&nbsp; Logged as&nbsp;
<b>{{ user.username }}</b> <b>{{user.username}}</b>
</li> </li>
<li> <li>
<hr class="navbar-divider" /> <hr class="navbar-divider" />
@ -101,30 +98,18 @@
</div> </div>
</div> </div>
<div v-else class="navbar-item"> <div v-else class="navbar-item">
<router-link class="btn btn-blue" to="/register" <router-link class="btn btn-blue" to="/register">Sign up</router-link>
>Sign up</router-link <router-link class="ml-2 btn btn-blue" to="/login">Login</router-link>
>
<router-link class="ml-2 btn btn-blue" to="/login"
>Login</router-link
>
</div> </div>
</div> </div>
</div> </div>
</nav> </nav>
<div v-if="error" class="container h-screen" role="alert"> <div v-if="error" class="container h-screen" role="alert">
<div <div v-if="error" class="h-full flex justify-center items-center" role="alert">
v-if="error"
class="h-full flex justify-center items-center"
role="alert"
>
<div v-if="error" class="w-full" role="alert"> <div v-if="error" class="w-full" role="alert">
<div class="bg-red-500 text-white font-bold rounded-t px-4 py-2"> <div class="bg-red-500 text-white font-bold rounded-t px-4 py-2">Error</div>
Error <div class="border border-t-0 border-red-400 rounded-b bg-red-100 px-4 py-3 text-red-700">
</div>
<div
class="border border-t-0 border-red-400 rounded-b bg-red-100 px-4 py-3 text-red-700"
>
<p class="mb-8">Failed to fetch data: {{ error }}</p> <p class="mb-8">Failed to fetch data: {{ error }}</p>
<button class="btn btn-red" @click="reload()">Retry</button> <button class="btn btn-red" @click="reload()">Retry</button>
</div> </div>
@ -138,46 +123,48 @@
</div> </div>
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
import { mapGetters } from 'vuex'; import { mapGetters } from "vuex";
import { ownerSettingsLink } from '@/util/link.js'; import { ownerSettingsLink } from "@/util/link.js";
export default { export default {
name: 'App', name: "App",
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
components: {}, components: {},
computed: { computed: {
...mapGetters(['error', 'user']), ...mapGetters(["error", "user"])
}, },
data() { data() {
return { return {
routerActive: true, routerActive: true,
navActive: false, navActive: false,
userDropdownActive: false, userDropdownActive: false,
createDropdownActive: false, createDropdownActive: false
}; };
}, },
watch: { watch: {
$route: function () { $route: function() {
this.userDropdownActive = false; this.userDropdownActive = false;
this.createDropdownActive = false; this.createDropdownActive = false;
}, }
}, },
// method to reload current view from https://github.com/vuejs/vue-router/issues/296#issuecomment-356530037 // method to reload current view from https://github.com/vuejs/vue-router/issues/296#issuecomment-356530037
methods: { methods: {
ownerSettingsLink: ownerSettingsLink, ownerSettingsLink: ownerSettingsLink,
reload() { reload() {
this.$store.dispatch('setError', null); this.$store.dispatch("setError", null);
this.routerActive = false; this.routerActive = false;
this.$nextTick(() => (this.routerActive = true)); this.$nextTick(() => (this.routerActive = true));
}, }
}, }
}; };
</script> </script>
<style lang="scss"></style> <style lang="scss">
</style>

View File

@ -8,21 +8,19 @@
type="text" type="text"
placeholder="Organization name" placeholder="Organization name"
v-model="orgName" v-model="orgName"
/> >
</div> </div>
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label> <label>
<input type="checkbox" v-model="orgIsPrivate" /> <input type="checkbox" v-model="orgIsPrivate">
Private Private
</label> </label>
</div> </div>
<button <button
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
@click="createOrg()" @click="createOrg()"
> >Create Organization</button>
Create Organization
</button>
<div <div
v-if="createOrgError" v-if="createOrgError"
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
@ -34,19 +32,19 @@
</template> </template>
<script> <script>
import { createOrganization } from '@/util/data.js'; import { createOrganization } from "@/util/data.js";
import { ownerLink } from '@/util/link.js'; import { ownerLink } from "@/util/link.js";
export default { export default {
components: {}, components: {},
name: 'createorganization', name: "createorganization",
props: {}, props: {},
data() { data() {
return { return {
createOrgError: null, createOrgError: null,
orgIsPrivate: false, orgIsPrivate: false,
orgName: null, orgName: null
}; };
}, },
methods: { methods: {
@ -56,9 +54,9 @@ export default {
async createOrg() { async createOrg() {
this.resetErrors(); this.resetErrors();
let visibility = 'public'; let visibility = "public";
if (this.orgIsPrivate) { if (this.orgIsPrivate) {
visibility = 'private'; visibility = "private";
} }
let { error } = await createOrganization(this.orgName, visibility); let { error } = await createOrganization(this.orgName, visibility);
@ -67,11 +65,14 @@ export default {
return; return;
} }
this.$router.push(ownerLink('org', this.orgName)); this.$router.push(ownerLink("org", this.orgName));
}
}, },
}, created: async function() {}
created: async function () {},
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -7,18 +7,17 @@
type="text" type="text"
placeholder="Project Name" placeholder="Project Name"
v-model="projectName" v-model="projectName"
/> >
<div class="mb-4"> <div class="mb-4">
<label> <label>
<input type="checkbox" v-model="projectIsPrivate" /> <input type="checkbox" v-model="projectIsPrivate">
Private Private
</label> </label>
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" v-model="pass_vars_to_forked_pr" /> <input type="checkbox" v-model="pass_vars_to_forked_pr" />
Pass variables to run even if triggered by PR from forked repo Pass variables to run even if triggered by PR from forked repo (DANGEROUS)
(DANGEROUS)
</label> </label>
</div> </div>
<div class="mb-3 flex items-center"> <div class="mb-3 flex items-center">
@ -32,48 +31,31 @@
v-for="(rs, index) in remoteSources" v-for="(rs, index) in remoteSources"
v-bind:key="rs.id" v-bind:key="rs.id"
:value="index" :value="index"
> >{{ rs.name }}</option>
{{ rs.name }}
</option>
</select> </select>
<div <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2">
class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2" <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
> <path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"></path>
<svg
class="fill-current h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
>
<path
d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
></path>
</svg> </svg>
</div> </div>
</div> </div>
<button <button
class="ml-3 btn btn-blue" class="ml-3 btn btn-blue"
v-bind:class="{ spinner: fetchRemoteReposLoading }" v-bind:class="{ 'spinner': fetchRemoteReposLoading }"
:disabled="selectedRemoteSourceIndex == null" :disabled="selectedRemoteSourceIndex == null"
@click="fetchRemoteRepos()" @click="fetchRemoteRepos()"
> >Fetch remote repositories</button>
Fetch remote repositories
</button>
</div> </div>
<div v-if="remoteRepos.length"> <div v-if="remoteRepos.length">
<h4 class="text-xl">Available remote repositories</h4> <h4 class="text-xl">Available remote repositories</h4>
<remoterepos <remoterepos :remoterepos="remoteRepos" v-on:reposelected="repoSelected($event)"/>
:remoterepos="remoteRepos"
v-on:reposelected="repoSelected($event)"
/>
<button <button
class="btn btn-blue" class="btn btn-blue"
v-bind:class="{ spinner: createProjectLoading }" v-bind:class="{ 'spinner': createProjectLoading }"
:disabled="!createProjectButtonEnabled" :disabled="!createProjectButtonEnabled"
@click="createProject()" @click="createProject()"
> >Create Project</button>
Create Project
</button>
<div <div
v-if="createProjectError" v-if="createProjectError"
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
@ -90,20 +72,20 @@ import {
fetchCurrentUser, fetchCurrentUser,
fetchRemoteSources, fetchRemoteSources,
createProject, createProject,
userRemoteRepos, userRemoteRepos
} from '@/util/data.js'; } from "@/util/data.js";
import { projectLink } from '@/util/link.js'; import { projectLink } from "@/util/link.js";
import remoterepos from '@/components/remoterepos.vue'; import remoterepos from "@/components/remoterepos.vue";
export default { export default {
components: { remoterepos }, components: { remoterepos },
name: 'createproject', name: "createproject",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectgroupref: Array, projectgroupref: Array
}, },
data() { data() {
return { return {
@ -116,15 +98,15 @@ export default {
remoteSources: null, remoteSources: null,
remoteRepos: [], remoteRepos: [],
selectedRemoteSourceIndex: null, selectedRemoteSourceIndex: null,
projectName: '', projectName: "",
projectIsPrivate: false, projectIsPrivate: false,
remoteRepoPath: null, remoteRepoPath: null
}; };
}, },
computed: { computed: {
createProjectButtonEnabled: function () { createProjectButtonEnabled: function() {
return this.projectName.length && this.remoteRepoPath; return this.projectName.length && this.remoteRepoPath;
}, }
}, },
watch: {}, watch: {},
methods: { methods: {
@ -161,7 +143,7 @@ export default {
let { data, error } = await userRemoteRepos(remoteSource.id); let { data, error } = await userRemoteRepos(remoteSource.id);
this.stopFetchRemoteReposLoading(); this.stopFetchRemoteReposLoading();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.remoteRepos = data; this.remoteRepos = data;
@ -173,11 +155,11 @@ export default {
if (this.projectgroupref) { if (this.projectgroupref) {
refArray = [...refArray, ...this.projectgroupref]; refArray = [...refArray, ...this.projectgroupref];
} }
let parentref = refArray.join('/'); let parentref = refArray.join("/");
let visibility = 'public'; let visibility = "public";
if (this.projectIsPrivate) { if (this.projectIsPrivate) {
visibility = 'private'; visibility = "private";
} }
let remoteSource = this.remoteSources[this.selectedRemoteSourceIndex]; let remoteSource = this.remoteSources[this.selectedRemoteSourceIndex];
@ -204,12 +186,12 @@ export default {
this.$router.push( this.$router.push(
projectLink(this.ownertype, this.ownername, projectref) projectLink(this.ownertype, this.ownername, projectref)
); );
}
}, },
}, created: async function() {
created: async function () {
let { data, error } = await fetchCurrentUser(); let { data, error } = await fetchCurrentUser();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.user = data; this.user = data;
@ -217,7 +199,7 @@ export default {
// TODO(sgotti) filter only remote source where the user has a linked account // TODO(sgotti) filter only remote source where the user has a linked account
({ data, error } = await fetchRemoteSources()); ({ data, error } = await fetchRemoteSources());
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
@ -233,8 +215,10 @@ export default {
} }
this.remoteSources = remoteSources; this.remoteSources = remoteSources;
} }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -5,11 +5,9 @@
<button <button
@click="clicked" @click="clicked"
class="relative flex items-center focus:outline-none bg-green-500 hover:bg-green-600 text-white font-semibold hover:text-white py-2 px-4 border border-green-700 rounded rounded-r-none" class="relative flex items-center focus:outline-none bg-green-500 hover:bg-green-600 text-white font-semibold hover:text-white py-2 px-4 border border-green-700 rounded rounded-r-none"
> >{{ buttonValue }}</button>
{{ buttonValue }}
</button>
<button <button
v-click-outside="() => (dropdownActive = false)" v-click-outside="() => dropdownActive = false"
@click="dropdownActive = !dropdownActive" @click="dropdownActive = !dropdownActive"
class="relative flex items-center focus:outline-none bg-green-500 hover:bg-green-600 text-white font-semibold hover:text-white py-2 px-4 border border-l-0 border-green-700 rounded rounded-l-none" class="relative flex items-center focus:outline-none bg-green-500 hover:bg-green-600 text-white font-semibold hover:text-white py-2 px-4 border border-l-0 border-green-700 rounded rounded-l-none"
> >
@ -26,16 +24,14 @@
href="#" href="#"
class="block px-4 py-2 hover:bg-blue-500 hover:text-white" class="block px-4 py-2 hover:bg-blue-500 hover:text-white"
@click="setButton('project')" @click="setButton('project')"
>New Project</a >New Project</a>
>
</li> </li>
<li> <li>
<a <a
href="#" href="#"
class="block px-4 py-2 hover:bg-blue-500 hover:text-white" class="block px-4 py-2 hover:bg-blue-500 hover:text-white"
@click="setButton('projectgroup')" @click="setButton('projectgroup')"
>New Project Group</a >New Project Group</a>
>
</li> </li>
</ul> </ul>
</div> </div>
@ -44,28 +40,28 @@
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
export default { export default {
components: {}, components: {},
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
name: 'createprojectbutton', name: "createprojectbutton",
props: {}, props: {},
data() { data() {
return { return {
dropdownActive: false, dropdownActive: false,
type: 'project', type: "project"
}; };
}, },
computed: { computed: {
buttonValue: function () { buttonValue: function() {
if (this.type == 'project') { if (this.type == "project") {
return 'New Project'; return "New Project";
}
return "New Project Group";
} }
return 'New Project Group';
},
}, },
methods: { methods: {
setButton(type) { setButton(type) {
@ -73,10 +69,12 @@ export default {
this.dropdownActive = false; this.dropdownActive = false;
}, },
clicked() { clicked() {
this.$emit('click', this.type); this.$emit("click", this.type);
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -7,22 +7,20 @@
type="text" type="text"
placeholder="Project Group Name" placeholder="Project Group Name"
v-model="projectGroupName" v-model="projectGroupName"
/> >
<div class="mb-4"> <div class="mb-4">
<label> <label>
<input type="checkbox" v-model="projectGroupIsPrivate" /> <input type="checkbox" v-model="projectGroupIsPrivate">
Private Private
</label> </label>
</div> </div>
<button <button
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
v-bind:class="{ spinner: createProjectGroupLoading }" v-bind:class="{ 'spinner': createProjectGroupLoading }"
:disabled="!createProjectGroupButtonEnabled" :disabled="!createProjectGroupButtonEnabled"
@click="createProjectGroup()" @click="createProjectGroup()"
> >Create ProjectGroup</button>
Create ProjectGroup
</button>
<div <div
v-if="createProjectGroupError" v-if="createProjectGroupError"
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
@ -34,31 +32,31 @@
</template> </template>
<script> <script>
import { createProjectGroup } from '@/util/data.js'; import { createProjectGroup } from "@/util/data.js";
import { projectGroupLink } from '@/util/link.js'; import { projectGroupLink } from "@/util/link.js";
export default { export default {
components: {}, components: {},
name: 'createprojectgroup', name: "createprojectgroup",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectgroupref: Array, projectgroupref: Array
}, },
data() { data() {
return { return {
createProjectGroupError: null, createProjectGroupError: null,
createProjectGroupLoading: false, createProjectGroupLoading: false,
createProjectGroupLoadingTimeout: null, createProjectGroupLoadingTimeout: null,
projectGroupName: '', projectGroupName: "",
projectGroupIsPrivate: false, projectGroupIsPrivate: false
}; };
}, },
computed: { computed: {
createProjectGroupButtonEnabled: function () { createProjectGroupButtonEnabled: function() {
return this.projectGroupName.length; return this.projectGroupName.length;
}, }
}, },
methods: { methods: {
resetErrors() { resetErrors() {
@ -80,11 +78,11 @@ export default {
if (this.projectgroupref) { if (this.projectgroupref) {
refArray = [...refArray, ...this.projectgroupref]; refArray = [...refArray, ...this.projectgroupref];
} }
let parentref = refArray.join('/'); let parentref = refArray.join("/");
let visibility = 'public'; let visibility = "public";
if (this.projectGroupIsPrivate) { if (this.projectGroupIsPrivate) {
visibility = 'private'; visibility = "private";
} }
this.startProjectGroupLoading(); this.startProjectGroupLoading();
@ -106,9 +104,12 @@ export default {
this.$router.push( this.$router.push(
projectGroupLink(this.ownertype, this.ownername, projectgroupref) projectGroupLink(this.ownertype, this.ownername, projectgroupref)
); );
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -1,178 +0,0 @@
<template>
<div class="w-6/12">
<h1>
If you need more advanced options or a little help,
<a
class="text-blue-600"
rel="noopener noreferrer nofollow"
href="https://agola.io/tryit/#test-using-a-local-gitea-instance"
>
take a look at the documentation
</a>
</h1>
<form
class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"
@submit.prevent="
$emit('createSource', {
token,
name,
type,
clientId,
clientSecret,
url,
skipVerify,
sshHostKey,
skipSshHostKeyCheck,
})
"
>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="token"
>Agola Admin token</label
>
<input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="token"
type="password"
placeholder="Agola Admin token"
v-model="token"
/>
</div>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="type">Type</label>
<select
class="border bg-white rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="type"
v-model="type"
>
<option value="gitea">Gitea</option>
<option value="gitlab">GitLab</option>
<option value="github">GitHub</option>
</select>
</div>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="name"
>Source name</label
>
<input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="name"
pattern="^[a-zA-Z][a-zA-Z0-9]*([-]?[a-zA-Z0-9]+)+$"
type="text"
placeholder="Source name (only numbers, letters and -)"
v-model="name"
/>
</div>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="url"
>Source API URL</label
>
<input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="url"
type="text"
placeholder="API URL"
v-model="url"
/>
</div>
<div class="mb-4 flex flex-row">
<input
id="skip_verify"
type="checkbox"
class="h-6 w-6 border border-gray-300 rounded-md checked:bg-blue-600 checked:border-transparent focus:outline-none"
v-model="skipVerify"
/>
<label class="text-sm mt-auto font-bold mx-2" for="skip_verify"
>Skip TLS certificate validation</label
>
</div>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="ssh_key"
>Source Public SSH Key</label
>
<input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="ssh_key"
type="text"
autocomplete="off"
placeholder="Public SSH key"
v-model="sshHostKey"
/>
</div>
<div class="mb-4 flex flex-row">
<input
id="skip_ssh_key_check"
type="checkbox"
class="h-6 w-6 border border-gray-300 rounded-md checked:bg-blue-600 checked:border-transparent focus:outline-none"
v-model="skipSshHostKeyCheck"
/>
<label class="text-sm mt-auto font-bold mx-2" for="skip_ssh_key_check"
>Skip SSH host key check</label
>
</div>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="client_id"
>Source client ID</label
>
<input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="client_id"
type="text"
placeholder="Client ID"
v-model="clientId"
/>
</div>
<div class="mb-4">
<label class="block text-sm font-bold mb-2" for="client_secret"
>Source client secret</label
>
<input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="client_secret"
type="password"
placeholder="Client secret"
v-model="clientSecret"
/>
</div>
<div class="flex justify-center">
<button
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Create
</button>
</div>
</form>
</div>
</template>
<script>
import { GITHUB_SSH_KEY, GITHUB_API_URL } from '@/util/data';
export default {
name: 'CreateSourceForm',
data: function () {
return {
name: null,
token: null,
url: null,
sshHostKey: null,
skipVerify: false,
skipSshHostKeyCheck: false,
type: 'gitea', // default value for select
clientId: null,
clientSecret: null,
};
},
watch: {
type: function (value) {
if (value === 'github') {
this.url = GITHUB_API_URL;
this.sshHostKey = GITHUB_SSH_KEY;
this.skipVerify = false;
this.skipSshHostKeyCheck = false;
}
},
},
};
</script>

View File

@ -43,18 +43,18 @@
</template> </template>
<script> <script>
import { apiurl, fetch } from '@/util/auth'; import { apiurl, fetch } from "@/util/auth";
import AnsiUp from 'ansi_up'; import AnsiUp from "ansi_up";
export default { export default {
name: 'Log', name: "Log",
props: { props: {
show: Boolean, show: Boolean,
runid: String, runid: String,
taskid: String, taskid: String,
setup: Boolean, setup: Boolean,
step: Number, step: Number,
stepphase: String, stepphase: String
}, },
computed: {}, computed: {},
data() { data() {
@ -65,7 +65,7 @@ export default {
fetchAbort: null, fetchAbort: null,
items: [], items: [],
lastitem: '', lastitem: "",
lines: [], lines: [],
formatter: formatter, formatter: formatter,
es: null, es: null,
@ -73,7 +73,7 @@ export default {
streaming: false, streaming: false,
done: false, done: false,
logExists: null, logExists: null,
error: null, error: null
}; };
}, },
methods: { methods: {
@ -83,7 +83,7 @@ export default {
} }
let follow = false; let follow = false;
if (this.stepphase == 'running') { if (this.stepphase == "running") {
follow = true; follow = true;
} }
@ -94,14 +94,14 @@ export default {
this.logExists = null; this.logExists = null;
this.error = null; this.error = null;
let path = '/logs?runID=' + this.runid + '&taskID=' + this.taskid; let path = "/logs?runID=" + this.runid + "&taskID=" + this.taskid;
if (this.setup) { if (this.setup) {
path += '&setup'; path += "&setup";
} else { } else {
path += '&step=' + this.step; path += "&step=" + this.step;
} }
if (follow) { if (follow) {
path += '&follow'; path += "&follow";
} }
try { try {
@ -111,7 +111,7 @@ export default {
this.streaming = true; this.streaming = true;
const reader = res.body.getReader(); const reader = res.body.getReader();
let lastline = ''; let lastline = "";
let j = 0; let j = 0;
for (;;) { for (;;) {
let { done, value } = await reader.read(); let { done, value } = await reader.read();
@ -122,12 +122,12 @@ export default {
return; return;
} }
let data = new TextDecoder('utf-8').decode(value, { stream: true }); let data = new TextDecoder("utf-8").decode(value, { stream: true });
let part = ''; let part = "";
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
let c = data.charAt(i); let c = data.charAt(i);
if (c == '\r') { if (c == "\r") {
// replace lastline from start, simulating line feed (go to start of line) // replace lastline from start, simulating line feed (go to start of line)
// this isn't perfect since the previous line contents could have // this isn't perfect since the previous line contents could have
// been written using different colors and this will lose them but // been written using different colors and this will lose them but
@ -136,17 +136,17 @@ export default {
lastline.slice(0, j) + part + lastline.slice(j + part.length); lastline.slice(0, j) + part + lastline.slice(j + part.length);
j = 0; j = 0;
this.lastitem = this.formatter.ansi_to_html(lastline); this.lastitem = this.formatter.ansi_to_html(lastline);
part = ''; part = "";
} else if (c == '\n') { } else if (c == "\n") {
lastline = lastline =
lastline.slice(0, j) + part + lastline.slice(j + part.length); lastline.slice(0, j) + part + lastline.slice(j + part.length);
j += part.length; j += part.length;
this.lastitem = this.formatter.ansi_to_html(lastline); this.lastitem = this.formatter.ansi_to_html(lastline);
this.items.push(this.lastitem); this.items.push(this.lastitem);
this.lastitem = ''; this.lastitem = "";
lastline = ''; lastline = "";
j = 0; j = 0;
part = ''; part = "";
} else { } else {
part += c; part += c;
} }
@ -174,10 +174,10 @@ export default {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
}, }
}, },
watch: { watch: {
show: function (post, pre) { show: function(post, pre) {
if (pre == false && post == true) { if (pre == false && post == true) {
this.abortFetch(); this.abortFetch();
this.fetch(); this.fetch();
@ -186,23 +186,23 @@ export default {
this.abortFetch(); this.abortFetch();
} }
}, },
stepphase: function (post) { stepphase: function(post) {
if (!this.show) { if (!this.show) {
return; return;
} }
if (this.fetching) { if (this.fetching) {
return; return;
} }
if (post == 'running') { if (post == "running") {
this.abortFetch(); this.abortFetch();
this.getLogs(true); this.getLogs(true);
} else { } else {
this.abortFetch(); this.abortFetch();
this.getLogs(false); this.getLogs(false);
} }
}
}, },
}, created: function() {
created: function () {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
if (this.show) { if (this.show) {
@ -217,6 +217,6 @@ export default {
if (this.es !== null) { if (this.es !== null) {
this.es.close(); this.es.close();
} }
}, }
}; };
</script> </script>

View File

@ -5,53 +5,50 @@
@submit.prevent="$emit('login', { username, password })" @submit.prevent="$emit('login', { username, password })"
> >
<div class="mb-4"> <div class="mb-4">
<label class="block text-sm font-bold mb-2" for="username" <label class="block text-sm font-bold mb-2" for="username">Username</label>
>Username</label
>
<input <input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="username" id="username"
type="text" type="text"
placeholder="Username" placeholder="Username"
v-model="username" v-model="username"
/> >
</div> </div>
<div class="mb-6"> <div class="mb-6">
<label class="block text-sm font-bold mb-2" for="password" <label class="block text-sm font-bold mb-2" for="password">Password</label>
>Password</label
>
<input <input
class="appearance-none border rounded w-full py-2 px-3 mb-3 leading-tight focus:outline-none focus:shadow-outline" class="appearance-none border rounded w-full py-2 px-3 mb-3 leading-tight focus:outline-none focus:shadow-outline"
id="password" id="password"
type="password" type="password"
placeholder="******************" placeholder="******************"
v-model="password" v-model="password"
/> >
</div> </div>
<div class="flex justify-center"> <div class="flex justify-center">
<button <button
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit" type="submit"
> >{{action}} with {{name}}</button>
{{ action }} with {{ name }}
</button>
</div> </div>
</form> </form>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'LoginForm', name: "LoginForm",
props: { props: {
action: String, action: String,
name: String, name: String
}, },
data: function () { data: function() {
return { return {
username: null, username: null,
password: null, password: null
}; };
}, }
}; };
</script> </script>

View File

@ -3,8 +3,8 @@
<h4 class="mb-3 text-xl">Organization Members</h4> <h4 class="mb-3 text-xl">Organization Members</h4>
<ul v-if="members.length"> <ul v-if="members.length">
<li class="flex" v-for="member in members" v-bind:key="member.user.id"> <li class="flex" v-for="member in members" v-bind:key="member.user.id">
<span class="w-1/2 font-bold">{{ member.user.username }}</span> <span class="w-1/2 font-bold">{{member.user.username}}</span>
<span class="w-1/2">{{ member.role }}</span> <span class="w-1/2">{{member.role}}</span>
</li> </li>
</ul> </ul>
<div v-else>No Members</div> <div v-else>No Members</div>
@ -12,38 +12,39 @@
</template> </template>
<script> <script>
import { fetchOrgMembers } from '@/util/data.js'; import { fetchOrgMembers } from "@/util/data.js";
export default { export default {
components: {}, components: {},
name: 'orgmembers', name: "orgmembers",
props: { props: {
orgname: String, orgname: String
}, },
data() { data() {
return { return {
members: [], members: []
}; };
}, },
watch: { watch: {
$route: async function () { $route: async function() {
this.fetchOrgMembers(this.orgname); this.fetchOrgMembers(this.orgname);
}, }
}, },
methods: { methods: {
async fetchOrgMembers(orgname) { async fetchOrgMembers(orgname) {
let { data, error } = await fetchOrgMembers(orgname); let { data, error } = await fetchOrgMembers(orgname);
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.members = data.members; this.members = data.members;
}
}, },
}, created: function() {
created: function () {
this.fetchOrgMembers(this.orgname); this.fetchOrgMembers(this.orgname);
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -2,67 +2,57 @@
<nav class="mb-4 bg-grey-light rounded font-sans w-full"> <nav class="mb-4 bg-grey-light rounded font-sans w-full">
<ol class="list-reset flex text-grey-dark"> <ol class="list-reset flex text-grey-dark">
<li> <li>
<a>{{ ownertype }}</a> <a>{{ownertype}}</a>
</li> </li>
<li> <li>
<span class="mx-2">/</span> <span class="mx-2">/</span>
</li> </li>
<li> <li>
<router-link :to="ownerLink(ownertype, ownername)">{{ <router-link :to="ownerLink(ownertype, ownername)">{{ownername}}</router-link>
ownername
}}</router-link>
</li> </li>
<li v-for="(ref, i) in projectref" v-bind:key="i"> <li v-for="(ref, i) in projectref" v-bind:key="i">
<span class="mx-2">/</span> <span class="mx-2">/</span>
<router-link <router-link
v-if="i + 1 < projectref.length" v-if="i+1 < projectref.length"
:to=" :to="projectGroupLink(ownertype, ownername, projectref.slice(0, i+1))"
projectGroupLink(ownertype, ownername, projectref.slice(0, i + 1)) >{{ref}}</router-link>
"
>{{ ref }}</router-link
>
<router-link <router-link
v-else v-else
:to="projectLink(ownertype, ownername, projectref.slice(0, i + 1))" :to="projectLink(ownertype, ownername, projectref.slice(0, i+1))"
>{{ ref }}</router-link >{{ref}}</router-link>
>
</li> </li>
<li v-for="(ref, i) in projectgroupref" v-bind:key="i"> <li v-for="(ref, i) in projectgroupref" v-bind:key="i">
<span class="mx-2">/</span> <span class="mx-2">/</span>
<router-link <router-link
:to=" :to="projectGroupLink(ownertype, ownername, projectgroupref.slice(0, i+1))"
projectGroupLink( >{{ref}}</router-link>
ownertype,
ownername,
projectgroupref.slice(0, i + 1)
)
"
>{{ ref }}</router-link
>
</li> </li>
</ol> </ol>
</nav> </nav>
</template> </template>
<script> <script>
import { ownerLink, projectLink, projectGroupLink } from '@/util/link.js'; import { ownerLink, projectLink, projectGroupLink } from "@/util/link.js";
export default { export default {
name: 'projbreadcrumbs', name: "projbreadcrumbs",
components: {}, components: {},
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array,
projectgroupref: Array, projectgroupref: Array
}, },
methods: { methods: {
ownerLink: ownerLink, ownerLink: ownerLink,
projectLink: projectLink, projectLink: projectLink,
projectGroupLink: projectGroupLink, projectGroupLink: projectGroupLink
}, }
}; };
</script> </script>
<style scoped lang="scss"></style>
<style scoped lang="scss">
</style>

View File

@ -20,9 +20,7 @@
Private Private
</label> </label>
</div> </div>
<button class="btn btn-blue" @click="updateProjectGroup()"> <button class="btn btn-blue" @click="updateProjectGroup()">Update</button>
Update
</button>
<div <div
v-if="updateProjectGroupError" v-if="updateProjectGroupError"
@ -37,22 +35,14 @@
<div class="panel"> <div class="panel">
<p class="panel-title">Secrets</p> <p class="panel-title">Secrets</p>
<div class="p-4"> <div class="p-4">
<projectsecrets <projectsecrets :secrets="secrets" :allsecrets="allsecrets" type="projectgroup" />
:secrets="secrets"
:allsecrets="allsecrets"
type="projectgroup"
/>
</div> </div>
</div> </div>
<div class="panel"> <div class="panel">
<p class="panel-title">Variables</p> <p class="panel-title">Variables</p>
<div class="p-4"> <div class="p-4">
<projectvars <projectvars :variables="variables" :allvariables="allvariables" type="projectgroup" />
:variables="variables"
:allvariables="allvariables"
type="projectgroup"
/>
</div> </div>
</div> </div>
@ -66,13 +56,16 @@
> >
<p> <p>
This operation This operation
<strong>CANNOT</strong> be undone. This operation will remove <strong>CANNOT</strong> be undone.
<strong>{{ projectGroupPath }}</strong> This operation will remove
<strong>{{projectGroupPath}}</strong>
</p> </p>
</div> </div>
<label class="block mb-2"> <label class="block mb-2">
Please type the project group name for confirmation: Please type the project group name for confirmation:
<span class="text-red-500 font-bold">{{ projectGroupName }}</span> <span
class="text-red-500 font-bold"
>{{ projectGroupName }}</span>
</label> </label>
<div class="mb-4"> <div class="mb-4">
<input <input
@ -86,9 +79,7 @@
class="btn btn-red" class="btn btn-red"
@click="deleteProjectGroup()" @click="deleteProjectGroup()"
:disabled="!deleteButtonEnabled" :disabled="!deleteButtonEnabled"
> >Delete Project Group</button>
Delete Project Group
</button>
</div> </div>
</div> </div>
<div <div
@ -107,21 +98,21 @@ import {
fetchSecrets, fetchSecrets,
fetchVariables, fetchVariables,
updateProjectGroup, updateProjectGroup,
deleteProjectGroup, deleteProjectGroup
} from '@/util/data.js'; } from "@/util/data.js";
import { projectGroupLink } from '@/util/link.js'; import { projectGroupLink } from "@/util/link.js";
import projectsecrets from '@/components/projectsecrets'; import projectsecrets from "@/components/projectsecrets";
import projectvars from '@/components/projectvars'; import projectvars from "@/components/projectvars";
export default { export default {
components: { projectsecrets, projectvars }, components: { projectsecrets, projectvars },
name: 'projectgroupsettings', name: "projectgroupsettings",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectgroupref: Array, projectgroupref: Array
}, },
data() { data() {
return { return {
@ -133,24 +124,24 @@ export default {
allsecrets: [], allsecrets: [],
variables: [], variables: [],
allvariables: [], allvariables: [],
projectGroupNameToDelete: '', projectGroupNameToDelete: ""
}; };
}, },
computed: { computed: {
projectGroupName: function () { projectGroupName: function() {
return this.projectgroupref[this.projectgroupref.length - 1]; return this.projectgroupref[this.projectgroupref.length - 1];
}, },
projectGroupPath: function () { projectGroupPath: function() {
return ['', this.ownertype, this.ownername, ...this.projectgroupref].join( return ["", this.ownertype, this.ownername, ...this.projectgroupref].join(
'/' "/"
); );
}, },
deleteButtonEnabled: function () { deleteButtonEnabled: function() {
return this.projectGroupNameToDelete == this.projectGroupName; return this.projectGroupNameToDelete == this.projectGroupName;
}, },
isRootProjectGroup() { isRootProjectGroup() {
return this.projectgroupref.length == 0; return this.projectgroupref.length == 0;
}, }
}, },
methods: { methods: {
resetErrors() { resetErrors() {
@ -163,12 +154,12 @@ export default {
let projectgroupref = [ let projectgroupref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectgroupref, ...this.projectgroupref
].join('/'); ].join("/");
let visibility = 'public'; let visibility = "public";
if (this.projectGroupIsPrivate) { if (this.projectGroupIsPrivate) {
visibility = 'private'; visibility = "private";
} }
let { error } = await updateProjectGroup( let { error } = await updateProjectGroup(
projectgroupref, projectgroupref,
@ -184,8 +175,8 @@ export default {
let projectgroupref = [ let projectgroupref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectgroupref, ...this.projectgroupref
].join('/'); ].join("/");
if (this.projectGroupNameToDelete == this.projectGroupName) { if (this.projectGroupNameToDelete == this.projectGroupName) {
let { error } = await deleteProjectGroup(projectgroupref); let { error } = await deleteProjectGroup(projectgroupref);
@ -201,68 +192,70 @@ export default {
) )
); );
} }
}
}, },
}, created: async function() {
created: async function () {
let projectgroupref = [ let projectgroupref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectgroupref, ...this.projectgroupref
].join('/'); ].join("/");
let { data, error } = await fetchProjectGroup(projectgroupref); let { data, error } = await fetchProjectGroup(projectgroupref);
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.projectGroup = data; this.projectGroup = data;
this.projectGroupIsPrivate = this.projectGroup.visibility == 'private'; this.projectGroupIsPrivate = this.projectGroup.visibility == "private";
({ data, error } = await fetchSecrets( ({ data, error } = await fetchSecrets(
'projectgroup', "projectgroup",
projectgroupref, projectgroupref,
false false
)); ));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.secrets = data; this.secrets = data;
({ data, error } = await fetchSecrets( ({ data, error } = await fetchSecrets(
'projectgroup', "projectgroup",
projectgroupref, projectgroupref,
true true
)); ));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.allsecrets = data; this.allsecrets = data;
({ data, error } = await fetchVariables( ({ data, error } = await fetchVariables(
'projectgroup', "projectgroup",
projectgroupref, projectgroupref,
false false
)); ));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.variables = data; this.variables = data;
({ data, error } = await fetchVariables( ({ data, error } = await fetchVariables(
'projectgroup', "projectgroup",
projectgroupref, projectgroupref,
true true
)); ));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.allvariables = data; this.allvariables = data;
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -2,20 +2,13 @@
<div> <div>
<h4 class="text-xl my-3">Projects</h4> <h4 class="text-xl my-3">Projects</h4>
<div v-if="fetchProjectsLoading" class="ml-6 flex w-48"> <div v-if="fetchProjectsLoading" class="ml-6 flex w-48">
<div v-bind:class="{ spinner: fetchProjectsLoading }"></div> <div v-bind:class="{ 'spinner': fetchProjectsLoading }"></div>
</div> </div>
<ul v-else-if="projects.length > 0"> <ul v-else-if="projects.length > 0">
<li <li class="mb-2 border rounded-l" v-for="project in projects" v-bind:key="project.id">
class="mb-2 border rounded-l"
v-for="project in projects"
v-bind:key="project.id"
>
<div class="pl-4 py-4 flex items-center"> <div class="pl-4 py-4 flex items-center">
<router-link <router-link class="item" :to="projectLink(ownertype, ownername, ref(project.name))">
class="item" <span class="font-bold">{{project.name}}</span>
:to="projectLink(ownertype, ownername, ref(project.name))"
>
<span class="font-bold">{{ project.name }}</span>
</router-link> </router-link>
</div> </div>
</li> </li>
@ -26,7 +19,7 @@
<h4 class="text-xl my-3">Project Groups</h4> <h4 class="text-xl my-3">Project Groups</h4>
<div v-if="fetchProjectGroupsLoading" class="ml-6 flex w-48"> <div v-if="fetchProjectGroupsLoading" class="ml-6 flex w-48">
<div v-bind:class="{ spinner: fetchProjectGroupsLoading }"></div> <div v-bind:class="{ 'spinner': fetchProjectGroupsLoading }"></div>
</div> </div>
<ul v-else-if="projectgroups.length > 0"> <ul v-else-if="projectgroups.length > 0">
<li <li
@ -39,7 +32,7 @@
class="item" class="item"
:to="projectGroupLink(ownertype, ownername, ref(projectgroup.name))" :to="projectGroupLink(ownertype, ownername, ref(projectgroup.name))"
> >
<span class="font-bold">{{ projectgroup.name }}</span> <span class="font-bold">{{projectgroup.name}}</span>
</router-link> </router-link>
</div> </div>
</li> </li>
@ -51,18 +44,18 @@
<script> <script>
import { import {
fetchProjectGroupProjects, fetchProjectGroupProjects,
fetchProjectGroupSubgroups, fetchProjectGroupSubgroups
} from '@/util/data.js'; } from "@/util/data.js";
import { projectLink, projectGroupLink } from '@/util/link.js'; import { projectLink, projectGroupLink } from "@/util/link.js";
export default { export default {
components: {}, components: {},
name: 'Projects', name: "Projects",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectgroupref: Array, projectgroupref: Array
}, },
data() { data() {
return { return {
@ -72,18 +65,18 @@ export default {
fetchProjectsLoading: false, fetchProjectsLoading: false,
projects: [], projects: [],
projectgroups: [], projectgroups: []
}; };
}, },
watch: { watch: {
$route: async function () { $route: async function() {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
this.fetchProjects(this.ownertype, this.ownername); this.fetchProjects(this.ownertype, this.ownername);
this.fetchProjectGroups(this.ownertype, this.ownername); this.fetchProjectGroups(this.ownertype, this.ownername);
}, }
}, },
methods: { methods: {
startFetchProjectsLoading() { startFetchProjectsLoading() {
@ -114,7 +107,7 @@ export default {
this.startFetchProjectsLoading(); this.startFetchProjectsLoading();
let { data, error, aborted } = await fetchProjectGroupProjects( let { data, error, aborted } = await fetchProjectGroupProjects(
projectgroupref.join('/'), projectgroupref.join("/"),
this.fetchAbort.signal this.fetchAbort.signal
); );
this.stopFetchProjectsLoading(); this.stopFetchProjectsLoading();
@ -122,7 +115,7 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.projects = data; this.projects = data;
@ -134,7 +127,7 @@ export default {
} }
this.startFetchProjectGroupsLoading(); this.startFetchProjectGroupsLoading();
let { data, error, aborted } = await fetchProjectGroupSubgroups( let { data, error, aborted } = await fetchProjectGroupSubgroups(
projectgroupref.join('/'), projectgroupref.join("/"),
this.fetchAbort.signal this.fetchAbort.signal
); );
this.stopFetchProjectGroupsLoading(); this.stopFetchProjectGroupsLoading();
@ -142,15 +135,15 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.projectgroups = data; this.projectgroups = data;
}, },
projectLink: projectLink, projectLink: projectLink,
projectGroupLink: projectGroupLink, projectGroupLink: projectGroupLink
}, },
created: function () { created: function() {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
this.fetchProjects(this.ownertype, this.ownername); this.fetchProjects(this.ownertype, this.ownername);
this.fetchProjectGroups(this.ownertype, this.ownername); this.fetchProjectGroups(this.ownertype, this.ownername);
@ -159,8 +152,9 @@ export default {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -7,34 +7,33 @@
<hr class="my-6 border-t" /> <hr class="my-6 border-t" />
<h5 class="text-2xl">All secrets (local and inherited)</h5> <h5 class="text-2xl">All secrets (local and inherited)</h5>
<secrets <secrets v-if="allsecrets.length" :secrets="allsecrets" :showparentpath="true" />
v-if="allsecrets.length"
:secrets="allsecrets"
:showparentpath="true"
/>
<span v-else>No secrets</span> <span v-else>No secrets</span>
</div> </div>
</template> </template>
<script> <script>
import secrets from '@/components/secrets'; import secrets from "@/components/secrets";
export default { export default {
components: { secrets }, components: { secrets },
name: 'projectsecrets', name: "projectsecrets",
props: { props: {
secrets: Array, secrets: Array,
allsecrets: Array, allsecrets: Array,
type: String, type: String
}, },
computed: { computed: {
typetitle() { typetitle() {
if (this.type == 'project') return 'Project'; if (this.type == "project") return "Project";
if (this.type == 'projectgroup') return 'Project group'; if (this.type == "projectgroup") return "Project group";
return ''; return "";
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -21,8 +21,7 @@
<div class="mb-4"> <div class="mb-4">
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" v-model="project.pass_vars_to_forked_pr" /> <input type="checkbox" v-model="project.pass_vars_to_forked_pr" />
Pass variables to run even if triggered by PR from forked repo Pass variables to run even if triggered by PR from forked repo (DANGEROUS)
(DANGEROUS)
</label> </label>
</div> </div>
<button class="btn btn-blue" @click="updateProject()">Update</button> <button class="btn btn-blue" @click="updateProject()">Update</button>
@ -39,22 +38,14 @@
<div class="panel"> <div class="panel">
<p class="panel-title">Secrets</p> <p class="panel-title">Secrets</p>
<div class="p-4"> <div class="p-4">
<projectsecrets <projectsecrets :secrets="secrets" :allsecrets="allsecrets" type="project" />
:secrets="secrets"
:allsecrets="allsecrets"
type="project"
/>
</div> </div>
</div> </div>
<div class="panel"> <div class="panel">
<p class="panel-title">Variables</p> <p class="panel-title">Variables</p>
<div class="p-4"> <div class="p-4">
<projectvars <projectvars :variables="variables" :allvariables="allvariables" type="project" />
:variables="variables"
:allvariables="allvariables"
type="project"
/>
</div> </div>
</div> </div>
@ -68,13 +59,16 @@
> >
<p> <p>
This operation This operation
<strong>CANNOT</strong> be undone. This operation will remove <strong>CANNOT</strong> be undone.
<strong>{{ projectPath }}</strong> This operation will remove
<strong>{{projectPath}}</strong>
</p> </p>
</div> </div>
<label class="block mb-2"> <label class="block mb-2">
Please type the project name for confirmation: Please type the project name for confirmation:
<span class="text-red-500 font-bold">{{ projectName }}</span> <span
class="text-red-500 font-bold"
>{{ projectName }}</span>
</label> </label>
<div class="mb-4"> <div class="mb-4">
<input <input
@ -88,9 +82,7 @@
class="btn btn-red" class="btn btn-red"
@click="deleteProject()" @click="deleteProject()"
:disabled="!deleteButtonEnabled" :disabled="!deleteButtonEnabled"
> >Delete Project</button>
Delete Project
</button>
<div <div
v-if="deleteProjectError" v-if="deleteProjectError"
@ -101,30 +93,21 @@
</div> </div>
</div> </div>
<div class="p-4 border-t"> <div class="p-4 border-t">
<h4 class="mb-4 title text-xl"> <h4 class="mb-4 title text-xl">Change remote repository linked account</h4>
Change remote repository linked account
</h4>
<div <div
class="mb-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded" class="mb-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded"
role="alert" role="alert"
> >
<p> <p>This operation will change the linked account associated with the project remote repository to the current user linked account</p>
This operation will change the linked account associated with the
project remote repository to the current user linked account
</p>
</div> </div>
<button class="btn btn-red" @click="updateRepoLinkedAccount()"> <button class="btn btn-red" @click="updateRepoLinkedAccount()">Change</button>
Change
</button>
<div <div
v-if="updateRepoLinkedAccountError" v-if="updateRepoLinkedAccountError"
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
role="alert" role="alert"
> >
<span class="block sm:inline">{{ <span class="block sm:inline">{{ updateRepoLinkedAccountError }}</span>
updateRepoLinkedAccountError
}}</span>
</div> </div>
</div> </div>
</div> </div>
@ -138,21 +121,21 @@ import {
fetchVariables, fetchVariables,
updateProject, updateProject,
deleteProject, deleteProject,
projectUpdateRepoLinkedAccount, projectUpdateRepoLinkedAccount
} from '@/util/data.js'; } from "@/util/data.js";
import { projectGroupLink } from '@/util/link.js'; import { projectGroupLink } from "@/util/link.js";
import projectsecrets from '@/components/projectsecrets'; import projectsecrets from "@/components/projectsecrets";
import projectvars from '@/components/projectvars'; import projectvars from "@/components/projectvars";
export default { export default {
components: { projectsecrets, projectvars }, components: { projectsecrets, projectvars },
name: 'projectsettings', name: "projectsettings",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array
}, },
data() { data() {
return { return {
@ -165,19 +148,19 @@ export default {
allsecrets: [], allsecrets: [],
variables: [], variables: [],
allvariables: [], allvariables: [],
projectNameToDelete: '', projectNameToDelete: ""
}; };
}, },
computed: { computed: {
projectName: function () { projectName: function() {
return this.projectref[this.projectref.length - 1]; return this.projectref[this.projectref.length - 1];
}, },
projectPath: function () { projectPath: function() {
return ['', this.ownertype, this.ownername, ...this.projectref].join('/'); return ["", this.ownertype, this.ownername, ...this.projectref].join("/");
}, },
deleteButtonEnabled: function () { deleteButtonEnabled: function() {
return this.projectNameToDelete == this.projectName; return this.projectNameToDelete == this.projectName;
}, }
}, },
methods: { methods: {
resetErrors() { resetErrors() {
@ -191,12 +174,12 @@ export default {
let projectref = [ let projectref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectref, ...this.projectref
].join('/'); ].join("/");
let visibility = 'public'; let visibility = "public";
if (this.projectIsPrivate) { if (this.projectIsPrivate) {
visibility = 'private'; visibility = "private";
} }
let { error } = await updateProject( let { error } = await updateProject(
projectref, projectref,
@ -215,8 +198,8 @@ export default {
let projectref = [ let projectref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectref, ...this.projectref
].join('/'); ].join("/");
if (this.projectNameToDelete == this.projectName) { if (this.projectNameToDelete == this.projectName) {
let { error } = await deleteProject(projectref); let { error } = await deleteProject(projectref);
@ -239,59 +222,60 @@ export default {
let projectref = [ let projectref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectref, ...this.projectref
].join('/'); ].join("/");
let { error } = await projectUpdateRepoLinkedAccount(projectref); let { error } = await projectUpdateRepoLinkedAccount(projectref);
if (error) { if (error) {
this.updateRepoLinkedAccountError = error; this.updateRepoLinkedAccountError = error;
return; return;
} }
}
}, },
}, created: async function() {
created: async function () {
let projectref = [this.ownertype, this.ownername, ...this.projectref].join( let projectref = [this.ownertype, this.ownername, ...this.projectref].join(
'/' "/"
); );
let { data, error } = await fetchProject(projectref); let { data, error } = await fetchProject(projectref);
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.project = data; this.project = data;
this.projectIsPrivate = this.project.visibility == 'private'; this.projectIsPrivate = this.project.visibility == "private";
({ data, error } = await fetchSecrets('project', projectref, false)); ({ data, error } = await fetchSecrets("project", projectref, false));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.secrets = data; this.secrets = data;
({ data, error } = await fetchSecrets('project', projectref, true)); ({ data, error } = await fetchSecrets("project", projectref, true));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.allsecrets = data; this.allsecrets = data;
({ data, error } = await fetchVariables('project', projectref, false)); ({ data, error } = await fetchVariables("project", projectref, false));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.variables = data; this.variables = data;
({ data, error } = await fetchVariables('project', projectref, true)); ({ data, error } = await fetchVariables("project", projectref, true));
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.allvariables = data; this.allvariables = data;
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -7,34 +7,32 @@
<hr class="my-6 border-t" /> <hr class="my-6 border-t" />
<h5 class="text-2xl">All variables (local and inherited)</h5> <h5 class="text-2xl">All variables (local and inherited)</h5>
<vars <vars v-if="allvariables.length" :variables="allvariables" :showparentpath="true" />
v-if="allvariables.length"
:variables="allvariables"
:showparentpath="true"
/>
<span v-else>No variables</span> <span v-else>No variables</span>
</div> </div>
</template> </template>
<script> <script>
import vars from '@/components/vars'; import vars from "@/components/vars";
export default { export default {
components: { vars }, components: { vars },
name: 'projectvars', name: "projectvars",
props: { props: {
variables: Array, variables: Array,
allvariables: Array, allvariables: Array,
type: String, type: String
}, },
computed: { computed: {
typetitle() { typetitle() {
if (this.type == 'project') return 'Project'; if (this.type == "project") return "Project";
if (this.type == 'projectgroup') return 'Project group'; if (this.type == "projectgroup") return "Project group";
return ''; return "";
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -5,9 +5,7 @@
@submit.prevent="$emit('login', { username })" @submit.prevent="$emit('login', { username })"
> >
<div class="mb-4"> <div class="mb-4">
<label class="block text-sm font-bold mb-2" for="username" <label class="block text-sm font-bold mb-2" for="username">Remote Username</label>
>Remote Username</label
>
<input <input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="username" id="username"
@ -15,38 +13,38 @@
placeholder="Username" placeholder="Username"
:disabled="true" :disabled="true"
v-model="remoteUsername" v-model="remoteUsername"
/> >
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label class="block text-sm font-bold mb-2" for="username" <label class="block text-sm font-bold mb-2" for="username">Username</label>
>Username</label
>
<input <input
class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" class="appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline"
id="username" id="username"
type="text" type="text"
placeholder="Username" placeholder="Username"
v-model="username" v-model="username"
/> >
</div> </div>
<div class="flex justify-center"> <div class="flex justify-center">
<button <button
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit" type="submit"
> >Register</button>
Register
</button>
</div> </div>
</form> </form>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'RegisterForm', name: "RegisterForm",
props: { props: {
remoteUsername: String, remoteUsername: String,
username: String, username: String
}, }
}; };
</script> </script>

View File

@ -7,8 +7,8 @@
v-bind:key="repo.id" v-bind:key="repo.id"
@click="select(index)" @click="select(index)"
> >
<input type="radio" :checked="selectedrepo == index" /> <input type="radio" :checked="selectedrepo == index">
{{ repo.path }} {{repo.path}}
</label> </label>
</div> </div>
<div v-else class="block px-4 py-2 border-b">No remote repositories</div> <div v-else class="block px-4 py-2 border-b">No remote repositories</div>
@ -18,22 +18,23 @@
<script> <script>
export default { export default {
components: {}, components: {},
name: 'remoterepos', name: "remoterepos",
props: { props: {
remoterepos: Array, remoterepos: Array
}, },
data() { data() {
return { return {
selectedrepo: null, selectedrepo: null
}; };
}, },
methods: { methods: {
select(index) { select(index) {
this.selectedrepo = index; this.selectedrepo = index;
this.$emit('reposelected', this.remoterepos[index].path); this.$emit("reposelected", this.remoterepos[index].path);
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -27,29 +27,21 @@
<div class="p-4 border border-l-0 rounded-r flex"> <div class="p-4 border border-l-0 rounded-r flex">
<div class="w-4/6 items-start justify-between"> <div class="w-4/6 items-start justify-between">
<div class="flex items-center mb-1"> <div class="flex items-center mb-1">
<h2 class="text-2xl mr-3">{{ run.name }}</h2> <h2 class="text-2xl mr-3">{{run.name}}</h2>
<span <span
class="mr-3 rounded px-2 py-1 text-xs" class="mr-3 rounded px-2 py-1 text-xs"
:class="'is-' + runResultClass(run)" :class="'is-' + runResultClass(run)"
>{{ runStatus(run) | capitalize }}</span >{{ runStatus(run) | capitalize }}</span>
>
<span <span
v-if="stillRunning(run)" v-if="stillRunning(run)"
class="rounded bg-gray-500 text-white px-2 py-1 text-xs" class="rounded bg-gray-500 text-white px-2 py-1 text-xs"
>Still running</span >Still running</span>
>
</div>
<div class="mb-6">
{{ run.annotations.message.split(/\r?\n/)[0] }}
</div> </div>
<div class="mb-6">{{run.annotations.message.split(/\r?\n/)[0]}}</div>
<div> <div>
<a <a :href="run.annotations.commit_link" class="block" target="_blank">
:href="run.annotations.commit_link"
class="block"
target="_blank"
>
<i class="mdi mdi-source-commit mdi-rotate-90"></i> <i class="mdi mdi-source-commit mdi-rotate-90"></i>
<span>{{ run.annotations.commit_sha.substring(0, 8) }}</span> <span>{{run.annotations.commit_sha.substring(0,8)}}</span>
</a> </a>
<a <a
v-if="run.annotations.ref_type == 'branch'" v-if="run.annotations.ref_type == 'branch'"
@ -58,7 +50,7 @@
target="_blank" target="_blank"
> >
<i class="mdi mdi-source-branch"></i> <i class="mdi mdi-source-branch"></i>
<span>{{ run.annotations.branch }}</span> <span>{{run.annotations.branch}}</span>
</a> </a>
<a <a
v-else-if="run.annotations.ref_type == 'tag'" v-else-if="run.annotations.ref_type == 'tag'"
@ -67,7 +59,7 @@
target="_blank" target="_blank"
> >
<i class="mdi mdi-tag"></i> <i class="mdi mdi-tag"></i>
<span>{{ run.annotations.tag }}</span> <span>{{run.annotations.tag}}</span>
</a> </a>
<a <a
v-else-if="run.annotations.ref_type == 'pull_request'" v-else-if="run.annotations.ref_type == 'pull_request'"
@ -76,7 +68,7 @@
target="_blank" target="_blank"
> >
<i class="mdi mdi-source-pull"></i> <i class="mdi mdi-source-pull"></i>
<span>PR #{{ run.annotations.pull_request_id }}</span> <span>PR #{{run.annotations.pull_request_id}}</span>
</a> </a>
</div> </div>
</div> </div>
@ -93,18 +85,12 @@
<div class="w-1/6 flex items-start justify-between"> <div class="w-1/6 flex items-start justify-between">
<div class="relative ml-auto mr-3"> <div class="relative ml-auto mr-3">
<div <div
v-if=" v-if="run.can_restart_from_scratch || run.can_restart_from_failed_tasks"
run.can_restart_from_scratch ||
run.can_restart_from_failed_tasks
"
class="flex" class="flex"
v-click-outside="() => (dropdownActive = false)" v-click-outside="() => dropdownActive = false"
> >
<div class="flex items-center"> <div class="flex items-center">
<button <button class="btn btn-blue" @click="dropdownActive = !dropdownActive">
class="btn btn-blue"
@click="dropdownActive = !dropdownActive"
>
<span>Restart</span> <span>Restart</span>
<i class="ml-3 mdi mdi-restart" aria-hidden="true"></i> <i class="ml-3 mdi mdi-restart" aria-hidden="true"></i>
</button> </button>
@ -121,16 +107,14 @@
v-if="run.can_restart_from_scratch" v-if="run.can_restart_from_scratch"
class="block px-4 py-2 hover:bg-blue-500 hover:text-white cursor-pointer" class="block px-4 py-2 hover:bg-blue-500 hover:text-white cursor-pointer"
@click="restartRun(run.id, true)" @click="restartRun(run.id, true)"
>From start</a >From start</a>
>
</li> </li>
<li> <li>
<a <a
v-if="run.can_restart_from_failed_tasks" v-if="run.can_restart_from_failed_tasks"
class="block px-4 py-2 hover:bg-blue-500 hover:text-white cursor-pointer" class="block px-4 py-2 hover:bg-blue-500 hover:text-white cursor-pointer"
@click="restartRun(run.id)" @click="restartRun(run.id)"
>From failed tasks</a >From failed tasks</a>
>
</li> </li>
</ul> </ul>
</div> </div>
@ -138,17 +122,13 @@
class="btn btn-red" class="btn btn-red"
v-if="run.phase == 'queued'" v-if="run.phase == 'queued'"
@click="cancelRun(run.id)" @click="cancelRun(run.id)"
> >Cancel</button>
Cancel
</button>
<button <button
class="btn btn-red" class="btn btn-red"
v-if="run.phase == 'running'" v-if="run.phase == 'running'"
:disabled="run.stopping" :disabled="run.stopping"
@click="stopRun(run.id)" @click="stopRun(run.id)"
> >Stop</button>
Stop
</button>
</div> </div>
</div> </div>
</div> </div>
@ -158,27 +138,27 @@
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
import { cancelRun, stopRun, restartRun } from '@/util/data.js'; import { cancelRun, stopRun, restartRun } from "@/util/data.js";
import { userDirectRunLink, projectRunLink } from '@/util/link.js'; import { userDirectRunLink, projectRunLink } from "@/util/link.js";
import { runStatus, runResultClass } from '@/util/run.js'; import { runStatus, runResultClass } from "@/util/run.js";
import * as moment from 'moment'; import * as moment from "moment";
import momentDurationFormatSetup from 'moment-duration-format'; import momentDurationFormatSetup from "moment-duration-format";
momentDurationFormatSetup(moment); momentDurationFormatSetup(moment);
export default { export default {
name: 'rundetail', name: "rundetail",
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array,
run: Object, run: Object
}, },
data() { data() {
return { return {
@ -186,7 +166,7 @@ export default {
stopRunError: null, stopRunError: null,
cancelRunError: null, cancelRunError: null,
restartRunError: null, restartRunError: null,
dropdownActive: false, dropdownActive: false
}; };
}, },
methods: { methods: {
@ -198,14 +178,14 @@ export default {
this.restartRunError = null; this.restartRunError = null;
}, },
stillRunning(run) { stillRunning(run) {
return run.result != 'unknown' && run.phase == 'running'; return run.result != "unknown" && run.phase == "running";
}, },
taskClass(task) { taskClass(task) {
if (task.status == 'success') return 'success'; if (task.status == "success") return "success";
if (task.status == 'failed') return 'failed'; if (task.status == "failed") return "failed";
if (task.status == 'stopped') return 'failed'; if (task.status == "stopped") return "failed";
if (task.status == 'running') return 'running'; if (task.status == "running") return "running";
return 'unknown'; return "unknown";
}, },
async stopRun(runid) { async stopRun(runid) {
this.resetErrors(); this.resetErrors();
@ -227,7 +207,7 @@ export default {
return; return;
} }
this.run.phase = 'cancelled'; this.run.phase = "cancelled";
}, },
async restartRun(runid, fromStart) { async restartRun(runid, fromStart) {
this.dropdownActive = false; this.dropdownActive = false;
@ -251,7 +231,7 @@ export default {
this.$router.push(runLink); this.$router.push(runLink);
}, },
duration(run) { duration(run) {
let formatString = 'h:mm:ss[s]'; let formatString = "h:mm:ss[s]";
let start = moment(run.start_time); let start = moment(run.start_time);
let end = moment(run.end_time); let end = moment(run.end_time);
@ -264,29 +244,30 @@ export default {
return moment.duration(end.diff(start)).format(formatString); return moment.duration(end.diff(start)).format(formatString);
}, },
endTime(run) { endTime(run) {
let formatString = 'lll'; let formatString = "lll";
let end = moment(run.end_time); let end = moment(run.end_time);
if (run.end_time === null) { if (run.end_time === null) {
return ''; return "";
} }
return 'Finished ' + end.format(formatString); return "Finished " + end.format(formatString);
}, },
endTimeHuman(run) { endTimeHuman(run) {
let end = moment(run.end_time); let end = moment(run.end_time);
if (run.end_time === null) { if (run.end_time === null) {
return ''; return "";
} }
return end.fromNow(); return end.fromNow();
}
}, },
}, created: function() {
created: function () {
window.setInterval(() => { window.setInterval(() => {
this.now = moment(); this.now = moment();
}, 500); }, 500);
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -9,7 +9,7 @@
</div> </div>
<div class="ml-6 flex w-48"> <div class="ml-6 flex w-48">
<div v-bind:class="{ spinner: fetchRunsLoading }"></div> <div v-bind:class="{ 'spinner': fetchRunsLoading }"></div>
</div> </div>
<div v-if="runs"> <div v-if="runs">
<ul> <ul>
@ -27,21 +27,21 @@
class="whitespace-no-wrap overflow-x-hidden" class="whitespace-no-wrap overflow-x-hidden"
> >
<i class="mdi mdi-source-branch mr-1"></i> <i class="mdi mdi-source-branch mr-1"></i>
<span>{{ run.annotations.branch }}</span> <span>{{run.annotations.branch}}</span>
</div> </div>
<div <div
v-else-if="run.annotations.ref_type == 'tag'" v-else-if="run.annotations.ref_type == 'tag'"
class="whitespace-no-wrap overflow-x-hidden" class="whitespace-no-wrap overflow-x-hidden"
> >
<i class="mdi mdi-tag mr-1"></i> <i class="mdi mdi-tag mr-1"></i>
<span>{{ run.annotations.tag }}</span> <span>{{run.annotations.tag}}</span>
</div> </div>
<div <div
v-else-if="run.annotations.ref_type == 'pull_request'" v-else-if="run.annotations.ref_type == 'pull_request'"
class="whitespace-no-wrap overflow-x-hidden" class="whitespace-no-wrap overflow-x-hidden"
> >
<i class="mdi mdi-source-pull mr-1"></i> <i class="mdi mdi-source-pull mr-1"></i>
<span>PR #{{ run.annotations.pull_request_id }}</span> <span>PR #{{run.annotations.pull_request_id}}</span>
</div> </div>
</div> </div>
<div v-else class="w-2/12"> <div v-else class="w-2/12">
@ -53,36 +53,30 @@
class="w-5/12 pl-3 mr-auto whitespace-no-wrap overflow-hidden" class="w-5/12 pl-3 mr-auto whitespace-no-wrap overflow-hidden"
:to="projectRunLink(ownertype, ownername, projectref, run.id)" :to="projectRunLink(ownertype, ownername, projectref, run.id)"
> >
<span class="font-bold">{{ run.name }}</span> <span class="font-bold">{{run.name}}</span>
<div>{{ run.annotations.message.split(/\r?\n/)[0] }}</div> <div>{{run.annotations.message.split(/\r?\n/)[0]}}</div>
</router-link> </router-link>
<router-link <router-link
v-else v-else
class="w-5/12 pl-3 mr-auto whitespace-no-wrap overflow-hidden" class="w-5/12 pl-3 mr-auto whitespace-no-wrap overflow-hidden"
:to="userDirectRunLink(ownername, run.id)" :to="userDirectRunLink(ownername, run.id)"
> >
<span class="font-bold">{{ run.name }}</span> <span class="font-bold">{{run.name}}</span>
<div>{{ run.annotations.message.split(/\r?\n/)[0] }}</div> <div>{{run.annotations.message.split(/\r?\n/)[0]}}</div>
</router-link> </router-link>
<span <span
v-if="waitingApproval(run)" v-if="waitingApproval(run)"
class="w-2/12 bg-gray-200 rounded-full px-3 py-1 text-sm text-center font-semibold mr-2" class="w-2/12 bg-gray-200 rounded-full px-3 py-1 text-sm text-center font-semibold mr-2"
>Waiting Approval</span >Waiting Approval</span>
>
<span <span
v-if="stillRunning(run)" v-if="stillRunning(run)"
class="w-2/12 bg-gray-200 rounded-full px-3 py-1 text-sm text-center font-semibold mr-2" class="w-2/12 bg-gray-200 rounded-full px-3 py-1 text-sm text-center font-semibold mr-2"
>Still running</span >Still running</span>
>
<div class="w-32"> <div class="w-32">
<span>#{{ run.counter }}</span> <span>#{{run.counter}}</span>
<a <a :href="run.annotations.commit_link" class="block" target="_blank">
:href="run.annotations.commit_link"
class="block"
target="_blank"
>
<i class="mdi mdi-source-commit mdi-rotate-90 mr-1"></i> <i class="mdi mdi-source-commit mdi-rotate-90 mr-1"></i>
<span>{{ run.annotations.commit_sha.substring(0, 8) }}</span> <span>{{run.annotations.commit_sha.substring(0,8)}}</span>
</a> </a>
</div> </div>
<div class="w-32"> <div class="w-32">
@ -103,9 +97,7 @@
v-if="hasMoreRuns" v-if="hasMoreRuns"
class="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded" class="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded"
@click="loadMoreRuns()" @click="loadMoreRuns()"
> >Load more...</button>
Load more...
</button>
</div> </div>
</div> </div>
<div v-if="runs && runs.length == 0" class>No runs</div> <div v-if="runs && runs.length == 0" class>No runs</div>
@ -113,22 +105,22 @@
</template> </template>
<script> <script>
import { fetchUser, fetchProject, fetchRuns } from '@/util/data.js'; import { fetchUser, fetchProject, fetchRuns } from "@/util/data.js";
import { userDirectRunLink, projectRunLink } from '@/util/link.js'; import { userDirectRunLink, projectRunLink } from "@/util/link.js";
import { runResultClass } from '@/util/run.js'; import { runResultClass } from "@/util/run.js";
import * as moment from 'moment'; import * as moment from "moment";
import momentDurationFormatSetup from 'moment-duration-format'; import momentDurationFormatSetup from "moment-duration-format";
momentDurationFormatSetup(moment); momentDurationFormatSetup(moment);
export default { export default {
components: {}, components: {},
name: 'runs', name: "runs",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array,
query: String, query: String
}, },
data() { data() {
return { return {
@ -145,15 +137,15 @@ export default {
wantedRunsNumber: 25, wantedRunsNumber: 25,
hasMoreRuns: false, hasMoreRuns: false,
project: null, project: null,
user: null, user: null
}; };
}, },
watch: { watch: {
$route: function () { $route: function() {
this.runs = null; this.runs = null;
this.hasMoreRuns = false; this.hasMoreRuns = false;
this.update(); this.update();
}, }
}, },
methods: { methods: {
projectRunLink: projectRunLink, projectRunLink: projectRunLink,
@ -169,7 +161,7 @@ export default {
this.fetchRunsLoading = false; this.fetchRunsLoading = false;
}, },
stillRunning(run) { stillRunning(run) {
return run.result != 'unknown' && run.phase == 'running'; return run.result != "unknown" && run.phase == "running";
}, },
waitingApproval(run) { waitingApproval(run) {
return run.tasks_waiting_approval.length > 0; return run.tasks_waiting_approval.length > 0;
@ -191,8 +183,8 @@ export default {
let projectref = [ let projectref = [
this.ownertype, this.ownertype,
this.ownername, this.ownername,
...this.projectref, ...this.projectref
].join('/'); ].join("/");
let { data, error, aborted } = await fetchProject( let { data, error, aborted } = await fetchProject(
projectref, projectref,
@ -202,7 +194,7 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.project = data; this.project = data;
@ -220,7 +212,7 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.user = data; this.user = data;
@ -236,17 +228,17 @@ export default {
let group; let group;
let lastrun = false; let lastrun = false;
if (this.project !== null) { if (this.project !== null) {
if (this.query == 'branches') { if (this.query == "branches") {
group = '/project/' + this.project.id + '/branch'; group = "/project/" + this.project.id + "/branch";
} else if (this.query == 'tags') { } else if (this.query == "tags") {
group = '/project/' + this.project.id + '/tag'; group = "/project/" + this.project.id + "/tag";
} else if (this.query == 'pullrequests') { } else if (this.query == "pullrequests") {
group = '/project/' + this.project.id + '/pr'; group = "/project/" + this.project.id + "/pr";
} else { } else {
group = '/project/' + this.project.id; group = "/project/" + this.project.id;
} }
} else if (this.user !== null) { } else if (this.user !== null) {
group = '/user/' + this.user.id; group = "/user/" + this.user.id;
} }
let newRuns = []; let newRuns = [];
@ -297,7 +289,7 @@ export default {
}, 2000); }, 2000);
}, },
duration(run) { duration(run) {
let formatString = 'h:mm:ss[s]'; let formatString = "h:mm:ss[s]";
let start = moment(run.start_time); let start = moment(run.start_time);
let end = moment(run.end_time); let end = moment(run.end_time);
@ -310,24 +302,24 @@ export default {
return moment.duration(end.diff(start)).format(formatString); return moment.duration(end.diff(start)).format(formatString);
}, },
endTime(run) { endTime(run) {
let formatString = 'lll'; let formatString = "lll";
let end = moment(run.end_time); let end = moment(run.end_time);
if (run.end_time === null) { if (run.end_time === null) {
return ''; return "";
} }
return 'Finished ' + end.format(formatString); return "Finished " + end.format(formatString);
}, },
endTimeHuman(run) { endTimeHuman(run) {
let end = moment(run.end_time); let end = moment(run.end_time);
if (run.end_time === null) { if (run.end_time === null) {
return ''; return "";
} }
return end.fromNow(); return end.fromNow();
}
}, },
}, created: function() {
created: function () {
window.setInterval(() => { window.setInterval(() => {
this.now = moment(); this.now = moment();
}, 500); }, 500);
@ -339,8 +331,9 @@ export default {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
clearTimeout(this.fetchRunsSchedule); clearTimeout(this.fetchRunsSchedule);
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -7,12 +7,7 @@
> >
<div>{{ fetchRunError }}</div> <div>{{ fetchRunError }}</div>
</div> </div>
<rundetail <rundetail :run="run" :ownertype="ownertype" :ownername="ownername" :projectref="projectref" />
:run="run"
:ownertype="ownertype"
:ownername="ownername"
:projectref="projectref"
/>
<div v-if="run"> <div v-if="run">
<div v-if="run.phase != 'setuperror'"> <div v-if="run.phase != 'setuperror'">
<div class="flex items-center my-6 justify-between"> <div class="flex items-center my-6 justify-between">
@ -22,7 +17,7 @@
<button <button
@click="tasksDisplay = 'graph'" @click="tasksDisplay = 'graph'"
class="relative flex items-center focus:outline-none bg-blue-500 hover:bg-blue-600 text-white font-semibold hover:text-white py-2 px-4 border border-blue-700 rounded rounded-r-none" class="relative flex items-center focus:outline-none bg-blue-500 hover:bg-blue-600 text-white font-semibold hover:text-white py-2 px-4 border border-blue-700 rounded rounded-r-none"
:class="{ 'bg-blue-600': tasksDisplay == 'graph' }" :class="{ 'bg-blue-600': tasksDisplay=='graph'}"
title="Tasks Graph" title="Tasks Graph"
> >
<i class="mr-1 mdi mdi-file-tree" /> <i class="mr-1 mdi mdi-file-tree" />
@ -31,7 +26,7 @@
@click="tasksDisplay = 'list'" @click="tasksDisplay = 'list'"
class="relative flex items-center focus:outline-none bg-blue-500 hover:bg-blue-600 text-white font-semibold hover:text-white py-2 px-4 border border-l-0 border-blue-700 rounded rounded-l-none" class="relative flex items-center focus:outline-none bg-blue-500 hover:bg-blue-600 text-white font-semibold hover:text-white py-2 px-4 border border-l-0 border-blue-700 rounded rounded-l-none"
title="Tasks List" title="Tasks List"
:class="{ 'bg-blue-600': tasksDisplay == 'list' }" :class="{ 'bg-blue-600': tasksDisplay=='list'}"
> >
<i class="mr-1 mdi mdi-format-list-bulleted-square" /> <i class="mr-1 mdi mdi-format-list-bulleted-square" />
</button> </button>
@ -47,8 +42,7 @@
class="font-mono leading-snug text-xs" class="font-mono leading-snug text-xs"
v-for="(error, i) in run.setup_errors" v-for="(error, i) in run.setup_errors"
v-bind:key="i" v-bind:key="i"
>{{ error }}</pre >{{error}}</pre>
>
</div> </div>
</div> </div>
</div> </div>
@ -56,21 +50,21 @@
</template> </template>
<script> <script>
import { fetchRun } from '@/util/data.js'; import { fetchRun } from "@/util/data.js";
import { userDirectRunTaskLink, projectRunTaskLink } from '@/util/link.js'; import { userDirectRunTaskLink, projectRunTaskLink } from "@/util/link.js";
import rundetail from '@/components/rundetail.vue'; import rundetail from "@/components/rundetail.vue";
import tasks from '@/components/tasks.vue'; import tasks from "@/components/tasks.vue";
import tasksgraph from '@/components/tasksgraph.vue'; import tasksgraph from "@/components/tasksgraph.vue";
export default { export default {
name: 'runsummary', name: "runsummary",
components: { rundetail, tasks, tasksgraph }, components: { rundetail, tasks, tasksgraph },
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array,
runid: String, runid: String
}, },
data() { data() {
return { return {
@ -86,11 +80,11 @@ export default {
taskYSpace: 20, taskYSpace: 20,
hoverTask: null, hoverTask: null,
tasksDisplay: 'graph', tasksDisplay: "graph"
}; };
}, },
watch: { watch: {
$route: async function () { $route: async function() {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
@ -99,7 +93,7 @@ export default {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
this.fetchRun(); this.fetchRun();
}, }
}, },
methods: { methods: {
runTaskLink(task) { runTaskLink(task) {
@ -116,16 +110,16 @@ export default {
} }
}, },
parents(task) { parents(task) {
return Object.keys(task.depends).map((key) => { return Object.keys(task.depends).map(key => {
return this.run.tasks[task.depends[key].task_id].name; return this.run.tasks[task.depends[key].task_id].name;
}); });
}, },
taskClass(task) { taskClass(task) {
if (task.status == 'success') return 'success'; if (task.status == "success") return "success";
if (task.status == 'failed') return 'failed'; if (task.status == "failed") return "failed";
if (task.status == 'stopped') return 'failed'; if (task.status == "stopped") return "failed";
if (task.status == 'running') return 'running'; if (task.status == "running") return "running";
return 'unknown'; return "unknown";
}, },
async fetchRun() { async fetchRun() {
let { data, error, aborted } = await fetchRun( let { data, error, aborted } = await fetchRun(
@ -151,8 +145,9 @@ export default {
let task = tasks[taskID]; let task = tasks[taskID];
task.link = this.runTaskLink(task); task.link = this.runTaskLink(task);
task.parents = this.parents(task); task.parents = this.parents(task);
task.waiting_approval = task.waiting_approval = this.run.tasks_waiting_approval.includes(
this.run.tasks_waiting_approval.includes(taskID); taskID
);
} }
this.scheduleFetchRun(); this.scheduleFetchRun();
@ -162,9 +157,9 @@ export default {
this.fetchRunSchedule = setTimeout(() => { this.fetchRunSchedule = setTimeout(() => {
this.fetchRun(); this.fetchRun();
}, 2000); }, 2000);
}
}, },
}, created: function() {
created: function () {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
this.fetchRun(); this.fetchRun();
}, },
@ -173,8 +168,9 @@ export default {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
clearTimeout(this.fetchRunSchedule); clearTimeout(this.fetchRunSchedule);
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -5,10 +5,8 @@
</div> </div>
<div class="flex" v-for="secret in secrets" v-bind:key="secret.id"> <div class="flex" v-for="secret in secrets" v-bind:key="secret.id">
<div class="w-2/12"> <div class="w-2/12">
<span class="name">{{ secret.name }}</span> <span class="name">{{secret.name}}</span>
<div v-if="showparentpath" class="text-sm font-light"> <div v-if="showparentpath" class="text-sm font-light">from {{secret.parent_path}}</div>
from {{ secret.parent_path }}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -17,12 +15,16 @@
<script> <script>
export default { export default {
components: {}, components: {},
name: 'secrets', name: "secrets",
props: { props: {
secrets: Array, secrets: Array,
showparentpath: Boolean, showparentpath: Boolean
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -12,7 +12,7 @@
class="inline-block mr-1 mdi mdi-arrow-right" class="inline-block mr-1 mdi mdi-arrow-right"
:class="{ 'arrow-down': active, 'arrow-right': !active }" :class="{ 'arrow-down': active, 'arrow-right': !active }"
></i> ></i>
<span class="w-1/3 font-bold">{{ step.name }}</span> <span class="w-1/3 font-bold">{{step.name}}</span>
</div> </div>
<span class>{{ duration }}</span> <span class>{{ duration }}</span>
</div> </div>
@ -20,24 +20,18 @@
<div v-if="step.type == 'run'"> <div v-if="step.type == 'run'">
<div class="p-3 rounded-t bg-gray-900 text-white"> <div class="p-3 rounded-t bg-gray-900 text-white">
<span> <span>
<span <span class="w-2/12 bg-gray-700 rounded-l px-3 py-1 text-center font-semibold">Shell</span>
class="w-2/12 bg-gray-700 rounded-l px-3 py-1 text-center font-semibold"
>Shell</span
>
<span <span
class="w-2/12 bg-gray-600 rounded-r px-3 py-1 text-center font-semibold mr-2" class="w-2/12 bg-gray-600 rounded-r px-3 py-1 text-center font-semibold mr-2"
>{{ step.shell }}</span >{{ step.shell}}</span>
>
</span> </span>
<span v-if="step.exit_status != undefined"> <span v-if="step.exit_status != undefined">
<span <span
class="w-2/12 bg-gray-700 rounded-l px-3 py-1 text-center font-semibold" class="w-2/12 bg-gray-700 rounded-l px-3 py-1 text-center font-semibold"
>Exit Status</span >Exit Status</span>
>
<span <span
class="w-2/12 bg-gray-600 rounded-r px-3 py-1 text-center font-semibold mr-2" class="w-2/12 bg-gray-600 rounded-r px-3 py-1 text-center font-semibold mr-2"
>{{ step.exit_status }}</span >{{ step.exit_status}}</span>
>
</span> </span>
</div> </div>
<div <div
@ -46,27 +40,22 @@
> >
<i <i
class="inline-block mr-1 mdi mdi-arrow-right" class="inline-block mr-1 mdi mdi-arrow-right"
:class="{ :class="{ 'arrow-down': commandActive, 'arrow-right': !commandActive }"
'arrow-down': commandActive,
'arrow-right': !commandActive,
}"
></i> ></i>
<span>Command</span> <span>Command</span>
</div> </div>
<div <div
v-show="commandActive" v-show="commandActive"
class="p-3 bg-gray-900 text-white overflow-x-auto" class="p-3 bg-gray-900 text-white overflow-x-auto"
:class="{ rounded: step.type != 'run' }" :class="{ 'rounded': step.type != 'run' }"
> >
<pre class="font-mono text-xs">{{ step.command }}</pre> <pre class="font-mono text-xs">{{ step.command}}</pre>
</div> </div>
</div> </div>
<div v-if="step.type == 'run'" class="px-3 py-2 bg-gray-700 text-white"> <div v-if="step.type == 'run'" class="px-3 py-2 bg-gray-700 text-white">Log</div>
Log
</div>
<div <div
class="p-3 rounded-b bg-gray-900 text-white" class="p-3 rounded-b bg-gray-900 text-white"
:class="{ rounded: step.type != 'run' }" :class="{ 'rounded': step.type != 'run' }"
> >
<Log <Log
v-bind:runid="runid" v-bind:runid="runid"
@ -83,22 +72,22 @@
</template> </template>
<script> <script>
import * as moment from 'moment'; import * as moment from "moment";
import momentDurationFormatSetup from 'moment-duration-format'; import momentDurationFormatSetup from "moment-duration-format";
import Log from '@/components/log.vue'; import Log from "@/components/log.vue";
momentDurationFormatSetup(moment); momentDurationFormatSetup(moment);
export default { export default {
name: 'step', name: "step",
components: { components: {
Log, Log
}, },
data() { data() {
return { return {
active: false, active: false,
commandActive: true, commandActive: true,
now: moment(), now: moment()
}; };
}, },
props: { props: {
@ -106,11 +95,11 @@ export default {
taskid: String, taskid: String,
setup: Boolean, setup: Boolean,
stepnum: Number, stepnum: Number,
step: Object, step: Object
}, },
computed: { computed: {
duration() { duration() {
let formatString = 'h:mm:ss[s]'; let formatString = "h:mm:ss[s]";
let start = moment(this.step.start_time); let start = moment(this.step.start_time);
let end = moment(this.step.end_time); let end = moment(this.step.end_time);
@ -123,12 +112,12 @@ export default {
return moment.duration(end.diff(start)).format(formatString); return moment.duration(end.diff(start)).format(formatString);
}, },
stepClass() { stepClass() {
if (this.step.phase == 'success') return 'success'; if (this.step.phase == "success") return "success";
if (this.step.phase == 'failed') return 'failed'; if (this.step.phase == "failed") return "failed";
if (this.step.phase == 'stopped') return 'failed'; if (this.step.phase == "stopped") return "failed";
if (this.step.phase == 'running') return 'running'; if (this.step.phase == "running") return "running";
return 'unknown'; return "unknown";
}, }
}, },
methods: { methods: {
toggle() { toggle() {
@ -136,13 +125,13 @@ export default {
}, },
toggleCommand() { toggleCommand() {
this.commandActive = !this.commandActive; this.commandActive = !this.commandActive;
}, }
}, },
created() { created() {
window.setInterval(() => { window.setInterval(() => {
this.now = moment(); this.now = moment();
}, 500); }, 500);
}, }
}; };
</script> </script>

View File

@ -1,18 +1,14 @@
<template> <template>
<div class="arrow"> <div class="arrow">
<svg viewBox="0 0 15 15"> <svg viewBox="0 0 15 15">
<path <path fill="none" stroke="#9d9d9d" d="M4.32.5l6.247 6.942L4.32 14.5"></path>
fill="none"
stroke="#9d9d9d"
d="M4.32.5l6.247 6.942L4.32 14.5"
></path>
</svg> </svg>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'tabarrow', name: "tabarrow"
}; };
</script> </script>

View File

@ -2,31 +2,24 @@
<ul> <ul>
<li v-for="task in sortedTasks" v-bind:key="task.id"> <li v-for="task in sortedTasks" v-bind:key="task.id">
<div class="mb-2 border-l-5 rounded-l" :class="taskClass(task)"> <div class="mb-2 border-l-5 rounded-l" :class="taskClass(task)">
<div <div class="px-4 py-4 flex justify-between items-center border border-l-0 rounded-r">
class="px-4 py-4 flex justify-between items-center border border-l-0 rounded-r"
>
<router-link class="w-1/3 font-bold" tag="a" :to="task.link"> <router-link class="w-1/3 font-bold" tag="a" :to="task.link">
<span class="w-1/3 font-bold">{{ task.name }}</span> <span class="w-1/3 font-bold">{{task.name}}</span>
</router-link> </router-link>
<div class="w-1/4"> <div class="w-1/4">
<span <span
v-if="task.waiting_approval" v-if="task.waiting_approval"
class="w-2/12 bg-gray-200 rounded-full px-3 py-1 text-sm text-center font-semibold mr-2" class="w-2/12 bg-gray-200 rounded-full px-3 py-1 text-sm text-center font-semibold mr-2"
>Waiting Approval</span >Waiting Approval</span>
>
</div> </div>
<div class="w-1/4"> <div class="w-1/4">
<span class="block text-xs" v-if="task.parents.length > 0" <span class="block text-xs" v-if="task.parents.length > 0">depends on: &nbsp;</span>
>depends on: &nbsp;</span
>
<ul> <ul>
<li <li
class="font-thin text-xs text-gray-600" class="font-thin text-xs text-gray-600"
v-for="dep in task.parents" v-for="dep in task.parents"
v-bind:key="dep" v-bind:key="dep"
> >{{dep}}</li>
{{ dep }}
</li>
</ul> </ul>
</div> </div>
<span class="w-16 text-right">{{ task.duration }}</span> <span class="w-16 text-right">{{ task.duration }}</span>
@ -37,21 +30,21 @@
</template> </template>
<script> <script>
import * as moment from 'moment'; import * as moment from "moment";
import momentDurationFormatSetup from 'moment-duration-format'; import momentDurationFormatSetup from "moment-duration-format";
momentDurationFormatSetup(moment); momentDurationFormatSetup(moment);
export default { export default {
name: 'tasks', name: "tasks",
components: {}, components: {},
data() { data() {
return { return {
now: moment(), now: moment()
}; };
}, },
props: { props: {
tasks: Object, tasks: Object
}, },
computed: { computed: {
sortedTasks() { sortedTasks() {
@ -66,18 +59,18 @@ export default {
? -1 ? -1
: 0 : 0
) )
.map((k) => tasks[k]); .map(k => tasks[k]);
for (let task of sortedTasks) { for (let task of sortedTasks) {
task.duration = this.duration(task); task.duration = this.duration(task);
} }
return sortedTasks; return sortedTasks;
}, }
}, },
methods: { methods: {
duration(task) { duration(task) {
let formatString = 'h:mm:ss[s]'; let formatString = "h:mm:ss[s]";
let start = moment(task.start_time); let start = moment(task.start_time);
let end = moment(task.end_time); let end = moment(task.end_time);
@ -90,18 +83,18 @@ export default {
return moment.duration(end.diff(start)).format(formatString); return moment.duration(end.diff(start)).format(formatString);
}, },
taskClass(task) { taskClass(task) {
if (task.status == 'success') return 'success'; if (task.status == "success") return "success";
if (task.status == 'failed') return 'failed'; if (task.status == "failed") return "failed";
if (task.status == 'stopped') return 'failed'; if (task.status == "stopped") return "failed";
if (task.status == 'running') return 'running'; if (task.status == "running") return "running";
if (task.status == 'skipped') return 'skipped'; if (task.status == "skipped") return "skipped";
return 'unknown'; return "unknown";
}, }
}, },
created() { created() {
window.setInterval(() => { window.setInterval(() => {
this.now = moment(); this.now = moment();
}, 500); }, 500);
}, }
}; };
</script> </script>

View File

@ -64,13 +64,13 @@
</template> </template>
<script> <script>
import * as moment from 'moment'; import * as moment from "moment";
import momentDurationFormatSetup from 'moment-duration-format'; import momentDurationFormatSetup from "moment-duration-format";
momentDurationFormatSetup(moment); momentDurationFormatSetup(moment);
export default { export default {
name: 'tasksgraph', name: "tasksgraph",
components: {}, components: {},
data() { data() {
return { return {
@ -85,14 +85,14 @@ export default {
taskYSpace: 20, taskYSpace: 20,
hoverTask: null, hoverTask: null,
height: '400px', height: "400px"
}; };
}, },
props: { props: {
tasks: Object, tasks: Object
}, },
computed: { computed: {
segments: function () { segments: function() {
let segments = []; let segments = [];
for (let edge of this.edges) { for (let edge of this.edges) {
for (let i = 0; i < edge.edgePoints.length - 1; i++) { for (let i = 0; i < edge.edgePoints.length - 1; i++) {
@ -107,7 +107,7 @@ export default {
} }
// TODO(sgotti) set different colors to edges based on source task status??? // TODO(sgotti) set different colors to edges based on source task status???
let stroke = 'text-dark'; let stroke = "text-dark";
segments.push({ segments.push({
edge: edge, edge: edge,
x1: edge.edgePoints[i].x, x1: edge.edgePoints[i].x,
@ -115,7 +115,7 @@ export default {
x2: edge.edgePoints[i + 1].x, x2: edge.edgePoints[i + 1].x,
y2: edge.edgePoints[i + 1].y, y2: edge.edgePoints[i + 1].y,
strokeWidth: strokeWidth, strokeWidth: strokeWidth,
stroke: stroke, stroke: stroke
}); });
} }
} }
@ -130,16 +130,16 @@ export default {
} }
return this.graphTasks; return this.graphTasks;
}, }
}, },
watch: { watch: {
tasks: function (tasks) { tasks: function(tasks) {
this.update(tasks); this.update(tasks);
}, }
}, },
methods: { methods: {
duration(task) { duration(task) {
let formatString = 'h:mm:ss[s]'; let formatString = "h:mm:ss[s]";
let start = moment(task.start_time); let start = moment(task.start_time);
let end = moment(task.end_time); let end = moment(task.end_time);
@ -152,12 +152,12 @@ export default {
return moment.duration(end.diff(start)).format(formatString); return moment.duration(end.diff(start)).format(formatString);
}, },
taskClass(task) { taskClass(task) {
if (task.status == 'success') return 'success'; if (task.status == "success") return "success";
if (task.status == 'failed') return 'failed'; if (task.status == "failed") return "failed";
if (task.status == 'stopped') return 'failed'; if (task.status == "stopped") return "failed";
if (task.status == 'running') return 'running'; if (task.status == "running") return "running";
if (task.status == 'skipped') return 'skipped'; if (task.status == "skipped") return "skipped";
return 'unknown'; return "unknown";
}, },
update(tasks) { update(tasks) {
// sort tasks by level // sort tasks by level
@ -169,7 +169,7 @@ export default {
? -1 ? -1
: 0 : 0
) )
.map((k) => tasks[k]); .map(k => tasks[k]);
this.graphTasks = graphTasks; this.graphTasks = graphTasks;
@ -180,7 +180,7 @@ export default {
} }
} }
let taskChilds = function (tasks, task) { let taskChilds = function(tasks, task) {
let childs = []; let childs = [];
for (let ot of tasks) { for (let ot of tasks) {
for (let depTaskID in ot.depends) { for (let depTaskID in ot.depends) {
@ -192,7 +192,7 @@ export default {
return childs; return childs;
}; };
let taskMaxChildLevel = function (tasks, task) { let taskMaxChildLevel = function(tasks, task) {
let level = task.level; let level = task.level;
let childs = taskChilds(tasks, task); let childs = taskChilds(tasks, task);
for (let child of childs) { for (let child of childs) {
@ -203,7 +203,7 @@ export default {
return level; return level;
}; };
let levelTasks = function (tasks, level) { let levelTasks = function(tasks, level) {
let levelTasks = []; let levelTasks = [];
for (let task of tasks) { for (let task of tasks) {
if (task.level != level) { if (task.level != level) {
@ -214,7 +214,7 @@ export default {
return levelTasks; return levelTasks;
}; };
let levelsTasks = function (tasks, startLevel) { let levelsTasks = function(tasks, startLevel) {
let levelTasks = []; let levelTasks = [];
for (let task of tasks) { for (let task of tasks) {
if (task.level < startLevel) { if (task.level < startLevel) {
@ -225,13 +225,13 @@ export default {
return levelTasks; return levelTasks;
}; };
let levelsTasksByRow = function (tasks, startLevel) { let levelsTasksByRow = function(tasks, startLevel) {
return levelsTasks(tasks, startLevel).sort((a, b) => return levelsTasks(tasks, startLevel).sort((a, b) =>
a.row > b.row ? 1 : b.row > a.row ? -1 : 0 a.row > b.row ? 1 : b.row > a.row ? -1 : 0
); );
}; };
let levelFreeRow = function (tasks, level) { let levelFreeRow = function(tasks, level) {
let rows = []; let rows = [];
for (let task of tasks) { for (let task of tasks) {
if (task.level != level) { if (task.level != level) {
@ -255,7 +255,7 @@ export default {
return prevrow; return prevrow;
}; };
let levelsMaxRow = function (tasks, level) { let levelsMaxRow = function(tasks, level) {
let row = 0; let row = 0;
for (let task of tasks) { for (let task of tasks) {
if (level >= 0 && task.level > level) { if (level >= 0 && task.level > level) {
@ -344,7 +344,7 @@ export default {
sourceTask: pTask, sourceTask: pTask,
targetTask: curTask, targetTask: curTask,
source: { level: pTask.level, row: pTask.row }, source: { level: pTask.level, row: pTask.row },
target: { level: curTask.level, row: curTask.row }, target: { level: curTask.level, row: curTask.row }
}); });
} }
} }
@ -362,30 +362,30 @@ export default {
edge.edgePoints.push({ edge.edgePoints.push({
x: (taskWidth + taskXSpace) * edge.source.level + taskWidth, x: (taskWidth + taskXSpace) * edge.source.level + taskWidth,
y: (taskHeight + taskYSpace) * edge.source.row + taskHeight / 2, y: (taskHeight + taskYSpace) * edge.source.row + taskHeight / 2
}); });
edge.edgePoints.push({ edge.edgePoints.push({
x: (taskWidth + taskXSpace) * edge.target.level - taskXSpace / 2, x: (taskWidth + taskXSpace) * edge.target.level - taskXSpace / 2,
y: (taskHeight + taskYSpace) * edge.source.row + taskHeight / 2, y: (taskHeight + taskYSpace) * edge.source.row + taskHeight / 2
}); });
edge.edgePoints.push({ edge.edgePoints.push({
x: (taskWidth + taskXSpace) * edge.target.level - taskXSpace / 2, x: (taskWidth + taskXSpace) * edge.target.level - taskXSpace / 2,
y: (taskHeight + taskYSpace) * edge.target.row + taskHeight / 2, y: (taskHeight + taskYSpace) * edge.target.row + taskHeight / 2
}); });
edge.edgePoints.push({ edge.edgePoints.push({
x: (taskWidth + taskXSpace) * edge.target.level, x: (taskWidth + taskXSpace) * edge.target.level,
y: (taskHeight + taskYSpace) * edge.target.row + taskHeight / 2, y: (taskHeight + taskYSpace) * edge.target.row + taskHeight / 2
}); });
} }
let width = (maxlevel + 1) * (this.taskWidth + this.taskXSpace); let width = (maxlevel + 1) * (this.taskWidth + this.taskXSpace);
this.width = width + 'px'; this.width = width + "px";
let height = let height =
(levelsMaxRow(graphTasks, -1) + 1) * (levelsMaxRow(graphTasks, -1) + 1) *
(this.taskHeight + this.taskYSpace); (this.taskHeight + this.taskYSpace);
this.height = height + 'px'; this.height = height + "px";
}, }
}, },
created() { created() {
this.update(this.tasks); this.update(this.tasks);
@ -393,6 +393,6 @@ export default {
window.setInterval(() => { window.setInterval(() => {
this.now = moment(); this.now = moment();
}, 500); }, 500);
}, }
}; };
</script> </script>

View File

@ -8,30 +8,22 @@
<div>Error fetching Run: {{ fetchRunError }}</div> <div>Error fetching Run: {{ fetchRunError }}</div>
<div>Error fetching Task: {{ fetchTaskError }}</div> <div>Error fetching Task: {{ fetchTaskError }}</div>
</div> </div>
<rundetail <rundetail :run="run" :ownertype="ownertype" :ownername="ownername" :projectref="projectref" />
:run="run"
:ownertype="ownertype"
:ownername="ownername"
:projectref="projectref"
/>
<div v-if="task != null"> <div v-if="task != null">
<div class="mt-8 mb-4 flex justify-between items-center"> <div class="mt-8 mb-4 flex justify-between items-center">
<div class="flex items-center"> <div class="flex items-center">
<span class="text-2xl mr-3">{{ task.name }}</span> <span class="text-2xl mr-3">{{task.name}}</span>
<span <span
class="mr-3 rounded px-2 py-1 text-xs" class="mr-3 rounded px-2 py-1 text-xs"
:class="taskClass(task)" :class="taskClass(task)"
>{{ task.status | capitalize }}</span >{{ task.status | capitalize }}</span>
>
</div> </div>
<button <button
v-if="task.waiting_approval" v-if="task.waiting_approval"
class="btn btn-blue" class="btn btn-blue"
@click="approveTask(run.id, task.id)" @click="approveTask(run.id, task.id)"
> >Approve</button>
Approve
</button>
</div> </div>
<step <step
v-bind:runid="runid" v-bind:runid="runid"
@ -52,23 +44,23 @@
</template> </template>
<script> <script>
import { fetchRun, fetchTask, approveTask } from '@/util/data.js'; import { fetchRun, fetchTask, approveTask } from "@/util/data.js";
import step from '@/components/step.vue'; import step from "@/components/step.vue";
import rundetail from '@/components/rundetail.vue'; import rundetail from "@/components/rundetail.vue";
export default { export default {
components: { components: {
step, step,
rundetail, rundetail
}, },
name: 'tasksummary', name: "tasksummary",
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array,
runid: String, runid: String,
taskid: String, taskid: String
}, },
data() { data() {
return { return {
@ -78,11 +70,11 @@ export default {
fetchTaskError: null, fetchTaskError: null,
run: null, run: null,
task: null, task: null
}; };
}, },
watch: { watch: {
$route: async function () { $route: async function() {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
@ -93,16 +85,16 @@ export default {
this.fetchRun(); this.fetchRun();
this.fetchTask(); this.fetchTask();
}, }
}, },
methods: { methods: {
taskClass(task) { taskClass(task) {
if (task.status == 'success') return 'is-success'; if (task.status == "success") return "is-success";
if (task.status == 'failed') return 'is-failed'; if (task.status == "failed") return "is-failed";
if (task.status == 'stopped') return 'is-failed'; if (task.status == "stopped") return "is-failed";
if (task.status == 'running') return 'is-running'; if (task.status == "running") return "is-running";
if (task.status == 'skipped') return 'is-skipped'; if (task.status == "skipped") return "is-skipped";
return 'unknown'; return "unknown";
}, },
async fetchRun() { async fetchRun() {
let { data, error, aborted } = await fetchRun( let { data, error, aborted } = await fetchRun(
@ -151,9 +143,9 @@ export default {
this.fetchTask(); this.fetchTask();
}, 2000); }, 2000);
}, },
approveTask: approveTask, approveTask: approveTask
}, },
created: function () { created: function() {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
this.fetchRun(); this.fetchRun();
@ -165,8 +157,9 @@ export default {
} }
clearTimeout(this.fetchRunSchedule); clearTimeout(this.fetchRunSchedule);
clearTimeout(this.fetchTaskSchedule); clearTimeout(this.fetchTaskSchedule);
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -7,10 +7,7 @@
class="mb-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded" class="mb-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded"
role="alert" role="alert"
> >
<p> <p>Removing a Linked Account will also block all the projects that uses this Linked Account to access their remote repository</p>
Removing a Linked Account will also block all the projects that uses
this Linked Account to access their remote repository
</p>
</div> </div>
<ul v-if="user.linked_accounts"> <ul v-if="user.linked_accounts">
<li <li
@ -19,14 +16,10 @@
v-bind:key="index" v-bind:key="index"
> >
<div> <div>
<span class="font-bold">{{ la.remote_user_name }}</span> <span class="font-bold">{{la.remote_user_name}}</span>
<span class="ml-1" <span class="ml-1">(on remote source {{laRemoteSourceName(la)}})</span>
>(on remote source {{ laRemoteSourceName(la) }})</span
>
</div> </div>
<button class="btn btn-red" @click="deleteLinkedAccount(la)"> <button class="btn btn-red" @click="deleteLinkedAccount(la)">Delete</button>
Delete
</button>
</li> </li>
<div <div
v-if="deleteLinkedAccountError" v-if="deleteLinkedAccountError"
@ -47,13 +40,9 @@
class="block appearance-none w-full bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline" class="block appearance-none w-full bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline"
v-model="selectedRemoteSourceName" v-model="selectedRemoteSourceName"
> >
<option v-for="rs in remotesources" v-bind:key="rs.id"> <option v-for="rs in remotesources" v-bind:key="rs.id">{{ rs.name }}</option>
{{ rs.name }}
</option>
</select> </select>
<div <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2">
class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2"
>
<svg <svg
class="fill-current h-4 w-4" class="fill-current h-4 w-4"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -67,9 +56,7 @@
</div> </div>
</div> </div>
<button class="ml-3 btn btn-blue" @click="addLinkedAccount()"> <button class="ml-3 btn btn-blue" @click="addLinkedAccount()">Add Linked Account</button>
Add Linked Account
</button>
</div> </div>
</div> </div>
@ -82,10 +69,8 @@
v-for="token in user.tokens" v-for="token in user.tokens"
v-bind:key="token" v-bind:key="token"
> >
<span class="font-bold">{{ token }}</span> <span class="font-bold">{{token}}</span>
<button class="btn btn-red" @click="deleteUserToken(token)"> <button class="btn btn-red" @click="deleteUserToken(token)">Delete</button>
Delete
</button>
</li> </li>
<div <div
v-if="deleteUserTokenError" v-if="deleteUserTokenError"
@ -117,10 +102,8 @@
</svg> </svg>
</div> </div>
<div> <div>
<p class="font-bold"> <p class="font-bold">User token created. Copy it now since it won't be showed again</p>
User token created. Copy it now since it won't be showed again <p class="text-sm">{{token}}</p>
</p>
<p class="text-sm">{{ token }}</p>
</div> </div>
</div> </div>
<span <span
@ -147,10 +130,8 @@
type="text" type="text"
placeholder="Token name" placeholder="Token name"
v-model="newtokenname" v-model="newtokenname"
/> >
<button class="ml-3 btn btn-blue" @click="createUserToken()"> <button class="ml-3 btn btn-blue" @click="createUserToken()">Create Token</button>
Create Token
</button>
</div> </div>
<div <div
v-if="createUserTokenError" v-if="createUserTokenError"
@ -170,14 +151,14 @@ import {
fetchRemoteSources, fetchRemoteSources,
createUserToken, createUserToken,
deleteUserToken, deleteUserToken,
deleteLinkedAccount, deleteLinkedAccount
} from '@/util/data.js'; } from "@/util/data.js";
import { userAddLinkedAccountLink } from '@/util/link.js'; import { userAddLinkedAccountLink } from "@/util/link.js";
export default { export default {
components: {}, components: {},
name: 'usersettings', name: "usersettings",
props: {}, props: {},
data() { data() {
return { return {
@ -188,7 +169,7 @@ export default {
remotesources: [], remotesources: [],
token: null, token: null,
newtokenname: null, newtokenname: null,
selectedRemoteSourceName: null, selectedRemoteSourceName: null
}; };
}, },
methods: { methods: {
@ -200,7 +181,7 @@ export default {
async fetchCurrentUser() { async fetchCurrentUser() {
let { data, error } = await fetchCurrentUser(); let { data, error } = await fetchCurrentUser();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.user = data; this.user = data;
@ -208,7 +189,7 @@ export default {
async fetchRemoteSources() { async fetchRemoteSources() {
let { data, error } = await fetchRemoteSources(); let { data, error } = await fetchRemoteSources();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.remotesources = data; this.remotesources = data;
@ -268,13 +249,15 @@ export default {
return; return;
} }
this.fetchCurrentUser(); this.fetchCurrentUser();
}
}, },
}, created: function() {
created: function () {
this.fetchCurrentUser(); this.fetchCurrentUser();
this.fetchRemoteSources(); this.fetchRemoteSources();
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -18,22 +18,21 @@
</div> </div>
<div class="flex" v-for="variable in variables" v-bind:key="variable.id"> <div class="flex" v-for="variable in variables" v-bind:key="variable.id">
<div class="w-2/12"> <div class="w-2/12">
<span class="name">{{ variable.name }}</span> <span class="name">{{variable.name}}</span>
<div v-if="showparentpath" class="text-sm font-light"> <div v-if="showparentpath" class="text-sm font-light">from {{variable.parent_path}}</div>
from {{ variable.parent_path }}
</div>
</div> </div>
<div class="w-10/12"> <div class="w-10/12">
<div class="flex" v-for="val in variable.values" v-bind:key="val.id"> <div class="flex" v-for="val in variable.values" v-bind:key="val.id">
<div class="w-2/12"> <div class="w-2/12">
<span>{{ val.secret_name }}</span> <span>{{val.secret_name}}</span>
<div v-if="val.matching_secret_parent_path" class="text-sm"> <div
using secret from {{ val.matching_secret_parent_path }} v-if="val.matching_secret_parent_path"
</div> class="text-sm"
>using secret from {{val.matching_secret_parent_path}}</div>
<div v-else class="text-sm text-red-600">no matching secret</div> <div v-else class="text-sm text-red-600">no matching secret</div>
</div> </div>
<div class="w-2/12"> <div class="w-2/12">
<span>{{ val.secret_var }}</span> <span>{{val.secret_var}}</span>
</div> </div>
<div class="w-8/12"> <div class="w-8/12">
<div v-if="val.when"> <div v-if="val.when">
@ -44,19 +43,13 @@
<span>{{ type }}</span> <span>{{ type }}</span>
</div> </div>
<div class="w-1/3"> <div class="w-1/3">
<div <div v-for="include in val.when[type].include" v-bind:key="include.match">
v-for="include in val.when[type].include" <div>{{include.match}}</div>
v-bind:key="include.match"
>
<div>{{ include.match }}</div>
</div> </div>
</div> </div>
<div class="w-1/3"> <div class="w-1/3">
<div <div v-for="exclude in val.when[type].exclude" v-bind:key="exclude.match">
v-for="exclude in val.when[type].exclude" <div>{{exclude.match}}</div>
v-bind:key="exclude.match"
>
<div>{{ exclude.match }}</div>
</div> </div>
</div> </div>
</div> </div>
@ -73,12 +66,15 @@
<script> <script>
export default { export default {
components: {}, components: {},
name: 'vars', name: "vars",
props: { props: {
variables: Array, variables: Array,
showparentpath: Boolean, showparentpath: Boolean
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -1,7 +1,7 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@import '@/css/_ansi.scss'; @import "@/css/_ansi.scss";
.btn { .btn {
@apply font-bold py-2 px-4 rounded; @apply font-bold py-2 px-4 rounded;
@ -119,7 +119,7 @@
border-radius: 290486px; border-radius: 290486px;
border-right-color: transparent; border-right-color: transparent;
border-top-color: transparent; border-top-color: transparent;
content: ''; content: "";
display: block; display: block;
width: 1em; width: 1em;
height: 1em; height: 1em;

View File

@ -1,11 +1,11 @@
import '@/css/tailwind.scss'; import "@/css/tailwind.scss";
import { getUser } from '@/util/auth'; import { getUser } from "@/util/auth";
import '@mdi/font/css/materialdesignicons.css'; import "@mdi/font/css/materialdesignicons.css";
import Vue from 'vue'; import Vue from "vue";
import Vue2Filters from 'vue2-filters'; import Vue2Filters from "vue2-filters";
import App from './App.vue'; import App from "./App.vue";
import router from './router'; import router from "./router";
import store from './store'; import store from "./store";
Vue.use(Vue2Filters); Vue.use(Vue2Filters);
@ -13,12 +13,12 @@ Vue.use(Vue2Filters);
new Vue({ new Vue({
router, router,
store, store,
created: function () { created: function() {
let user = getUser(); let user = getUser();
if (user) { if (user) {
store.dispatch('setUser', user); store.dispatch("setUser", user);
} }
store.dispatch('setRegisterUser', null); store.dispatch("setRegisterUser", null);
}, },
render: (h) => h(App), render: h => h(App)
}).$mount('#app'); }).$mount("#app");

View File

@ -1,348 +1,243 @@
import Vue from 'vue'; import Vue from "vue";
import VueRouter from 'vue-router'; import VueRouter from "vue-router";
import Home from './views/Home.vue'; import Home from "./views/Home.vue";
import User from './views/User.vue'; import User from "./views/User.vue";
import Org from './views/Org.vue'; import Org from "./views/Org.vue";
import Project from './views/Project.vue'; import Project from "./views/Project.vue";
import ProjectGroup from './views/ProjectGroup.vue'; import ProjectGroup from "./views/ProjectGroup.vue";
import AddLinkedAccount from './views/AddLinkedAccount.vue'; import AddLinkedAccount from "./views/AddLinkedAccount.vue";
import usersettings from './components/usersettings.vue'; import usersettings from "./components/usersettings.vue";
import projects from './components/projects.vue'; import projects from "./components/projects.vue";
import projectsettings from './components/projectsettings.vue'; import projectsettings from "./components/projectsettings.vue";
import projectgroupsettings from './components/projectgroupsettings.vue'; import projectgroupsettings from "./components/projectgroupsettings.vue";
import createproject from './components/createproject.vue'; import createproject from "./components/createproject.vue";
import createprojectgroup from './components/createprojectgroup.vue'; import createprojectgroup from "./components/createprojectgroup.vue";
import createorganization from './components/createorganization.vue'; import createorganization from "./components/createorganization.vue";
import orgmembers from './components/orgmembers.vue'; import orgmembers from "./components/orgmembers.vue";
import runs from './components/runs.vue'; import runs from "./components/runs.vue";
import runsummary from './components/runsummary.vue'; import runsummary from "./components/runsummary.vue";
import tasksummary from './components/tasksummary.vue'; import tasksummary from "./components/tasksummary.vue";
import Oauth2 from './views/Oauth2.vue'; import Oauth2 from "./views/Oauth2.vue";
import Register from './views/Register.vue'; import Register from "./views/Register.vue";
import Login from './views/Login.vue'; import Login from "./views/Login.vue";
import Logout from './views/Logout.vue'; import Logout from "./views/Logout.vue";
import CreateSource from './views/CreateSource.vue';
import { parseRef, projectRunLink } from '@/util/link.js'; import { parseRef, projectRunLink } from "@/util/link.js";
import { fetchProject } from '@/util/data.js'; import { fetchProject } from "@/util/data.js";
import store from './store'; import store from "./store";
Vue.use(VueRouter); Vue.use(VueRouter);
const router = new VueRouter({ const router = new VueRouter({
mode: 'history', mode: "history",
routes: [ routes: [
{ {
path: '/register', path: "/register",
name: 'register', name: "register",
component: Register, component: Register,
}, },
{ {
path: '/newsource', path: "/login",
name: 'newsource', name: "login",
component: CreateSource, component: Login
}, },
{ {
path: '/login', path: "/logout",
name: 'login', name: "logout",
component: Login, component: Logout
}, },
{ {
path: '/logout', path: "/oauth2/callback",
name: 'logout', name: "oauth2callback",
component: Logout, component: Oauth2
}, },
{ {
path: '/oauth2/callback', path: "/",
name: 'oauth2callback', name: "home",
component: Oauth2, component: Home
}, },
{ {
path: '/', path: "/neworganization",
name: 'home',
component: Home,
},
{
path: '/neworganization',
component: createorganization, component: createorganization,
}, },
{ {
path: '/user/:username', path: "/user/:username",
component: User, component: User,
props: (route) => ({ username: route.params.username }), props: (route) => ({ username: route.params.username }),
children: [ children: [
{ {
path: '', path: "",
name: 'user', name: "user",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username })
ownertype: 'user',
ownername: route.params.username,
}),
}, },
{ {
path: 'projects', path: "projects",
name: 'user projects', name: "user projects",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username })
ownertype: 'user',
ownername: route.params.username,
}),
}, },
{ {
path: 'runs', path: "runs",
name: 'user direct runs', name: "user direct runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username })
ownertype: 'user',
ownername: route.params.username,
}),
}, },
{ {
path: 'runs/:runid', path: "runs/:runid",
name: 'user direct run', name: "user direct run",
component: runsummary, component: runsummary,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, runid: route.params.runid })
ownertype: 'user',
ownername: route.params.username,
runid: route.params.runid,
}),
}, },
{ {
path: 'runs/:runid/tasks/:taskid', path: "runs/:runid/tasks/:taskid",
name: 'user direct run task', name: "user direct run task",
component: tasksummary, component: tasksummary,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, runid: route.params.runid, taskid: route.params.taskid })
ownertype: 'user',
ownername: route.params.username,
runid: route.params.runid,
taskid: route.params.taskid,
}),
}, },
{ {
path: 'settings', path: "settings",
name: 'user settings', name: "user settings",
component: usersettings, component: usersettings,
props: (route) => ({ username: route.params.username }), props: (route) => ({ username: route.params.username }),
}, },
{ {
path: 'linkedaccounts/add/:remotesource', path: "linkedaccounts/add/:remotesource",
name: 'user add linked account', name: "user add linked account",
component: AddLinkedAccount, component: AddLinkedAccount,
props: (route) => ({ props: (route) => ({ username: route.params.username, remoteSourceName: route.params.remotesource })
username: route.params.username,
remoteSourceName: route.params.remotesource,
}),
}, },
{ {
path: 'createprojectgroup', path: "createprojectgroup",
name: 'user create project group', name: "user create project group",
component: createprojectgroup, component: createprojectgroup,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username })
ownertype: 'user',
ownername: route.params.username,
}),
}, },
{ {
path: 'createproject', path: "createproject",
name: 'user create project', name: "user create project",
component: createproject, component: createproject,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username })
ownertype: 'user',
ownername: route.params.username,
}),
}, },
], ]
}, },
{ {
path: '/user/:username/projects/:projectref(.*\\.proj)', path: "/user/:username/projects/:projectref(.*\\.proj)",
component: Project, component: Project,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref) }),
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
}),
children: [ children: [
{ {
path: '', path: "",
name: 'user project', name: "user project",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref) })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
}),
}, },
{ {
path: 'runs', path: "runs",
name: 'user project runs', name: "user project runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref) })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
}),
}, },
{ {
path: 'branches', path: "branches",
name: 'user project branches runs', name: "user project branches runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref), query: "branches" })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
query: 'branches',
}),
}, },
{ {
path: 'tags', path: "tags",
name: 'user project tags runs', name: "user project tags runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref), query: "tags" })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
query: 'tags',
}),
}, },
{ {
path: 'pullrequests', path: "pullrequests",
name: 'user project pull requests runs', name: "user project pull requests runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref), query: "pullrequests" })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
query: 'pullrequests',
}),
}, },
{ {
path: 'runs/:runid', path: "runs/:runid",
name: 'user project run', name: "user project run",
component: runsummary, component: runsummary,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref), runid: route.params.runid })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
runid: route.params.runid,
}),
}, },
{ {
path: 'runs/:runid/tasks/:taskid', path: "runs/:runid/tasks/:taskid",
name: 'user project run task', name: "user project run task",
component: tasksummary, component: tasksummary,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref), runid: route.params.runid, taskid: route.params.taskid })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
runid: route.params.runid,
taskid: route.params.taskid,
}),
}, },
{ {
path: 'settings', path: "settings",
name: 'user project settings', name: "user project settings",
component: projectsettings, component: projectsettings,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectref: parseRef(route.params.projectref) })
ownertype: 'user',
ownername: route.params.username,
projectref: parseRef(route.params.projectref),
}),
}, },
], ]
}, },
{ {
path: '/user/:username/projectgroups/:projectgroupref(.*\\.proj)', path: "/user/:username/projectgroups/:projectgroupref(.*\\.proj)",
component: ProjectGroup, component: ProjectGroup,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectgroupref: parseRef(route.params.projectgroupref) }),
ownertype: 'user',
ownername: route.params.username,
projectgroupref: parseRef(route.params.projectgroupref),
}),
children: [ children: [
{ {
path: '', path: "",
name: 'user project group', name: "user project group",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectgroupref: parseRef(route.params.projectgroupref) }),
ownertype: 'user',
ownername: route.params.username,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'projects', path: "projects",
name: 'user project group projects', name: "user project group projects",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'user',
ownername: route.params.username,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'settings', path: "settings",
name: 'user project group settings', name: "user project group settings",
component: projectgroupsettings, component: projectgroupsettings,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'user',
ownername: route.params.username,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'createprojectgroup', path: "createprojectgroup",
name: 'user project group create project group', name: "user project group create project group",
component: createprojectgroup, component: createprojectgroup,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'user',
ownername: route.params.username,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'createproject', path: "createproject",
name: 'user project group create project', name: "user project group create project",
component: createproject, component: createproject,
props: (route) => ({ props: (route) => ({ ownertype: "user", ownername: route.params.username, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'user',
ownername: route.params.username,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
], ]
}, },
{ {
path: '/org/:orgname', path: "/org/:orgname",
component: Org, component: Org,
props: (route) => ({ orgname: route.params.orgname }), props: (route) => ({ orgname: route.params.orgname }),
children: [ children: [
{ {
path: '', path: "",
name: 'org', name: "org",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname })
ownertype: 'org',
ownername: route.params.orgname,
}),
}, },
{ {
path: 'projects', path: "projects",
name: 'org projects', name: "org projects",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname })
ownertype: 'org',
ownername: route.params.orgname,
}),
}, },
{ {
path: 'members', path: "members",
name: 'org members', name: "org members",
component: orgmembers, component: orgmembers,
props: (route) => ({ orgname: route.params.orgname }), props: (route) => ({ orgname: route.params.orgname })
}, },
/* { /* {
path: "settings", path: "settings",
@ -351,213 +246,141 @@ const router = new VueRouter({
props: (route) => ({ username: route.params.username }), props: (route) => ({ username: route.params.username }),
}, */ }, */
{ {
path: 'createprojectgroup', path: "createprojectgroup",
name: 'org create project group', name: "org create project group",
component: createprojectgroup, component: createprojectgroup,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname })
ownertype: 'org',
ownername: route.params.orgname,
}),
}, },
{ {
path: 'createproject', path: "createproject",
name: 'org create project', name: "org create project",
component: createproject, component: createproject,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname })
ownertype: 'org',
ownername: route.params.orgname,
}),
}, },
], ]
}, },
{ {
path: '/org/:orgname/projects/:projectref(.*\\.proj)', path: "/org/:orgname/projects/:projectref(.*\\.proj)",
component: Project, component: Project,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref) }),
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
}),
children: [ children: [
{ {
path: '', path: "",
name: 'org project', name: "org project",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref) })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
}),
}, },
{ {
path: 'runs', path: "runs",
name: 'org project runs', name: "org project runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref) })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
}),
}, },
{ {
path: 'branches', path: "branches",
name: 'org project branches runs', name: "org project branches runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref), query: "branches" })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
query: 'branches',
}),
}, },
{ {
path: 'tags', path: "tags",
name: 'org project tags runs', name: "org project tags runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref), query: "tags" })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
query: 'tags',
}),
}, },
{ {
path: 'pullrequests', path: "pullrequests",
name: 'org project pull requests runs', name: "org project pull requests runs",
component: runs, component: runs,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref), query: "pullrequests" })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
query: 'pullrequests',
}),
}, },
{ {
path: 'runs/:runid', path: "runs/:runid",
name: 'org project run', name: "org project run",
component: runsummary, component: runsummary,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref), runid: route.params.runid })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
runid: route.params.runid,
}),
}, },
{ {
path: 'runs/:runid/tasks/:taskid', path: "runs/:runid/tasks/:taskid",
name: 'org project run task', name: "org project run task",
component: tasksummary, component: tasksummary,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref), runid: route.params.runid, taskid: route.params.taskid })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
runid: route.params.runid,
taskid: route.params.taskid,
}),
}, },
{ {
path: 'settings', path: "settings",
name: 'org project settings', name: "org project settings",
component: projectsettings, component: projectsettings,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectref: parseRef(route.params.projectref) })
ownertype: 'org',
ownername: route.params.orgname,
projectref: parseRef(route.params.projectref),
}),
}, },
], ]
}, },
{ {
path: '/org/:orgname/projectgroups/:projectgroupref(.*\\.proj)', path: "/org/:orgname/projectgroups/:projectgroupref(.*\\.proj)",
component: ProjectGroup, component: ProjectGroup,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectgroupref: parseRef(route.params.projectgroupref) }),
ownertype: 'org',
ownername: route.params.orgname,
projectgroupref: parseRef(route.params.projectgroupref),
}),
children: [ children: [
{ {
path: '', path: "",
name: 'org project group', name: "org project group",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectgroupref: parseRef(route.params.projectgroupref) }),
ownertype: 'org',
ownername: route.params.orgname,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'projects', path: "projects",
name: 'org project group projects', name: "org project group projects",
component: projects, component: projects,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'org',
ownername: route.params.orgname,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'settings', path: "settings",
name: 'org project group settings', name: "org project group settings",
component: projectgroupsettings, component: projectgroupsettings,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'org',
ownername: route.params.orgname,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'createprojectgroup', path: "createprojectgroup",
name: 'org project group create project group', name: "org project group create project group",
component: createprojectgroup, component: createprojectgroup,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'org',
ownername: route.params.orgname,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
{ {
path: 'createproject', path: "createproject",
name: 'org project group create project', name: "org project group create project",
component: createproject, component: createproject,
props: (route) => ({ props: (route) => ({ ownertype: "org", ownername: route.params.orgname, projectgroupref: parseRef(route.params.projectgroupref) })
ownertype: 'org',
ownername: route.params.orgname,
projectgroupref: parseRef(route.params.projectgroupref),
}),
}, },
], ]
}, },
], ]
}); });
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
store.dispatch('setError', null); store.dispatch("setError", null);
const { path, query } = to; const { path, query } = to
if (path == '/run') { if (path == "/run") {
// generic run handler by projectref and runid // generic run handler by projectref and runid
let projectref = query.projectref; let projectref = query.projectref
let runid = query.runid; let runid = query.runid
let { data, error } = await fetchProject(projectref); let { data, error } = await fetchProject(projectref);
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
let project = data; let project = data;
let parts = project.path.split('/'); let parts = project.path.split("/")
let nextPath = projectRunLink(parts[0], parts[1], parts.slice(2), runid); let nextPath = projectRunLink(parts[0], parts[1], parts.slice(2), runid)
next({ path: nextPath.path, replace: true }); next({ path: nextPath.path, replace: true })
} }
next(); next()
}); })
export default router; export default router

View File

@ -1,54 +1,55 @@
import Vue from 'vue'; import Vue from 'vue'
import Vuex from 'vuex'; import Vuex from 'vuex'
Vue.use(Vuex); Vue.use(Vuex)
const state = { const state = {
error: null, error: null,
user: null, user: null,
registeruser: null, registeruser: null,
}; }
const getters = { const getters = {
// global error // global error
error: (state) => { error: state => {
return state.error; return state.error
}, },
user: (state) => { user: state => {
return state.user; return state.user
}, },
registeruser: (state) => { registeruser: state => {
return state.registeruser; return state.registeruser
}, }
}; }
const mutations = { const mutations = {
setError(state, error) { setError(state, error) {
state.error = error; state.error = error
}, },
setUser(state, user) { setUser(state, user) {
state.user = user; state.user = user
}, },
setRegisterUser(state, user) { setRegisterUser(state, user) {
state.registeruser = user; state.registeruser = user
}, }
}; }
const actions = { const actions = {
setError({ commit }, error) { setError({ commit }, error) {
commit('setError', error); commit('setError', error)
}, },
setUser({ commit }, user) { setUser({ commit }, user) {
commit('setUser', user); commit('setUser', user)
}, },
setRegisterUser({ commit }, user) { setRegisterUser({ commit }, user) {
commit('setRegisterUser', user); commit('setRegisterUser', user)
}, }
}; }
export default new Vuex.Store({ export default new Vuex.Store({
state, state,
getters, getters,
actions, actions,
mutations, mutations,
}); })

View File

@ -1,8 +1,8 @@
import store from '@/store'; import store from "@/store";
const ID_TOKEN_KEY = 'id_token'; const ID_TOKEN_KEY = "id_token";
const USER_KEY = 'user'; const USER_KEY = "user";
const LOGIN_REDIRECT_KEY = 'login_redirect'; const LOGIN_REDIRECT_KEY = "login_redirect";
let API_URL = window.CONFIG.API_URL; let API_URL = window.CONFIG.API_URL;
let API_BASE_PATH = window.CONFIG.API_BASE_PATH; let API_BASE_PATH = window.CONFIG.API_BASE_PATH;
@ -10,20 +10,20 @@ let API_BASE_PATH = window.CONFIG.API_BASE_PATH;
export function setLoggedUser(token, user) { export function setLoggedUser(token, user) {
setIdToken(token); setIdToken(token);
setUser(user); setUser(user);
store.dispatch('setUser', user); store.dispatch("setUser", user);
} }
export function doLogout() { export function doLogout() {
unsetIdToken(); unsetIdToken();
unsetUser(); unsetUser();
store.dispatch('setUser', null); store.dispatch("setUser", null);
} }
export function apiurlwithtoken(path) { export function apiurlwithtoken(path) {
let u = new URL(API_URL + API_BASE_PATH + path); let u = new URL(API_URL + API_BASE_PATH + path);
let idToken = getIdToken(); let idToken = getIdToken();
if (idToken) { if (idToken) {
u.searchParams.append('access_token', idToken); u.searchParams.append("access_token", idToken);
} }
return u; return u;
} }
@ -33,19 +33,19 @@ export function apiurl(path) {
} }
export function loginurl() { export function loginurl() {
return apiurl('/auth/login'); return apiurl("/auth/login");
} }
export function authorizeurl() { export function authorizeurl() {
return apiurl('/auth/authorize'); return apiurl("/auth/authorize");
} }
export function registerurl() { export function registerurl() {
return new apiurl('/auth/register'); return new apiurl("/auth/register");
} }
export function oauth2callbackurl() { export function oauth2callbackurl() {
return new apiurl('/auth/oauth2/callback'); return new apiurl("/auth/oauth2/callback");
} }
export async function loginapi(init) { export async function loginapi(init) {
@ -64,19 +64,19 @@ export async function registerapi(init) {
return await window.fetch(registerurl(), init); return await window.fetch(registerurl(), init);
} }
export async function fetch(url, init, signal, token, tokenType = 'bearer') { export async function fetch(url, init, signal) {
if (!init) { if (!init) {
init = {}; init = {};
} }
if (init.headers === undefined) { if (init.headers === undefined) {
init['headers'] = {}; init["headers"] = {};
} }
if (signal) { if (signal) {
init['signal'] = signal; init["signal"] = signal;
} }
let idToken = token || getIdToken(); let idToken = getIdToken();
if (idToken) { if (idToken) {
init.headers['Authorization'] = tokenType + ' ' + idToken; init.headers["Authorization"] = "bearer " + idToken;
} }
return await window.fetch(url, init); return await window.fetch(url, init);

View File

@ -1,18 +1,14 @@
import router from '@/router'; import router from "@/router";
import { apiurl, fetch as authfetch, loginapi, registerapi } from '@/util/auth'; import { apiurl, fetch as authfetch, loginapi, registerapi } from "@/util/auth";
export const GITHUB_API_URL = 'https://api.github.com'; export async function fetch(url, init, signal) {
export const GITHUB_SSH_KEY =
'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==';
export async function fetch(url, init, signal, token, tokenType) {
try { try {
let res = await authfetch(url, init, signal, token, tokenType); let res = await authfetch(url, init, signal);
if (!res.ok) { if (!res.ok) {
if (res.status === 401) { if (res.status === 401) {
router.push({ router.push({
name: 'login', name: "login",
query: { redirect: router.currentRoute.fullPath }, query: { redirect: router.currentRoute.fullPath }
}); });
// if we return a response containing an error what happens is // if we return a response containing an error what happens is
// that router.push mounts the login view before the calling // that router.push mounts the login view before the calling
@ -37,21 +33,21 @@ export async function fetch(url, init, signal, token, tokenType) {
return { data: await res.json(), error: null }; return { data: await res.json(), error: null };
} }
} catch (e) { } catch (e) {
if (e.name == 'AbortError') { if (e.name == "AbortError") {
return { data: null, error: null, aborted: true }; return { data: null, error: null, aborted: true };
} }
return { data: null, error: 'api call failed: ' + e.message }; return { data: null, error: "api call failed: " + e.message };
} }
} }
export async function login(username, password, remotesourcename) { export async function login(username, password, remotesourcename) {
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
remote_source_name: remotesourcename, remote_source_name: remotesourcename,
login_name: username, login_name: username,
password: password, password: password
}), })
}; };
try { try {
@ -63,7 +59,7 @@ export async function login(username, password, remotesourcename) {
return { data: await res.json(), error: null }; return { data: await res.json(), error: null };
} }
} catch (e) { } catch (e) {
return { data: null, error: 'api call failed: ' + e.message }; return { data: null, error: "api call failed: " + e.message };
} }
} }
@ -74,13 +70,13 @@ export async function register(
remotepassword remotepassword
) { ) {
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
username: username, username: username,
remote_source_name: remotesourcename, remote_source_name: remotesourcename,
remote_source_login_name: remoteloginname, remote_source_login_name: remoteloginname,
remote_source_login_password: remotepassword, remote_source_login_password: remotepassword
}), })
}; };
try { try {
@ -92,166 +88,131 @@ export async function register(
return { data: await res.json(), error: null }; return { data: await res.json(), error: null };
} }
} catch (e) { } catch (e) {
return { data: null, error: 'api call failed: ' + e.message }; return { data: null, error: "api call failed: " + e.message };
} }
} }
export async function fetchCurrentUser(signal) { export async function fetchCurrentUser(signal) {
let path = '/user'; let path = "/user";
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchOrgMembers(orgref, signal) { export async function fetchOrgMembers(orgref, signal) {
let path = '/orgs/' + orgref + '/members'; let path = "/orgs/" + orgref + "/members";
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchRuns(group, startRunID, lastrun, signal) { export async function fetchRuns(group, startRunID, lastrun, signal) {
let u = apiurl('/runs'); let u = apiurl("/runs");
if (group) { if (group) {
u.searchParams.append('group', group); u.searchParams.append("group", group);
} }
if (lastrun) { if (lastrun) {
u.searchParams.append('lastrun', true); u.searchParams.append("lastrun", true);
} }
if (startRunID) { if (startRunID) {
u.searchParams.append('start', startRunID); u.searchParams.append("start", startRunID);
} }
return await fetch(u, null, signal); return await fetch(u, null, signal);
} }
export async function fetchRun(runid, signal) { export async function fetchRun(runid, signal) {
return await fetch(apiurl('/runs/' + runid), null, signal); return await fetch(apiurl("/runs/" + runid), null, signal);
} }
export async function fetchTask(runid, taskid, signal) { export async function fetchTask(runid, taskid, signal) {
return await fetch(apiurl('/runs/' + runid + '/tasks/' + taskid), signal); return await fetch(apiurl("/runs/" + runid + "/tasks/" + taskid), signal);
} }
export async function fetchUser(username, signal) { export async function fetchUser(username, signal) {
let path = '/users/' + username; let path = "/users/" + username;
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchProjectGroup(projectgroupref, signal) { export async function fetchProjectGroup(projectgroupref, signal) {
let path = '/projectgroups/' + encodeURIComponent(projectgroupref); let path = "/projectgroups/" + encodeURIComponent(projectgroupref);
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchProjectGroupSubgroups(projectgroupref, signal) { export async function fetchProjectGroupSubgroups(projectgroupref, signal) {
let path = '/projectgroups/' + encodeURIComponent(projectgroupref); let path = "/projectgroups/" + encodeURIComponent(projectgroupref);
path += '/subgroups'; path += "/subgroups";
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchProjectGroupProjects(projectgroupref, signal) { export async function fetchProjectGroupProjects(projectgroupref, signal) {
let path = '/projectgroups/' + encodeURIComponent(projectgroupref); let path = "/projectgroups/" + encodeURIComponent(projectgroupref);
path += '/projects'; path += "/projects";
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchProject(ref, signal) { export async function fetchProject(ref, signal) {
let path = '/projects/' + encodeURIComponent(ref); let path = "/projects/" + encodeURIComponent(ref);
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchSecrets(ownertype, ref, all, signal) { export async function fetchSecrets(ownertype, ref, all, signal) {
let path; let path;
if (ownertype == 'project') { if (ownertype == "project") {
path = '/projects/'; path = "/projects/";
} else if (ownertype == 'projectgroup') { } else if (ownertype == "projectgroup") {
path = '/projectgroups/'; path = "/projectgroups/";
} }
path += encodeURIComponent(ref); path += encodeURIComponent(ref);
path += '/secrets'; path += "/secrets";
if (all) { if (all) {
path += '?tree&removeoverridden'; path += "?tree&removeoverridden";
} }
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function fetchVariables(ownertype, ref, all, signal) { export async function fetchVariables(ownertype, ref, all, signal) {
let path; let path;
if (ownertype == 'project') { if (ownertype == "project") {
path = '/projects/'; path = "/projects/";
} else if (ownertype == 'projectgroup') { } else if (ownertype == "projectgroup") {
path = '/projectgroups/'; path = "/projectgroups/";
} }
path += encodeURIComponent(ref); path += encodeURIComponent(ref);
path += '/variables'; path += "/variables";
if (all) { if (all) {
path += '?tree&removeoverridden'; path += "?tree&removeoverridden";
} }
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function createRemoteSource(
token,
type,
name,
clientID,
clientSecret,
apiURL,
authType,
skipVerify,
sshHostKey,
skipSshHostKeyCheck,
registrationEnabled,
loginEnabled,
signal
) {
let path = '/remotesources';
let init = {
method: 'POST',
body: JSON.stringify({
name,
apiurl: apiURL,
type,
auth_type: authType,
skip_verify: skipVerify,
ssh_host_key: sshHostKey,
skip_ssh_host_key_check: skipSshHostKeyCheck,
oauth_2_client_id: clientID,
oauth_2_client_secret: clientSecret,
registration_enabled: registrationEnabled,
login_enabled: loginEnabled,
}),
};
return await fetch(apiurl(path), init, signal, token, 'token');
}
export async function createOrganization(orgname, visibility, signal) { export async function createOrganization(orgname, visibility, signal) {
let path = '/orgs'; let path = "/orgs";
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
name: orgname, name: orgname,
visibility: visibility, visibility: visibility
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function createUserToken(username, tokenname, signal) { export async function createUserToken(username, tokenname, signal) {
let path = '/users/' + username + '/tokens'; let path = "/users/" + username + "/tokens";
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
token_name: tokenname, token_name: tokenname
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function deleteUserToken(username, tokenname, signal) { export async function deleteUserToken(username, tokenname, signal) {
let path = '/users/' + username + '/tokens/' + tokenname; let path = "/users/" + username + "/tokens/" + tokenname;
let init = { let init = {
method: 'DELETE', method: "DELETE"
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
@ -263,90 +224,90 @@ export async function createUserLinkedAccount(
password, password,
signal signal
) { ) {
let path = '/users/' + username + '/linkedaccounts'; let path = "/users/" + username + "/linkedaccounts";
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
remote_source_name: remotesourcename, remote_source_name: remotesourcename,
remote_source_login_name: loginname, remote_source_login_name: loginname,
remote_source_login_password: password, remote_source_login_password: password
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function deleteLinkedAccount(username, laid, signal) { export async function deleteLinkedAccount(username, laid, signal) {
let path = '/users/' + username + '/linkedaccounts/' + laid; let path = "/users/" + username + "/linkedaccounts/" + laid;
let init = { let init = {
method: 'DELETE', method: "DELETE"
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function restartRun(runid, fromStart, signal) { export async function restartRun(runid, fromStart, signal) {
let path = '/runs/' + runid + '/actions'; let path = "/runs/" + runid + "/actions";
let init = { let init = {
method: 'PUT', method: "PUT",
body: JSON.stringify({ body: JSON.stringify({
action_type: 'restart', action_type: "restart",
from_start: fromStart, from_start: fromStart
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function cancelRun(runid, signal) { export async function cancelRun(runid, signal) {
let path = '/runs/' + runid + '/actions'; let path = "/runs/" + runid + "/actions";
let init = { let init = {
method: 'PUT', method: "PUT",
body: JSON.stringify({ body: JSON.stringify({
action_type: 'cancel', action_type: "cancel"
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function stopRun(runid, signal) { export async function stopRun(runid, signal) {
let path = '/runs/' + runid + '/actions'; let path = "/runs/" + runid + "/actions";
let init = { let init = {
method: 'PUT', method: "PUT",
body: JSON.stringify({ body: JSON.stringify({
action_type: 'stop', action_type: "stop"
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function approveTask(runid, taskid, signal) { export async function approveTask(runid, taskid, signal) {
let path = '/runs/' + runid + '/tasks/' + taskid + '/actions'; let path = "/runs/" + runid + "/tasks/" + taskid + "/actions";
let init = { let init = {
method: 'PUT', method: "PUT",
body: JSON.stringify({ body: JSON.stringify({
action_type: 'approve', action_type: "approve"
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function fetchRemoteSources(signal) { export async function fetchRemoteSources(signal) {
let path = '/remotesources'; let path = "/remotesources";
return await fetch(apiurl(path), null, signal); return await fetch(apiurl(path), null, signal);
} }
export async function userRemoteRepos(remotesourceid, signal) { export async function userRemoteRepos(remotesourceid, signal) {
let path = '/user/remoterepos/' + remotesourceid; let path = "/user/remoterepos/" + remotesourceid;
return await fetch(apiurl(path, null, signal)); return await fetch(apiurl(path, null, signal));
} }
export async function createProjectGroup(parentref, name, visibility, signal) { export async function createProjectGroup(parentref, name, visibility, signal) {
let path = '/projectgroups'; let path = "/projectgroups";
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
name: name, name: name,
parent_ref: parentref, parent_ref: parentref,
visibility: visibility, visibility: visibility
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
@ -357,13 +318,13 @@ export async function updateProjectGroup(
visibility, visibility,
signal signal
) { ) {
let path = '/projectgroups/' + encodeURIComponent(projectgroupref); let path = "/projectgroups/" + encodeURIComponent(projectgroupref);
let init = { let init = {
method: 'PUT', method: "PUT",
body: JSON.stringify({ body: JSON.stringify({
name: name, name: name,
visibility: visibility, visibility: visibility
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
@ -377,61 +338,55 @@ export async function createProject(
passvarstoforkedpr, passvarstoforkedpr,
signal signal
) { ) {
let path = '/projects'; let path = "/projects";
let init = { let init = {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
name: name, name: name,
parent_ref: parentref, parent_ref: parentref,
visibility: visibility, visibility: visibility,
remote_source_name: remotesourcename, remote_source_name: remotesourcename,
repo_path: remoterepopath, repo_path: remoterepopath,
pass_vars_to_forked_pr: passvarstoforkedpr, pass_vars_to_forked_pr: passvarstoforkedpr
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function updateProject( export async function updateProject(projectref, name, visibility, passvarstoforkedpr, signal) {
projectref, let path = "/projects/" + encodeURIComponent(projectref);
name,
visibility,
passvarstoforkedpr,
signal
) {
let path = '/projects/' + encodeURIComponent(projectref);
let init = { let init = {
method: 'PUT', method: "PUT",
body: JSON.stringify({ body: JSON.stringify({
name: name, name: name,
visibility: visibility, visibility: visibility,
pass_vars_to_forked_pr: passvarstoforkedpr, pass_vars_to_forked_pr: passvarstoforkedpr
}), })
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function deleteProject(projectref, signal) { export async function deleteProject(projectref, signal) {
let path = '/projects/' + encodeURIComponent(projectref); let path = "/projects/" + encodeURIComponent(projectref);
let init = { let init = {
method: 'DELETE', method: "DELETE"
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function projectUpdateRepoLinkedAccount(projectref, signal) { export async function projectUpdateRepoLinkedAccount(projectref, signal) {
let path = let path =
'/projects/' + encodeURIComponent(projectref) + '/updaterepolinkedaccount'; "/projects/" + encodeURIComponent(projectref) + "/updaterepolinkedaccount";
let init = { let init = {
method: 'PUT', method: "PUT"
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }
export async function deleteProjectGroup(projectgroupref, signal) { export async function deleteProjectGroup(projectgroupref, signal) {
let path = '/projectgroups/' + encodeURIComponent(projectgroupref); let path = "/projectgroups/" + encodeURIComponent(projectgroupref);
let init = { let init = {
method: 'DELETE', method: "DELETE"
}; };
return await fetch(apiurl(path), init, signal); return await fetch(apiurl(path), init, signal);
} }

View File

@ -1,173 +1,130 @@
export function parseRef(ref) { export function parseRef(ref) {
ref = ref.replace(/\.proj/, ''); ref = ref.replace(/\.proj/, "")
// return empty array or split return an array with the empty element // return empty array or split return an array with the empty element
if (!ref) { if (!ref) {
return []; return []
} }
return ref.split('/'); return ref.split("/")
} }
export function ownerLink(ownertype, ownername) { export function ownerLink(ownertype, ownername) {
if (ownertype == 'user') { if (ownertype == "user") {
return { name: ownertype, params: { username: ownername } }; return { name: ownertype, params: { username: ownername } }
} else if (ownertype == 'org') { } else if (ownertype == "org") {
return { name: ownertype, params: { orgname: ownername } }; return { name: ownertype, params: { orgname: ownername } }
} }
} }
export function ownerProjectsLink(ownertype, ownername) { export function ownerProjectsLink(ownertype, ownername) {
return { name: ownertype + ' projects', params: { ownername: ownername } }; return { name: ownertype + " projects", params: { ownername: ownername } }
} }
export function ownerSettingsLink(ownertype, ownername) { export function ownerSettingsLink(ownertype, ownername) {
if (ownertype == 'user') { if (ownertype == "user") {
return { name: ownertype + ' settings', params: { username: ownername } }; return { name: ownertype + " settings", params: { username: ownername } }
} else if (ownertype == 'org') { } else if (ownertype == "org") {
return { name: ownertype + ' settings', params: { orgname: ownername } }; return { name: ownertype + " settings", params: { orgname: ownername } }
} }
} }
export function userDirectRunsLink(username) { export function userDirectRunsLink(username) {
return { name: 'user direct runs', params: { username: username } }; return { name: "user direct runs", params: { username: username } }
} }
export function userDirectRunLink(username, runid) { export function userDirectRunLink(username, runid) {
return { return { name: "user direct run", params: { username: username, runid: runid } }
name: 'user direct run',
params: { username: username, runid: runid },
};
} }
export function userDirectRunTaskLink(username, runid, taskid) { export function userDirectRunTaskLink(username, runid, taskid) {
return { return { name: "user direct run task", params: { username: username, runid: runid, taskid: taskid } }
name: 'user direct run task',
params: { username: username, runid: runid, taskid: taskid },
};
} }
export function userAddLinkedAccountLink(username, remotesourcename) { export function userAddLinkedAccountLink(username, remotesourcename) {
return { return { name: "user add linked account", params: { username: username, remotesource: remotesourcename } }
name: 'user add linked account',
params: { username: username, remotesource: remotesourcename },
};
} }
export function orgMembersLink(orgname) { export function orgMembersLink(orgname) {
return { name: 'org members', params: { orgname: orgname } }; return { name: "org members", params: { orgname: orgname } }
} }
// Note, when creating a router link containing a project/projectgroup ref (a // Note, when creating a router link containing a project/projectgroup ref (a
// path), unfortunately, we cannot use route name and params since it will path // path), unfortunately, we cannot use route name and params since it will path
// escape it // escape it
export function projectGroupPath(ownertype, ownername, projectgroupref) { export function projectGroupPath(ownertype, ownername, projectgroupref) {
let path = `/${ownertype}/${ownername}`; let path = `/${ownertype}/${ownername}`
// root project group will have a .proj without a name // root project group will have a .proj without a name
let projectgrouppath = projectgroupref.join('/') + '.proj'; let projectgrouppath = (projectgroupref.join("/") + ".proj")
path = `${path}/projectgroups/${projectgrouppath}`; path = `${path}/projectgroups/${projectgrouppath}`
return path; return path
} }
export function projectPath(ownertype, ownername, projectref) { export function projectPath(ownertype, ownername, projectref) {
let path = `/${ownertype}/${ownername}`; let path = `/${ownertype}/${ownername}`
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
path = `${path}/projects/${projectpath}`; path = `${path}/projects/${projectpath}`
return path; return path
} }
export function projectGroupLink(ownertype, ownername, projectgroupref) { export function projectGroupLink(ownertype, ownername, projectgroupref) {
return { path: projectGroupPath(ownertype, ownername, projectgroupref) }; return { path: projectGroupPath(ownertype, ownername, projectgroupref) }
} }
export function projectGroupProjectsLink( export function projectGroupProjectsLink(ownertype, ownername, projectgroupref) {
ownertype, let projectgrouppath = (projectgroupref.join("/") + ".proj")
ownername, return { path: `/${ownertype}/${ownername}/projectgroups/${projectgrouppath}/projects` }
projectgroupref
) {
let projectgrouppath = projectgroupref.join('/') + '.proj';
return {
path: `/${ownertype}/${ownername}/projectgroups/${projectgrouppath}/projects`,
};
} }
export function projectLink(ownertype, ownername, projectref) { export function projectLink(ownertype, ownername, projectref) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { path: `/${ownertype}/${ownername}/projects/${projectpath}` }; return { path: `/${ownertype}/${ownername}/projects/${projectpath}` }
} }
export function projectRunsLink(ownertype, ownername, projectref) { export function projectRunsLink(ownertype, ownername, projectref) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { path: `/${ownertype}/${ownername}/projects/${projectpath}/runs` }; return { path: `/${ownertype}/${ownername}/projects/${projectpath}/runs` }
} }
export function projectBranchesRunsLink(ownertype, ownername, projectref) { export function projectBranchesRunsLink(ownertype, ownername, projectref) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { return { path: `/${ownertype}/${ownername}/projects/${projectpath}/branches` }
path: `/${ownertype}/${ownername}/projects/${projectpath}/branches`,
};
} }
export function projectTagsRunsLink(ownertype, ownername, projectref) { export function projectTagsRunsLink(ownertype, ownername, projectref) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { path: `/${ownertype}/${ownername}/projects/${projectpath}/tags` }; return { path: `/${ownertype}/${ownername}/projects/${projectpath}/tags` }
} }
export function projectPRsRunsLink(ownertype, ownername, projectref) { export function projectPRsRunsLink(ownertype, ownername, projectref) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { return { path: `/${ownertype}/${ownername}/projects/${projectpath}/pullrequests` }
path: `/${ownertype}/${ownername}/projects/${projectpath}/pullrequests`,
};
} }
export function projectRunLink(ownertype, ownername, projectref, runid) { export function projectRunLink(ownertype, ownername, projectref, runid) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { return { path: `/${ownertype}/${ownername}/projects/${projectpath}/runs/${runid}` }
path: `/${ownertype}/${ownername}/projects/${projectpath}/runs/${runid}`,
};
} }
export function projectRunTaskLink( export function projectRunTaskLink(ownertype, ownername, projectref, runid, taskid) {
ownertype, let projectpath = (projectref.join("/") + ".proj")
ownername, return { path: `/${ownertype}/${ownername}/projects/${projectpath}/runs/${runid}/tasks/${taskid}` }
projectref,
runid,
taskid
) {
let projectpath = projectref.join('/') + '.proj';
return {
path: `/${ownertype}/${ownername}/projects/${projectpath}/runs/${runid}/tasks/${taskid}`,
};
} }
export function projectGroupSettingsLink( export function projectGroupSettingsLink(ownertype, ownername, projectgroupref) {
ownertype, let path = projectGroupPath(ownertype, ownername, projectgroupref)
ownername, return { path: `${path}/settings` }
projectgroupref
) {
let path = projectGroupPath(ownertype, ownername, projectgroupref);
return { path: `${path}/settings` };
} }
export function projectSettingsLink(ownertype, ownername, projectref) { export function projectSettingsLink(ownertype, ownername, projectref) {
let projectpath = projectref.join('/') + '.proj'; let projectpath = (projectref.join("/") + ".proj")
return { return { path: `/${ownertype}/${ownername}/projects/${projectpath}/settings` }
path: `/${ownertype}/${ownername}/projects/${projectpath}/settings`,
};
} }
export function projectGroupCreateProjectGroupLink( export function projectGroupCreateProjectGroupLink(ownertype, ownername, projectgroupref) {
ownertype, let path = projectGroupPath(ownertype, ownername, projectgroupref)
ownername, return { path: `${path}/createprojectgroup` }
projectgroupref
) {
let path = projectGroupPath(ownertype, ownername, projectgroupref);
return { path: `${path}/createprojectgroup` };
} }
export function projectGroupCreateProjectLink( export function projectGroupCreateProjectLink(ownertype, ownername, projectgroupref) {
ownertype, let path = projectGroupPath(ownertype, ownername, projectgroupref)
ownername, return { path: `${path}/createproject` }
projectgroupref
) {
let path = projectGroupPath(ownertype, ownername, projectgroupref);
return { path: `${path}/createproject` };
} }

View File

@ -1,10 +1,11 @@
export function runStatus(run) { export function runStatus(run) {
// * if the run has a result then return the result // * if the run has a result then return the result
// * if stopping return "stopping" // * if stopping return "stopping"
// * return the phase // * return the phase
if (run.result != 'unknown') return run.result; if (run.result != "unknown") return run.result;
if (run.stopping) return 'stopping'; if (run.stopping) return "stopping";
if (run.phase != 'finished') return run.phase; if (run.phase != "finished") return run.phase;
return run.result; return run.result;
} }
@ -12,13 +13,13 @@ export function runStatus(run) {
export function runResultClass(run) { export function runResultClass(run) {
let status = runStatus(run); let status = runStatus(run);
if (status == 'setuperror') return 'setuperror'; if (status == "setuperror") return "setuperror";
if (status == 'queued') return 'unknown'; if (status == "queued") return "unknown";
if (status == 'cancelled') return 'failed'; if (status == "cancelled") return "failed";
if (status == 'running') return 'running'; if (status == "running") return "running";
if (status == 'stopping') return 'failed'; if (status == "stopping") return "failed";
if (status == 'stopped') return 'failed'; if (status == "stopped") return "failed";
if (status == 'success') return 'success'; if (status == "success") return "success";
if (status == 'failed') return 'failed'; if (status == "failed") return "failed";
return 'unknown'; return "unknown";
} }

View File

@ -13,44 +13,36 @@
v-if="remotesource.auth_type == 'password'" v-if="remotesource.auth_type == 'password'"
action="Add Linked Account" action="Add Linked Account"
:name="remotesource.name" :name="remotesource.name"
v-on:login=" v-on:login="doAddLinkedAccount(remotesource.name, $event.username, $event.password)"
doAddLinkedAccount(
remotesource.name,
$event.username,
$event.password
)
"
/> />
<button <button
v-else v-else
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
@click="doAddLinkedAccount(remotesource.name)" @click="doAddLinkedAccount(remotesource.name)"
> >Add Linked Account with {{remotesource.name}}</button>
Add Linked Account with {{ remotesource.name }}
</button>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import LoginForm from '@/components/loginform'; import LoginForm from "@/components/loginform";
import { fetchRemoteSources, createUserLinkedAccount } from '@/util/data'; import { fetchRemoteSources, createUserLinkedAccount } from "@/util/data";
export default { export default {
name: 'AddLinkedAccount', name: "AddLinkedAccount",
props: { props: {
username: String, username: String,
remoteSourceName: String, remoteSourceName: String
}, },
components: { components: {
LoginForm, LoginForm
}, },
data: function () { data: function() {
return { return {
addLinkedAccountError: null, addLinkedAccountError: null,
remotesource: null, remotesource: null
}; };
}, },
methods: { methods: {
@ -60,7 +52,7 @@ export default {
async fetchRemoteSources() { async fetchRemoteSources() {
let { data, error } = await fetchRemoteSources(); let { data, error } = await fetchRemoteSources();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
@ -87,13 +79,17 @@ export default {
return; return;
} }
this.$router.push({ this.$router.push({
name: 'user settings', name: "user settings",
params: { username: this.username }, params: { username: this.username }
}); });
}
}, },
}, created: function() {
created: function () {
this.fetchRemoteSources(); this.fetchRemoteSources();
}, }
}; };
</script> </script>

View File

@ -1,70 +0,0 @@
<template>
<div>
<div
v-if="error"
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
role="alert"
>
<span class="block sm:inline">{{ error }}</span>
</div>
<div>
<div>
<div class="flex justify-center items-center w-max">
<CreateSourceForm v-on:createSource="createSource($event)" />
</div>
</div>
</div>
</div>
</template>
<script>
import CreateSourceForm from '@/components/createsourceform';
import { createRemoteSource } from '@/util/data.js';
import router from '@/router';
export default {
name: 'CreateSource',
components: {
CreateSourceForm,
},
data: function () {
return {
error: null,
};
},
methods: {
async createSource({
token,
name,
type,
clientId,
clientSecret,
url,
skipVerify,
sshHostKey,
skipSshHostKeyCheck,
}) {
const res = await createRemoteSource(
token,
type,
name,
clientId,
clientSecret,
url,
'oauth2',
skipVerify,
sshHostKey,
skipSshHostKeyCheck,
true,
true,
undefined
);
if (res.error) this.$store.dispatch('setError', res.error);
else router.push({ name: 'login' });
},
},
mounted: function () {
this.$store.dispatch('setError', null);
},
};
</script>

View File

@ -1,39 +1,24 @@
<template> <template>
<div class="home flex flex-col items-center"> <div class="home"></div>
<img class="w-64 h-64" src="/img/agola-logo-name.svg" alt="agola logo" />
<h1 class="text-2xl">CI/CD redefined</h1>
<div class="m-8">
<h1 class="text-lg">
Hi, you are almost ready to go! Just
<router-link class="underline text-blue-600" to="/login">
login
</router-link>
into your account or create a
<router-link class="underline text-blue-600" to="/register">
new one
</router-link>
</h1>
</div>
</div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from "vuex";
export default { export default {
name: 'Home', name: "Home",
components: {}, components: {},
computed: { computed: {
...mapGetters(['user']), ...mapGetters(["user"])
}, },
created: function () { created: function() {
let user = this.$store.getters.user; let user = this.$store.getters.user;
if (user) { if (user) {
this.$router.push({ this.$router.push({
name: 'user', name: "user",
params: { username: this.user.username }, params: { username: this.user.username }
}); });
} }
}, }
}; };
</script> </script>

View File

@ -13,9 +13,6 @@
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
> >
No remote sources defined No remote sources defined
<router-link class="underline text-blue-600 block" to="/newsource">
<button class="btn btn-blue">Create one</button>
</router-link>
</div> </div>
<div <div
v-else-if="!hasLoginRemoteSources" v-else-if="!hasLoginRemoteSources"
@ -56,25 +53,25 @@
</template> </template>
<script> <script>
import { fetchRemoteSources, login } from '@/util/data'; import { fetchRemoteSources, login } from "@/util/data";
import { import {
setLoggedUser, setLoggedUser,
unsetLoginRedirect, unsetLoginRedirect,
setLoginRedirect, setLoginRedirect,
doLogout, doLogout
} from '@/util/auth'; } from "@/util/auth";
import LoginForm from '@/components/loginform'; import LoginForm from "@/components/loginform";
export default { export default {
name: 'Login', name: "Login",
components: { components: {
LoginForm, LoginForm
}, },
data: function () { data: function() {
return { return {
error: null, error: null,
remotesources: null, remotesources: null
}; };
}, },
computed: { computed: {
@ -91,20 +88,20 @@ export default {
} }
} }
return false; return false;
}, }
}, },
methods: { methods: {
async fetchRemoteSources() { async fetchRemoteSources() {
let { data, error } = await fetchRemoteSources(); let { data, error } = await fetchRemoteSources();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.remotesources = data; this.remotesources = data;
}, },
async doLogin(username, password, remotesourcename) { async doLogin(username, password, remotesourcename) {
unsetLoginRedirect(); unsetLoginRedirect();
let redirect = this.$route.query['redirect']; let redirect = this.$route.query["redirect"];
this.error = null; this.error = null;
@ -126,16 +123,18 @@ export default {
unsetLoginRedirect(); unsetLoginRedirect();
this.$router.push(redirect); this.$router.push(redirect);
} else { } else {
this.$router.push({ name: 'home' }); this.$router.push({ name: "home" });
}
} }
}, },
mounted: function() {
this.$store.dispatch("setError", null);
}, },
mounted: function () { created: function() {
this.$store.dispatch('setError', null);
},
created: function () {
doLogout(); doLogout();
this.fetchRemoteSources(); this.fetchRemoteSources();
}, }
}; };
</script> </script>

View File

@ -1,11 +1,13 @@
<script> <script>
import { doLogout } from '@/util/auth'; import { doLogout } from "@/util/auth";
export default { export default {
name: 'Logout', name: "Logout",
created: function () { created: function() {
doLogout(); doLogout();
this.$router.push('/'); this.$router.push("/");
}, }
}; };
</script> </script>

View File

@ -11,32 +11,32 @@
</template> </template>
<script> <script>
import { fetch } from '@/util/data'; import { fetch } from "@/util/data";
import { import {
oauth2callbackurl, oauth2callbackurl,
setLoggedUser, setLoggedUser,
unsetLoginRedirect, unsetLoginRedirect,
getLoginRedirect, getLoginRedirect
} from '@/util/auth'; } from "@/util/auth";
export default { export default {
components: {}, components: {},
name: 'Oauth2', name: "Oauth2",
props: {}, props: {},
data() { data() {
return { return {
error: null, error: null,
run: null, run: null,
code: this.$route.query.code, code: this.$route.query.code,
username: null, username: null
}; };
}, },
methods: { methods: {
async doOauth2() { async doOauth2() {
let u = oauth2callbackurl(); let u = oauth2callbackurl();
u.searchParams.append('code', this.$route.query.code); u.searchParams.append("code", this.$route.query.code);
u.searchParams.append('state', this.$route.query.state); u.searchParams.append("state", this.$route.query.state);
let { data, error } = await fetch(u); let { data, error } = await fetch(u);
if (error) { if (error) {
// set local login error on failed oauth2. // set local login error on failed oauth2.
@ -44,28 +44,29 @@ export default {
return; return;
} }
if (data.request_type === 'loginuser') { if (data.request_type === "loginuser") {
setLoggedUser(data.response.token, data.response.user); setLoggedUser(data.response.token, data.response.user);
let redirect = getLoginRedirect(redirect); let redirect = getLoginRedirect(redirect);
if (redirect) { if (redirect) {
unsetLoginRedirect(); unsetLoginRedirect();
this.$router.push(redirect); this.$router.push(redirect);
} else { } else {
this.$router.push({ name: 'home' }); this.$router.push({ name: "home" });
} }
} else if (data.request_type === 'authorize') { } else if (data.request_type === "authorize") {
this.$store.dispatch('setRegisterUser', data.response); this.$store.dispatch("setRegisterUser", data.response);
this.$router.push('/register'); this.$router.push("/register");
} else if (data.request_type === 'createuserla') { } else if (data.request_type === "createuserla") {
this.$router.push({ this.$router.push({
name: 'user settings', name: "user settings",
params: { username: this.username }, params: { username: this.username }
}); });
} }
}
}, },
}, created: function() {
created: function () {
this.doOauth2(); this.doOauth2();
}, }
}; };
</script> </script>

View File

@ -9,15 +9,13 @@
<span class="mx-2">/</span> <span class="mx-2">/</span>
</li> </li>
<li> <li>
<router-link :to="ownerLink('org', orgname)">{{ <router-link :to="ownerLink('org', orgname)">{{orgname}}</router-link>
orgname
}}</router-link>
</li> </li>
</ol> </ol>
</nav> </nav>
<div class="mb-8 flex justify-between"> <div class="mb-8 flex justify-between">
<span class="text-3xl">{{ orgname }}</span> <span class="text-3xl">{{orgname}}</span>
<createprojectbutton v-on:click="goToCreate($event)" /> <createprojectbutton v-on:click="goToCreate($event)" />
</div> </div>
@ -25,12 +23,7 @@
<ul class="flex-grow tab"> <ul class="flex-grow tab">
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name === 'org projects' || $route.name === 'org' }]"
{
'tab-element-selected':
$route.name === 'org projects' || $route.name === 'org',
},
]"
> >
<router-link :to="ownerProjectsLink('org', orgname)"> <router-link :to="ownerProjectsLink('org', orgname)">
<i class="mr-1 mdi mdi-home" /> <i class="mr-1 mdi mdi-home" />
@ -49,13 +42,7 @@
<li <li
v-if="$route.name.endsWith('org project group settings')" v-if="$route.name.endsWith('org project group settings')"
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('org project group settings') }]"
{
'tab-element-selected': $route.name.endsWith(
'org project group settings'
),
},
]"
> >
<router-link :to="projectGroupSettingsLink('org', orgname, [])"> <router-link :to="projectGroupSettingsLink('org', orgname, [])">
<i class="mr-1 mdi mdi-settings" /> <i class="mr-1 mdi mdi-settings" />
@ -65,9 +52,7 @@
<li <li
v-if="$route.name.endsWith('org settings')" v-if="$route.name.endsWith('org settings')"
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('org settings') }]"
{ 'tab-element-selected': $route.name.endsWith('org settings') },
]"
> >
<router-link :to="ownerSettingsLink('org', orgname)"> <router-link :to="ownerSettingsLink('org', orgname)">
<i class="mr-1 mdi mdi-settings" /> <i class="mr-1 mdi mdi-settings" />
@ -80,7 +65,7 @@
<div class="relative"> <div class="relative">
<div <div
class="flex -mt-3" class="flex -mt-3"
v-click-outside="() => (dropdownActive = false)" v-click-outside="() => dropdownActive = false"
@click="dropdownActive = !dropdownActive" @click="dropdownActive = !dropdownActive"
> >
<button <button
@ -123,8 +108,9 @@
</div> </div>
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
import { import {
ownerLink, ownerLink,
@ -133,23 +119,23 @@ import {
orgMembersLink, orgMembersLink,
projectGroupCreateProjectGroupLink, projectGroupCreateProjectGroupLink,
projectGroupCreateProjectLink, projectGroupCreateProjectLink,
projectGroupSettingsLink, projectGroupSettingsLink
} from '@/util/link.js'; } from "@/util/link.js";
import createprojectbutton from '@/components/createprojectbutton.vue'; import createprojectbutton from "@/components/createprojectbutton.vue";
export default { export default {
name: 'Org', name: "Org",
components: { createprojectbutton }, components: { createprojectbutton },
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
props: { props: {
orgname: String, orgname: String
}, },
data() { data() {
return { return {
dropdownActive: false, dropdownActive: false
}; };
}, },
methods: { methods: {
@ -161,18 +147,19 @@ export default {
projectGroupCreateProjectLink: projectGroupCreateProjectLink, projectGroupCreateProjectLink: projectGroupCreateProjectLink,
projectGroupSettingsLink: projectGroupSettingsLink, projectGroupSettingsLink: projectGroupSettingsLink,
goToCreate(type) { goToCreate(type) {
if (type == 'project') { if (type == "project") {
this.$router.push( this.$router.push(
projectGroupCreateProjectLink('org', this.orgname, []) projectGroupCreateProjectLink("org", this.orgname, [])
); );
return; return;
} }
this.$router.push( this.$router.push(
projectGroupCreateProjectGroupLink('org', this.orgname, []) projectGroupCreateProjectGroupLink("org", this.orgname, [])
); );
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -1,13 +1,9 @@
<template> <template>
<div> <div>
<projbreadcrumbs <projbreadcrumbs :ownertype="ownertype" :ownername="ownername" :projectref="projectref" />
:ownertype="ownertype"
:ownername="ownername"
:projectref="projectref"
/>
<div class="mb-8"> <div class="mb-8">
<span class="text-3xl">{{ projectName() }}</span> <span class="text-3xl">{{projectName()}}</span>
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
@ -21,13 +17,7 @@
</li> </li>
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.match('project runs') || $route.name.endsWith('project') }]"
{
'tab-element-selected':
$route.name.match('project runs') ||
$route.name.endsWith('project'),
},
]"
> >
<router-link :to="projectRunsLink(ownertype, ownername, projectref)"> <router-link :to="projectRunsLink(ownertype, ownername, projectref)">
<i class="mr-1 mdi mdi-asterisk" /> <i class="mr-1 mdi mdi-asterisk" />
@ -36,84 +26,45 @@
</li> </li>
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.match('project branches runs') }]"
{
'tab-element-selected': $route.name.match(
'project branches runs'
),
},
]"
>
<router-link
:to="projectBranchesRunsLink(ownertype, ownername, projectref)"
> >
<router-link :to="projectBranchesRunsLink(ownertype, ownername, projectref)">
<i class="mr-1 mdi mdi-source-branch" /> <i class="mr-1 mdi mdi-source-branch" />
<span>Branches</span> <span>Branches</span>
</router-link> </router-link>
</li> </li>
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.match('project tags runs') }]"
{ 'tab-element-selected': $route.name.match('project tags runs') },
]"
>
<router-link
:to="projectTagsRunsLink(ownertype, ownername, projectref)"
> >
<router-link :to="projectTagsRunsLink(ownertype, ownername, projectref)">
<i class="mr-1 mdi mdi-tag" /> <i class="mr-1 mdi mdi-tag" />
<span>Tags</span> <span>Tags</span>
</router-link> </router-link>
</li> </li>
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.match('project pull requests runs') }]"
{
'tab-element-selected': $route.name.match(
'project pull requests runs'
),
},
]"
>
<router-link
:to="projectPRsRunsLink(ownertype, ownername, projectref)"
> >
<router-link :to="projectPRsRunsLink(ownertype, ownername, projectref)">
<i class="mr-1 mdi mdi-source-pull" /> <i class="mr-1 mdi mdi-source-pull" />
<span>Pull Requests</span> <span>Pull Requests</span>
</router-link> </router-link>
</li> </li>
<li <li
v-if=" v-if="run && ($route.name.endsWith('project run') || $route.name.endsWith('project run task'))"
run &&
($route.name.endsWith('project run') ||
$route.name.endsWith('project run task'))
"
> >
<tabarrow /> <tabarrow />
</li> </li>
<li <li
class="tab-element" class="tab-element"
v-if=" v-if="run && ($route.name.endsWith('project run') || $route.name.endsWith('project run task'))"
run && :class="[{ 'tab-element-selected': $route.name.endsWith('project run') }]"
($route.name.endsWith('project run') ||
$route.name.endsWith('project run task'))
"
:class="[
{ 'tab-element-selected': $route.name.endsWith('project run') },
]"
>
<router-link
:to="
projectRunLink(
ownertype,
ownername,
projectref,
$route.params.runid
)
"
> >
<router-link :to="projectRunLink(ownertype, ownername, projectref, $route.params.runid)">
<p> <p>
Run Run
<strong>#{{ run.counter }}</strong> <strong>#{{run.counter}}</strong>
</p> </p>
</router-link> </router-link>
</li> </li>
@ -123,41 +74,23 @@
<li <li
class="tab-element" class="tab-element"
v-if="run && $route.name.endsWith('project run task')" v-if="run && $route.name.endsWith('project run task')"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('project run task') }]"
{
'tab-element-selected': $route.name.endsWith('project run task'),
},
]"
> >
<router-link <router-link
:to=" :to="projectRunTaskLink(ownertype, ownername, projectref, $route.params.runid, $route.params.taskid)"
projectRunTaskLink(
ownertype,
ownername,
projectref,
$route.params.runid,
$route.params.taskid
)
"
> >
<p> <p>
Task Task
<strong>{{ run.tasks[$route.params.taskid].name }}</strong> <strong>{{run.tasks[$route.params.taskid].name}}</strong>
</p> </p>
</router-link> </router-link>
</li> </li>
<li <li
v-if="$route.name.endsWith('project settings')" v-if="$route.name.endsWith('project settings')"
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('project settings') }]"
{
'tab-element-selected': $route.name.endsWith('project settings'),
},
]"
>
<router-link
:to="projectSettingsLink(ownertype, ownername, projectref)"
> >
<router-link :to="projectSettingsLink(ownertype, ownername, projectref)">
<i class="mr-1 mdi mdi-settings" /> <i class="mr-1 mdi mdi-settings" />
<span>Project Settings</span> <span>Project Settings</span>
</router-link> </router-link>
@ -168,7 +101,7 @@
<div class="relative"> <div class="relative">
<div <div
class="flex -mt-3" class="flex -mt-3"
v-click-outside="() => (dropdownActive = false)" v-click-outside="() => dropdownActive = false"
@click="dropdownActive = !dropdownActive" @click="dropdownActive = !dropdownActive"
> >
<button <button
@ -202,8 +135,9 @@
</div> </div>
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
import { import {
projectLink, projectLink,
@ -213,35 +147,35 @@ import {
projectPRsRunsLink, projectPRsRunsLink,
projectRunLink, projectRunLink,
projectRunTaskLink, projectRunTaskLink,
projectSettingsLink, projectSettingsLink
} from '@/util/link.js'; } from "@/util/link.js";
import { fetchRun } from '@/util/data.js'; import { fetchRun } from "@/util/data.js";
import projbreadcrumbs from '@/components/projbreadcrumbs.vue'; import projbreadcrumbs from "@/components/projbreadcrumbs.vue";
import tabarrow from '@/components/tabarrow.vue'; import tabarrow from "@/components/tabarrow.vue";
export default { export default {
name: 'Project', name: "Project",
components: { projbreadcrumbs, tabarrow }, components: { projbreadcrumbs, tabarrow },
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectref: Array, projectref: Array
}, },
data() { data() {
return { return {
fetchAbort: null, fetchAbort: null,
dropdownActive: false, dropdownActive: false,
run: null, run: null
}; };
}, },
watch: { watch: {
$route: async function (route) { $route: async function(route) {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
@ -257,12 +191,12 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.run = data; this.run = data;
} }
}, }
}, },
methods: { methods: {
projectLink: projectLink, projectLink: projectLink,
@ -275,9 +209,9 @@ export default {
projectSettingsLink: projectSettingsLink, projectSettingsLink: projectSettingsLink,
projectName() { projectName() {
return this.projectref[this.projectref.length - 1]; return this.projectref[this.projectref.length - 1];
}
}, },
}, created: async function() {
created: async function () {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
if (this.$route.params.runid) { if (this.$route.params.runid) {
@ -289,7 +223,7 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.run = data; this.run = data;
@ -299,8 +233,9 @@ export default {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -1,3 +1,4 @@
<template> <template>
<div> <div>
<projbreadcrumbs <projbreadcrumbs
@ -7,7 +8,7 @@
/> />
<div class="mb-8 flex justify-between"> <div class="mb-8 flex justify-between">
<span class="text-3xl">{{ projectGroupName() }}</span> <span class="text-3xl">{{projectGroupName()}}</span>
<createprojectbutton v-on:click="goToCreate($event)" /> <createprojectbutton v-on:click="goToCreate($event)" />
</div> </div>
@ -15,19 +16,9 @@
<ul class="flex-grow tab"> <ul class="flex-grow tab">
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.match('project group project') || $route.name.endsWith('project group') }]"
{
'tab-element-selected':
$route.name.match('project group project') ||
$route.name.endsWith('project group'),
},
]"
>
<router-link
:to="
projectGroupProjectsLink(ownertype, ownername, projectgroupref)
"
> >
<router-link :to="projectGroupProjectsLink(ownertype, ownername, projectgroupref)">
<i class="mdi mdi-home" /> <i class="mdi mdi-home" />
<span>Projects</span> <span>Projects</span>
</router-link> </router-link>
@ -35,19 +26,9 @@
<li <li
v-if="$route.name.endsWith('project group settings')" v-if="$route.name.endsWith('project group settings')"
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('project group settings') }]"
{
'tab-element-selected': $route.name.endsWith(
'project group settings'
),
},
]"
>
<router-link
:to="
projectGroupSettingsLink(ownertype, ownername, projectgroupref)
"
> >
<router-link :to="projectGroupSettingsLink(ownertype, ownername, projectgroupref)">
<i class="mdi mdi-settings" /> <i class="mdi mdi-settings" />
<span>Project Group Settings</span> <span>Project Group Settings</span>
</router-link> </router-link>
@ -58,7 +39,7 @@
<div class="relative"> <div class="relative">
<div <div
class="flex -mt-3" class="flex -mt-3"
v-click-outside="() => (dropdownActive = false)" v-click-outside="() => dropdownActive = false"
@click="dropdownActive = !dropdownActive" @click="dropdownActive = !dropdownActive"
> >
<button <button
@ -76,13 +57,7 @@
<li> <li>
<router-link <router-link
class="block px-4 py-2 hover:bg-blue-500 hover:text-white" class="block px-4 py-2 hover:bg-blue-500 hover:text-white"
:to=" :to="projectGroupSettingsLink(ownertype, ownername, projectgroupref)"
projectGroupSettingsLink(
ownertype,
ownername,
projectgroupref
)
"
> >
<i class="mdi mdi-settings" /> <i class="mdi mdi-settings" />
<span>Project Group Settings</span> <span>Project Group Settings</span>
@ -98,33 +73,34 @@
</div> </div>
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
import { import {
projectGroupProjectsLink, projectGroupProjectsLink,
projectGroupSettingsLink, projectGroupSettingsLink,
projectGroupCreateProjectGroupLink, projectGroupCreateProjectGroupLink,
projectGroupCreateProjectLink, projectGroupCreateProjectLink
} from '@/util/link.js'; } from "@/util/link.js";
import projbreadcrumbs from '@/components/projbreadcrumbs.vue'; import projbreadcrumbs from "@/components/projbreadcrumbs.vue";
import createprojectbutton from '@/components/createprojectbutton.vue'; import createprojectbutton from "@/components/createprojectbutton.vue";
export default { export default {
name: 'ProjectGroup', name: "ProjectGroup",
components: { projbreadcrumbs, createprojectbutton }, components: { projbreadcrumbs, createprojectbutton },
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
props: { props: {
ownertype: String, ownertype: String,
ownername: String, ownername: String,
projectgroupref: Array, projectgroupref: Array
}, },
data() { data() {
return { return {
dropdownActive: false, dropdownActive: false
}; };
}, },
methods: { methods: {
@ -134,12 +110,12 @@ export default {
projectGroupCreateProjectLink: projectGroupCreateProjectLink, projectGroupCreateProjectLink: projectGroupCreateProjectLink,
projectGroupName() { projectGroupName() {
if (!this.projectgroupref.length) { if (!this.projectgroupref.length) {
return 'Root Project Group'; return "Root Project Group";
} }
return this.projectgroupref[this.projectgroupref.length - 1]; return this.projectgroupref[this.projectgroupref.length - 1];
}, },
goToCreate(type) { goToCreate(type) {
if (type == 'project') { if (type == "project") {
this.$router.push( this.$router.push(
projectGroupCreateProjectLink( projectGroupCreateProjectLink(
this.ownertype, this.ownertype,
@ -156,9 +132,10 @@ export default {
this.projectgroupref this.projectgroupref
) )
); );
}, }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -28,9 +28,6 @@
class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" class="mb-10 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
> >
No remote sources defined No remote sources defined
<router-link class="underline text-blue-600 block" to="/newsource">
<button class="btn btn-blue">Create one</button>
</router-link>
</div> </div>
<div <div
v-else-if="!hasRegisterRemoteSources" v-else-if="!hasRegisterRemoteSources"
@ -70,29 +67,29 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from "vuex";
import LoginForm from '@/components/loginform'; import LoginForm from "@/components/loginform";
import RegisterForm from '@/components/registerform'; import RegisterForm from "@/components/registerform";
import { fetchRemoteSources, register } from '@/util/data'; import { fetchRemoteSources, register } from "@/util/data";
import { authorizeurl, fetch, doLogout } from '@/util/auth'; import { authorizeurl, fetch, doLogout } from "@/util/auth";
export default { export default {
name: 'Register', name: "Register",
components: { components: {
LoginForm, LoginForm,
RegisterForm, RegisterForm
}, },
data: function () { data: function() {
return { return {
error: null, error: null,
remotesources: null, remotesources: null
}; };
}, },
computed: { computed: {
...mapGetters(['registeruser']), ...mapGetters(["registeruser"]),
hasRemoteSources() { hasRemoteSources() {
if (this.remotesources) { if (this.remotesources) {
@ -107,13 +104,13 @@ export default {
} }
} }
return false; return false;
}, }
}, },
methods: { methods: {
async fetchRemoteSources() { async fetchRemoteSources() {
let { data, error } = await fetchRemoteSources(); let { data, error } = await fetchRemoteSources();
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.remotesources = data; this.remotesources = data;
@ -122,12 +119,12 @@ export default {
let u = authorizeurl(); let u = authorizeurl();
let res = await ( let res = await (
await fetch(u, { await fetch(u, {
method: 'POST', method: "POST",
body: JSON.stringify({ body: JSON.stringify({
remote_source_name: remotesourcename, remote_source_name: remotesourcename,
login_name: username, login_name: username,
password: password, password: password
}), })
}) })
).json(); ).json();
@ -135,11 +132,11 @@ export default {
window.location = res.oauth2_redirect; window.location = res.oauth2_redirect;
return; return;
} }
this.$store.dispatch('setRegisterUser', { this.$store.dispatch("setRegisterUser", {
remote_user_info: res.remote_user_info, remote_user_info: res.remote_user_info,
remote_source_name: res.remote_source_name, remote_source_name: res.remote_source_name,
remote_source_login_name: username, remote_source_login_name: username,
remote_source_login_password: password, remote_source_login_password: password
}); });
}, },
async doRegister( async doRegister(
@ -165,15 +162,18 @@ export default {
window.location = data.oauth2_redirect; window.location = data.oauth2_redirect;
return; return;
} }
this.$router.push({ name: 'home' }); this.$router.push({ name: "home" });
}
}, },
mounted: function() {
this.$store.dispatch("setError", null);
}, },
mounted: function () { created: function() {
this.$store.dispatch('setError', null);
},
created: function () {
doLogout(); doLogout();
this.fetchRemoteSources(); this.fetchRemoteSources();
}, }
}; };
</script> </script>

View File

@ -9,15 +9,13 @@
<span class="mx-2">/</span> <span class="mx-2">/</span>
</li> </li>
<li> <li>
<router-link :to="ownerLink('user', username)">{{ <router-link :to="ownerLink('user', username)">{{username}}</router-link>
username
}}</router-link>
</li> </li>
</ol> </ol>
</nav> </nav>
<div class="mb-8 flex justify-between"> <div class="mb-8 flex justify-between">
<span class="text-3xl">{{ username }}</span> <span class="text-3xl">{{username}}</span>
<createprojectbutton v-on:click="goToCreate($event)" /> <createprojectbutton v-on:click="goToCreate($event)" />
</div> </div>
@ -25,12 +23,7 @@
<ul class="flex-grow tab"> <ul class="flex-grow tab">
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name === 'user projects' || $route.name === 'user' }]"
{
'tab-element-selected':
$route.name === 'user projects' || $route.name === 'user',
},
]"
> >
<router-link :to="ownerProjectsLink('user', username)"> <router-link :to="ownerProjectsLink('user', username)">
<i class="mr-1 mdi mdi-home" /> <i class="mr-1 mdi mdi-home" />
@ -39,9 +32,7 @@
</li> </li>
<li <li
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name === 'user direct runs' }]"
{ 'tab-element-selected': $route.name === 'user direct runs' },
]"
> >
<router-link :to="userDirectRunsLink(username)"> <router-link :to="userDirectRunsLink(username)">
<i class="mr-1 mdi mdi-run-fast" /> <i class="mr-1 mdi mdi-run-fast" />
@ -49,29 +40,19 @@
</router-link> </router-link>
</li> </li>
<li <li
v-if=" v-if="run && ($route.name === 'user direct run' || $route.name == 'user direct run task')"
run &&
($route.name === 'user direct run' ||
$route.name == 'user direct run task')
"
> >
<tabarrow /> <tabarrow />
</li> </li>
<li <li
class="tab-element" class="tab-element"
v-if=" v-if="run && ($route.name === 'user direct run' || $route.name == 'user direct run task')"
run && :class="[{ 'tab-element-selected': $route.name === 'user direct run' }]"
($route.name === 'user direct run' ||
$route.name == 'user direct run task')
"
:class="[
{ 'tab-element-selected': $route.name === 'user direct run' },
]"
> >
<router-link :to="userDirectRunLink(username, $route.params.runid)"> <router-link :to="userDirectRunLink(username, $route.params.runid)">
<span> <span>
Run Run
<strong>#{{ run.counter }}</strong> <strong>#{{run.counter}}</strong>
</span> </span>
</router-link> </router-link>
</li> </li>
@ -81,35 +62,21 @@
<li <li
class="tab-element" class="tab-element"
v-if="run && $route.name == 'user direct run task'" v-if="run && $route.name == 'user direct run task'"
:class="[ :class="[{ 'tab-element-selected': $route.name === 'user direct run task' }]"
{ 'tab-element-selected': $route.name === 'user direct run task' },
]"
> >
<router-link <router-link
:to=" :to="userDirectRunTaskLink(username, $route.params.runid, $route.params.taskid)"
userDirectRunTaskLink(
username,
$route.params.runid,
$route.params.taskid
)
"
> >
<span> <span>
Task Task
<strong>{{ run.tasks[$route.params.taskid].name }}</strong> <strong>{{run.tasks[$route.params.taskid].name}}</strong>
</span> </span>
</router-link> </router-link>
</li> </li>
<li <li
v-if="$route.name.endsWith('user project group settings')" v-if="$route.name.endsWith('user project group settings')"
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('user project group settings') }]"
{
'tab-element-selected': $route.name.endsWith(
'user project group settings'
),
},
]"
> >
<router-link :to="projectGroupSettingsLink('user', username, [])"> <router-link :to="projectGroupSettingsLink('user', username, [])">
<i class="mr-1 mdi mdi-settings" /> <i class="mr-1 mdi mdi-settings" />
@ -119,9 +86,7 @@
<li <li
v-if="$route.name.endsWith('user settings')" v-if="$route.name.endsWith('user settings')"
class="tab-element" class="tab-element"
:class="[ :class="[{ 'tab-element-selected': $route.name.endsWith('user settings') }]"
{ 'tab-element-selected': $route.name.endsWith('user settings') },
]"
> >
<router-link :to="ownerSettingsLink('user', username)"> <router-link :to="ownerSettingsLink('user', username)">
<i class="mr-1 mdi mdi-settings" /> <i class="mr-1 mdi mdi-settings" />
@ -134,7 +99,7 @@
<div class="relative"> <div class="relative">
<div <div
class="flex -mt-3" class="flex -mt-3"
v-click-outside="() => (dropdownActive = false)" v-click-outside="() => dropdownActive = false"
@click="dropdownActive = !dropdownActive" @click="dropdownActive = !dropdownActive"
> >
<button <button
@ -169,7 +134,7 @@
</template> </template>
<script> <script>
import * as vClickOutside from 'v-click-outside-x'; import * as vClickOutside from "v-click-outside-x";
import { import {
ownerLink, ownerLink,
@ -180,33 +145,33 @@ import {
ownerSettingsLink, ownerSettingsLink,
projectGroupCreateProjectGroupLink, projectGroupCreateProjectGroupLink,
projectGroupCreateProjectLink, projectGroupCreateProjectLink,
projectGroupSettingsLink, projectGroupSettingsLink
} from '@/util/link.js'; } from "@/util/link.js";
import { fetchRun } from '@/util/data.js'; import { fetchRun } from "@/util/data.js";
import createprojectbutton from '@/components/createprojectbutton.vue'; import createprojectbutton from "@/components/createprojectbutton.vue";
import tabarrow from '@/components/tabarrow.vue'; import tabarrow from "@/components/tabarrow.vue";
export default { export default {
name: 'User', name: "User",
components: { createprojectbutton, tabarrow }, components: { createprojectbutton, tabarrow },
directives: { directives: {
clickOutside: vClickOutside.directive, clickOutside: vClickOutside.directive
}, },
props: { props: {
username: String, username: String
}, },
data() { data() {
return { return {
fetchAbort: null, fetchAbort: null,
dropdownActive: false, dropdownActive: false,
run: null, run: null
}; };
}, },
watch: { watch: {
$route: async function (route) { $route: async function(route) {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
@ -222,12 +187,12 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.run = data; this.run = data;
} }
}, }
}, },
methods: { methods: {
ownerLink: ownerLink, ownerLink: ownerLink,
@ -240,18 +205,18 @@ export default {
projectGroupCreateProjectLink: projectGroupCreateProjectLink, projectGroupCreateProjectLink: projectGroupCreateProjectLink,
projectGroupSettingsLink: projectGroupSettingsLink, projectGroupSettingsLink: projectGroupSettingsLink,
goToCreate(type) { goToCreate(type) {
if (type == 'project') { if (type == "project") {
this.$router.push( this.$router.push(
projectGroupCreateProjectLink('user', this.username, []) projectGroupCreateProjectLink("user", this.username, [])
); );
return; return;
} }
this.$router.push( this.$router.push(
projectGroupCreateProjectGroupLink('user', this.username, []) projectGroupCreateProjectGroupLink("user", this.username, [])
); );
}
}, },
}, created: async function() {
created: async function () {
this.fetchAbort = new AbortController(); this.fetchAbort = new AbortController();
if (this.$route.params.runid) { if (this.$route.params.runid) {
@ -263,7 +228,7 @@ export default {
return; return;
} }
if (error) { if (error) {
this.$store.dispatch('setError', error); this.$store.dispatch("setError", error);
return; return;
} }
this.run = data; this.run = data;
@ -273,8 +238,9 @@ export default {
if (this.fetchAbort) { if (this.fetchAbort) {
this.fetchAbort.abort(); this.fetchAbort.abort();
} }
}, }
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
</style>

View File

@ -6,54 +6,43 @@ module.exports = {
padding: '2rem', padding: '2rem',
}, },
fontFamily: { fontFamily: {
sans: [ 'sans': ['Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', 'sans-serif', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji']
'Segoe UI',
'Roboto',
'Helvetica Neue',
'Arial',
'Noto Sans',
'sans-serif',
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol',
'Noto Color Emoji',
],
}, },
borderWidth: { borderWidth: {
default: '1px', default: '1px',
0: '0', '0': '0',
2: '2px', '2': '2px',
4: '4px', '4': '4px',
5: '5px', '5': '5px',
6: '6px', '6': '6px',
}, },
spacing: { spacing: {
px: '1px', px: '1px',
'2px': '2px', '2px': '2px',
'3px': '3px', '3px': '3px',
0: '0', '0': '0',
1: '0.25rem', '1': '0.25rem',
2: '0.5rem', '2': '0.5rem',
3: '0.75rem', '3': '0.75rem',
4: '1rem', '4': '1rem',
5: '1.25rem', '5': '1.25rem',
6: '1.5rem', '6': '1.5rem',
8: '2rem', '8': '2rem',
10: '2.5rem', '10': '2.5rem',
12: '3rem', '12': '3rem',
16: '4rem', '16': '4rem',
20: '5rem', '20': '5rem',
24: '6rem', '24': '6rem',
32: '8rem', '32': '8rem',
40: '10rem', '40': '10rem',
48: '12rem', '48': '12rem',
56: '14rem', '56': '14rem',
64: '16rem', '64': '16rem',
}, },
colors: { colors: {
dark: '#4a4a4a', dark: '#4a4a4a',
}, }
}, }
}, },
variants: { variants: {
backgroundColor: ['responsive', 'hover', 'focus', 'disabled'], backgroundColor: ['responsive', 'hover', 'focus', 'disabled'],
@ -67,9 +56,9 @@ module.exports = {
function ({ addVariant, e }) { function ({ addVariant, e }) {
addVariant('disabled', ({ modifySelectors, separator }) => { addVariant('disabled', ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => { modifySelectors(({ className }) => {
return `.${e(`disabled${separator}${className}`)}:disabled`; return `.${e(`disabled${separator}${className}`)}:disabled`
}); })
}); })
}, }
], ]
}; }

View File

@ -1,7 +1,7 @@
const path = require('path'); const path = require("path");
module.exports = { module.exports = {
css: { css: {
sourceMap: true, sourceMap: true
}, }
}; };