diff --git a/.vscode/launch.json b/.vscode/launch.json index e910e88c84..0ee1bc87bf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,6 +19,24 @@ "mode": "debug", "program": "${workspaceFolder}/cmd/agent/", "cwd": "${workspaceFolder}" + }, + { + "name": "Woodpecker UI", + "type": "node", + "request": "launch", + "runtimeExecutable": "yarn", + "runtimeArgs": [ + "start", + ], + "cwd": "${workspaceFolder}/web", + "port": 3000, + "resolveSourceMapLocations": [ + "${workspaceFolder}/web/**", + "!**/node_modules/**" + ], + "skipFiles": [ + "/**" + ] } ] } diff --git a/.woodpecker/main.yml b/.woodpecker/main.yml index a8c8a7d101..66791a01fd 100644 --- a/.woodpecker/main.yml +++ b/.woodpecker/main.yml @@ -3,6 +3,61 @@ clone: image: plugins/git:next pipeline: + web-deps: + image: node:16-alpine + commands: + - cd web/ + - yarn install --frozen-lockfile + when: + path: "web/**" + +# TODO: enable if we have enouth mem (~2g) to lint, cause an oom atm. +# For reviewers, please run localy to verify it passes +# web-lint: +# TODO: disabled group for now to prevent oom +# group: web-test +# image: node:16-alpine +# commands: +# - cd web/ +# - yarn lint +# when: +# path: "web/**" + + web-formatcheck: + group: web-test + image: node:16-alpine + commands: + - cd web/ + - yarn formatcheck + when: + path: "web/**" + + web-typecheck: + group: web-test + image: node:16-alpine + commands: + - cd web/ + - yarn typecheck + when: + path: "web/**" + + web-test: + group: web-test + image: node:16-alpine + commands: + - cd web/ + - yarn test + when: + path: "web/**" + + web-build: + image: node:16-alpine + commands: + - cd web/ + - yarn build + when: + path: "web/**" + test: image: golang:1.16 group: test @@ -12,15 +67,6 @@ pipeline: - make lint - make formatcheck - test-frontend: - image: node:10.17.0-stretch - group: test - commands: - - (cd web/; yarn install) - - (cd web/; yarn run lesshint) - - (cd web/; yarn run lint --quiet) - - make test-frontend - test-postgres: image: golang:1.16 group: db-test @@ -40,8 +86,9 @@ pipeline: - go test -timeout 30s github.com/woodpecker-ci/woodpecker/server/store/datastore build-frontend: - image: node:10.17.0-stretch + image: node:16-alpine commands: + - apk add make - make release-frontend build-server: diff --git a/Makefile b/Makefile index ce834cada0..f0f71e0c7c 100644 --- a/Makefile +++ b/Makefile @@ -48,14 +48,20 @@ lint: go run vendor/github.com/rs/zerolog/cmd/lint/lint.go github.com/woodpecker-ci/woodpecker/cmd/cli go run vendor/github.com/rs/zerolog/cmd/lint/lint.go github.com/woodpecker-ci/woodpecker/cmd/server +frontend-dependencies: + (cd web/; yarn install --frozen-lockfile) + test-agent: $(DOCKER_RUN) go test -race -timeout 30s github.com/woodpecker-ci/woodpecker/cmd/agent $(GO_PACKAGES) test-server: $(DOCKER_RUN) go test -race -timeout 30s github.com/woodpecker-ci/woodpecker/cmd/server -test-frontend: - (cd web/; yarn; yarn run test) +test-frontend: frontend-dependencies + (cd web/; yarn run lint) + (cd web/; yarn run formatcheck) + (cd web/; yarn run typecheck) + (cd web/; yarn run test) test-lib: $(DOCKER_RUN) go test -race -timeout 30s $(shell go list ./... | grep -v '/cmd/') diff --git a/server/api/hook.go b/server/api/hook.go index c633001489..f380ac12dd 100644 --- a/server/api/hook.go +++ b/server/api/hook.go @@ -276,7 +276,7 @@ func PostHook(c *gin.Context) { defer func() { for _, item := range buildItems { - uri := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, build.Number) + uri := fmt.Sprintf("%s/%s/build/%d", server.Config.Server.Host, repo.FullName, build.Number) if len(buildItems) > 1 { err = remote_.Status(c, user, repo, build, uri, item.Proc) } else { diff --git a/server/router/router.go b/server/router/router.go index 2fa0a1c9f8..98c76614ed 100644 --- a/server/router/router.go +++ b/server/router/router.go @@ -30,7 +30,6 @@ import ( // Load loads the router func Load(serveHTTP func(w http.ResponseWriter, r *http.Request), middleware ...gin.HandlerFunc) http.Handler { - e := gin.New() e.Use(gin.Recovery()) diff --git a/server/web/web.go b/server/web/web.go index b47858874e..189f6d46da 100644 --- a/server/web/web.go +++ b/server/web/web.go @@ -62,7 +62,7 @@ func (w *website) Register(mux *gin.Engine) { h := http.FileServer(w.fs) h = setupCache(h) mux.GET("/favicon.svg", gin.WrapH(h)) - mux.GET("/static/*filepath", gin.WrapH(h)) + mux.GET("/assets/*filepath", gin.WrapH(h)) mux.NoRoute(gin.WrapF(w.handleIndex)) } diff --git a/web/.babelrc b/web/.babelrc deleted file mode 100644 index fd95ce5a90..0000000000 --- a/web/.babelrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "sourceMaps": false, - "presets": [ - ["es2015", { "loose":true }], - "stage-0", - "react" - ], - "plugins": [ - ["transform-decorators-legacy"], - ["transform-object-rest-spread"], - ["transform-react-jsx"], - ["transform-es3-property-literals"], - ["transform-es3-member-expression-literals"], - ["transform-decorators-legacy"] - ] -} diff --git a/web/.eslintignore b/web/.eslintignore new file mode 100644 index 0000000000..67bb21d0a2 --- /dev/null +++ b/web/.eslintignore @@ -0,0 +1,6 @@ +# don't lint build output (make sure it's set to your correct build folder name) +dist +coverage/ +package.json +tsconfig.eslint.json +tsconfig.json diff --git a/web/.eslintrc.js b/web/.eslintrc.js index 235507f919..e839e23e64 100644 --- a/web/.eslintrc.js +++ b/web/.eslintrc.js @@ -1,33 +1,136 @@ +// @ts-check +/** @type {import('@typescript-eslint/experimental-utils').TSESLint.Linter.Config} */ + +/* eslint-env node */ module.exports = { - extends: [ - "standard", - "plugin:jest/recommended", - "plugin:react/recommended", - "prettier", - "prettier/react" - ], - plugins: ["react", "jest", "prettier"], - parser: "babel-eslint", - parserOptions: { - ecmaVersion: 2016, - sourceType: "module", - ecmaFeatures: { - jsx: true - } - }, env: { - es6: true, browser: true, - node: true, - "jest/globals": true }, + + parser: 'vue-eslint-parser', + parserOptions: { + project: ['./tsconfig.eslint.json'], + tsconfigRootDir: __dirname, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore see https://github.com/vuejs/vue-eslint-parser#parseroptionsparser + parser: '@typescript-eslint/parser', + sourceType: 'module', + extraFileExtensions: ['.vue'], + }, + + plugins: ['@typescript-eslint', 'import', 'simple-import-sort'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'airbnb-base-ts', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:import/typescript', + 'plugin:promise/recommended', + 'plugin:vue/vue3-recommended', + 'plugin:prettier/recommended', + 'plugin:vue-scoped-css/recommended', + ], + rules: { - "react/prop-types": 1, - "prettier/prettier": [ - "error", + // enable scope analysis rules + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + 'no-use-before-define': 'off', + '@typescript-eslint/no-use-before-define': 'error', + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': 'error', + 'no-redeclare': 'off', + '@typescript-eslint/no-redeclare': 'error', + + // make typescript eslint rules even more strict + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'error', + + 'import/no-unresolved': 'off', // disable as this is handled by tsc itself + 'import/first': 'error', + 'import/newline-after-import': 'error', + 'import/no-cycle': 'error', + 'import/no-relative-parent-imports': 'error', + 'import/no-duplicates': 'error', + 'import/no-extraneous-dependencies': 'error', + 'import/extensions': 'off', + 'import/prefer-default-export': 'off', + + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + + 'promise/prefer-await-to-then': 'error', + 'promise/prefer-await-to-callbacks': 'error', + + 'no-underscore-dangle': 'off', + 'no-else-return': ['error', { allowElseIf: false }], + 'no-return-assign': ['error', 'always'], + 'no-return-await': 'error', + 'no-useless-return': 'error', + 'no-restricted-imports': [ + 'error', + { + patterns: ['src', 'dist'], + }, + ], + 'no-console': 'warn', + 'no-useless-concat': 'error', + 'prefer-const': 'error', + 'spaced-comment': ['error', 'always'], + 'object-shorthand': ['error', 'always'], + 'no-useless-rename': 'error', + eqeqeq: 'error', + + 'vue/attribute-hyphenation': 'error', + // enable in accordance with https://github.com/prettier/eslint-config-prettier#vuehtml-self-closing + 'vue/html-self-closing': [ + 'error', { - trailingComma: "all", - } - ] - } + html: { + void: 'any', + }, + }, + ], + 'vue/no-static-inline-styles': 'error', + 'vue/v-on-function-call': 'error', + 'vue/no-useless-v-bind': 'error', + 'vue/no-useless-mustaches': 'error', + 'vue/no-useless-concat': 'error', + 'vue/no-boolean-default': 'error', + 'vue/html-button-has-type': 'error', + 'vue/component-name-in-template-casing': 'error', + 'vue/match-component-file-name': [ + 'error', + { + extensions: ['vue'], + shouldMatchCase: true, + }, + ], + 'vue/require-name-property': 'error', + 'vue/v-for-delimiter-style': 'error', + 'vue/no-empty-component-block': 'error', + 'vue/no-duplicate-attr-inheritance': 'error', + 'vue/no-unused-properties': [ + 'error', + { + groups: ['props', 'data', 'computed', 'methods', 'setup'], + }, + ], + 'vue/new-line-between-multi-line-property': 'error', + 'vue/padding-line-between-blocks': 'error', + + // css rules + 'vue-scoped-css/no-unused-selector': 'error', + 'vue-scoped-css/no-parsing-error': 'error', + 'vue-scoped-css/require-scoped': 'error', + + // enable in accordance with https://github.com/prettier/eslint-config-prettier#curly + curly: ['error', 'all'], + + // risky because of https://github.com/prettier/eslint-plugin-prettier#arrow-body-style-and-prefer-arrow-callback-issue + 'arrow-body-style': 'error', + 'prefer-arrow-callback': 'error', + }, }; diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000000..d451ff16c1 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,5 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local diff --git a/web/.lesshintrc b/web/.lesshintrc deleted file mode 100644 index 9ad09a8ef9..0000000000 --- a/web/.lesshintrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "fileExtensions": [".less", ".css"], - - "excludedFiles": ["ansi.less"], - - "spaceAfterPropertyColon": { - "enabled": true, - "style": "one_space" - }, - - "emptyRule": true, - "qualifyingElement": false, - "trailingWhitespace": true, - "zeroUnit": { - "exclude": ["flex"] - } -} diff --git a/web/.prettierignore b/web/.prettierignore new file mode 100644 index 0000000000..73eb113494 --- /dev/null +++ b/web/.prettierignore @@ -0,0 +1,4 @@ +yarn-lock.yaml +dist +coverage/ +LICENSE diff --git a/web/.prettierrc.js b/web/.prettierrc.js new file mode 100644 index 0000000000..b651096fd4 --- /dev/null +++ b/web/.prettierrc.js @@ -0,0 +1,8 @@ +module.exports = { + semi: true, + trailingComma: 'all', + singleQuote: true, + printWidth: 120, + tabWidth: 2, + endOfLine: 'lf', +}; diff --git a/web/README.md b/web/README.md deleted file mode 100644 index 64b4d1a0fc..0000000000 --- a/web/README.md +++ /dev/null @@ -1,57 +0,0 @@ -This project contains the source code for the drone user interface. The generated javascript and css assets are embedded into a Go source file which is imported into the main drone application, using go get. - -## Building - -To compile the source and create minified css and javascript assets: - -```text -yarn install # install project dependencies - -yarn run format # formats the codebase -yarn run lint # lints the codebase -yarn run test # tests the codebase -yarn run build # builds the production bundle -``` - -## Running - -To run a devserver with watching, hotreloading and proxy to drone server: - -```text -export DRONE_SERVER= -export DRONE_TOKEN= - -yarn run start -``` - -For example: - -```text -export DRONE_SERVER=http://your.drone.server -export DRONE_TOKEN=eyJhbGciOiJIUzI1NiIsIn... - -yarn run start -``` - -Note you will need to retrieve your drone user token from the tokens screen in the drone user interface. When the server is running you can open the following url in your browser: - -```text -http://localhost:9999 -``` - -## Releases - -To bundle and embed the code in a Go source file install the following command line utility: - -```text -go get github.com/bradrydzewski/togo -``` - -To generate the Go source file run the following command: - -```text -go generate ./... -go install ./... -``` - -__Note__ that for security reasons we will not accept a pull request that updates embedded Go asset file since we are not able to easily review the embedded, minified code. This file is instead automatically generated by our build server to prevent tampering. diff --git a/web/dist/.gitkeep b/web/dist/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000000..263a92f7ae --- /dev/null +++ b/web/index.html @@ -0,0 +1,14 @@ + + + + + + + Woodpecker + + + +
+ + + diff --git a/web/package.json b/web/package.json index 708c56cf5c..c7a304c2a4 100644 --- a/web/package.json +++ b/web/package.json @@ -1,107 +1,59 @@ { - "name": "drone-ui-react", - "version": "1.0.0", - "main": "index.js", - "scripts": { - "prebuild": "rm -rf dist/files", - "build": "cross-env NODE_ENV=production webpack", - "lint": "eslint src/", - "lesshint": "lesshint --config .lesshintrc src/", - "test": "jest", - "start": "webpack-dev-server --progress --hot --inline", - "format": "prettier --trailing-comma all --write {src/*.js,src/**/*.js,src/**/*/*.js,src/*/*/*/*.js,src/*/*/*/*/*.js,src/*/*/*/*/*/*.js,src/*/*/*/*/*/*.js,src/*/*/*/*/*/*/*.js}" + "name": "woodpecker-ci", + "author": "Woodpecker CI", + "version": "0.0.0", + "license": "Apache-2.0", + "engines": { + "node": ">=14" }, - "jest": { - "moduleFileExtensions": [ - "js", - "jsx" - ], - "moduleDirectories": [ - "src", - "node_modules" - ], - "moduleNameMapper": { - "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", - "\\.(css|less)$": "identity-obj-proxy", - "^react$": "preact-compat-enzyme", - "^react-dom/server$": "preact-render-to-string", - "^react-dom$": "preact-compat-enzyme", - "^react-addons-test-utils$": "preact-test-utils" - }, - "collectCoverageFrom": [ - "src/**/*.{js,jsx}" - ] + "scripts": { + "start": "vite", + "build": "vite build", + "serve": "vite preview", + "lint": "eslint --max-warnings 0 --ext .js,.ts,.vue,.json .", + "formatcheck": "prettier -c .", + "format:fix": "prettier --write .", + "typecheck": "vue-tsc --noEmit", + "test": "echo 'No tests configured' && exit 0" }, - "author": "Brad Rydzewski", - "license": "Apache-2.0", "dependencies": { - "ansi_up": "^2.0.2", - "babel-polyfill": "^6.23.0", - "baobab": "^2.4.3", - "baobab-react": "^2.1.2", - "classnames": "^2.2.5", - "drone-js": "file:./vendor/drone-js/", - "humanize-duration": "^3.10.1", - "preact": "^8.2.1", - "preact-compat": "^3.16.0", - "query-string": "^5.0.0", - "react-collapsible": "^2.6.0", - "react-router": "^4.1.2", - "react-router-dom": "^4.1.2", - "react-screen-size": "^1.0.1", - "react-timeago": "^3.4.3", - "react-title-component": "^1.0.1", - "react-transition-group": "^1.2.0", - "yarn": "^1.17.3" + "@kyvg/vue3-notification": "2.3.4", + "@meforma/vue-toaster": "1.2.2", + "ansi-to-html": "0.7.2", + "fuse.js": "6.4.6", + "humanize-duration": "3.27.0", + "javascript-time-ago": "2.3.10", + "node-emoji": "1.11.0", + "pinia": "2.0.0", + "vue": "v3.2.20", + "vue-router": "4.0.10" }, "devDependencies": { - "babel-core": "^6.25.0", - "babel-eslint": "^7.2.3", - "babel-jest": "^21.0.0", - "babel-loader": "^7.1.1", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-es3-member-expression-literals": "^6.22.0", - "babel-plugin-transform-es3-property-literals": "^6.22.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-preset-env": "^1.6.0", - "babel-preset-es2015": "^6.24.1", - "babel-preset-react": "^6.24.1", - "babel-preset-stage-0": "^6.24.1", - "cross-env": "^5.0.3", - "css-loader": "^0.28.4", - "dotenv": "^4.0.0", - "enzyme": "^2.9.1", - "eslint": "^4.6.1", - "eslint-config-prettier": "^2.4.0", - "eslint-config-standard": "^10.2.1", - "eslint-plugin-import": "^2.7.0", - "eslint-plugin-jest": "^21.0.2", - "eslint-plugin-node": "^5.1.1", - "eslint-plugin-prettier": "^2.2.0", - "eslint-plugin-promise": "^3.5.0", - "eslint-plugin-react": "^7.3.0", - "eslint-plugin-standard": "^3.0.1", - "file-loader": "^0.11.2", - "html-webpack-plugin": "^2.30.1", - "identity-obj-proxy": "^3.0.0", - "jasmine-expect": "^3.7.1", - "jest": "^21.0.1", - "jsdoc": "^3.5.4", - "less": "^2.7.2", - "less-loader": "^4.0.5", - "lesshint": "^4.1.3", - "preact-compat-enzyme": "^0.2.5", - "preact-render-to-string": "^3.6.3", - "preact-test-utils": "^0.1.3", - "prettier": "^1.6.0", - "sinon": "^3.2.1", - "sinon-chai": "^2.13.0", - "style-loader": "^0.18.2", - "url-loader": "^0.5.9", - "webpack": "^3.4.1", - "webpack-dev-server": "^2.6.1" - }, - "resolutions": { - "ua-parser-js": "^0.7.30" + "@iconify/json": "1.1.421", + "@types/humanize-duration": "3.27.0", + "@types/javascript-time-ago": "2.0.3", + "@types/node": "16.11.6", + "@types/node-emoji": "1.8.1", + "@typescript-eslint/eslint-plugin": "4.31.2", + "@typescript-eslint/parser": "4.31.1", + "@vitejs/plugin-vue": "1.9.4", + "@vue/compiler-sfc": "3.2.20", + "eslint": "7.32.0", + "eslint-config-airbnb-base-ts": "14.1.2", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "4.0.0", + "eslint-plugin-promise": "5.1.1", + "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-vue": "7.18.0", + "eslint-plugin-vue-scoped-css": "1.3.0", + "prettier": "2.4.1", + "typescript": "4.4.4", + "unplugin-icons": "0.12.17", + "unplugin-vue-components": "0.17.0", + "vite": "2.6.13", + "vite-plugin-windicss": "1.4.12", + "vite-svg-loader": "3.0.0", + "vue-tsc": "0.28.10", + "windicss": "3.2.0" } } diff --git a/web/src/public/favicon.svg b/web/public/favicon.svg similarity index 100% rename from web/src/public/favicon.svg rename to web/public/favicon.svg diff --git a/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000000..d1b49080dc --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,115 @@ + + + + + + + + diff --git a/web/src/assets/logo.svg b/web/src/assets/logo.svg new file mode 100644 index 0000000000..b9c8b6c6cd --- /dev/null +++ b/web/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/woodpecker.svg b/web/src/assets/woodpecker.svg new file mode 100644 index 0000000000..e08d0a2f2a --- /dev/null +++ b/web/src/assets/woodpecker.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/src/components/atomic/Button.vue b/web/src/components/atomic/Button.vue new file mode 100644 index 0000000000..88ed6ef9c9 --- /dev/null +++ b/web/src/components/atomic/Button.vue @@ -0,0 +1,134 @@ + + + diff --git a/web/src/components/atomic/DocsLink.vue b/web/src/components/atomic/DocsLink.vue new file mode 100644 index 0000000000..f0b42394ce --- /dev/null +++ b/web/src/components/atomic/DocsLink.vue @@ -0,0 +1,32 @@ + + + diff --git a/web/src/components/atomic/Icon.vue b/web/src/components/atomic/Icon.vue new file mode 100644 index 0000000000..121f08d213 --- /dev/null +++ b/web/src/components/atomic/Icon.vue @@ -0,0 +1,83 @@ + + + diff --git a/web/src/components/atomic/IconButton.vue b/web/src/components/atomic/IconButton.vue new file mode 100644 index 0000000000..f704555d53 --- /dev/null +++ b/web/src/components/atomic/IconButton.vue @@ -0,0 +1,60 @@ + + + diff --git a/web/src/components/atomic/ListItem.vue b/web/src/components/atomic/ListItem.vue new file mode 100644 index 0000000000..b866bb39d0 --- /dev/null +++ b/web/src/components/atomic/ListItem.vue @@ -0,0 +1,32 @@ + + + diff --git a/web/src/components/build-feed/BuildFeedItem.vue b/web/src/components/build-feed/BuildFeedItem.vue new file mode 100644 index 0000000000..1e7978b72f --- /dev/null +++ b/web/src/components/build-feed/BuildFeedItem.vue @@ -0,0 +1,48 @@ + + + diff --git a/web/src/components/build-feed/BuildFeedSidebar.vue b/web/src/components/build-feed/BuildFeedSidebar.vue new file mode 100644 index 0000000000..38957f14c8 --- /dev/null +++ b/web/src/components/build-feed/BuildFeedSidebar.vue @@ -0,0 +1,48 @@ + + + diff --git a/web/src/components/form/Checkbox.vue b/web/src/components/form/Checkbox.vue new file mode 100644 index 0000000000..063b37aaab --- /dev/null +++ b/web/src/components/form/Checkbox.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/web/src/components/form/CheckboxesField.vue b/web/src/components/form/CheckboxesField.vue new file mode 100644 index 0000000000..8027110753 --- /dev/null +++ b/web/src/components/form/CheckboxesField.vue @@ -0,0 +1,65 @@ + + + diff --git a/web/src/components/form/InputField.vue b/web/src/components/form/InputField.vue new file mode 100644 index 0000000000..4edcbec7d3 --- /dev/null +++ b/web/src/components/form/InputField.vue @@ -0,0 +1,38 @@ + + + diff --git a/web/src/components/form/NumberField.vue b/web/src/components/form/NumberField.vue new file mode 100644 index 0000000000..0de88d29be --- /dev/null +++ b/web/src/components/form/NumberField.vue @@ -0,0 +1,48 @@ + + + diff --git a/web/src/components/form/RadioField.vue b/web/src/components/form/RadioField.vue new file mode 100644 index 0000000000..54f1b22337 --- /dev/null +++ b/web/src/components/form/RadioField.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/web/src/components/form/SelectField.vue b/web/src/components/form/SelectField.vue new file mode 100644 index 0000000000..5b1d4558e1 --- /dev/null +++ b/web/src/components/form/SelectField.vue @@ -0,0 +1,63 @@ + + + diff --git a/web/src/components/form/TextField.vue b/web/src/components/form/TextField.vue new file mode 100644 index 0000000000..0911f204a3 --- /dev/null +++ b/web/src/components/form/TextField.vue @@ -0,0 +1,74 @@ + + + diff --git a/web/src/components/form/form.types.ts b/web/src/components/form/form.types.ts new file mode 100644 index 0000000000..d069aeab5b --- /dev/null +++ b/web/src/components/form/form.types.ts @@ -0,0 +1,9 @@ +export type SelectOption = { + value: string; + text: string; + description?: string; +}; + +export type RadioOption = SelectOption; + +export type CheckboxOption = SelectOption; diff --git a/web/src/components/layout/FluidContainer.vue b/web/src/components/layout/FluidContainer.vue new file mode 100644 index 0000000000..bcc143b0e4 --- /dev/null +++ b/web/src/components/layout/FluidContainer.vue @@ -0,0 +1,13 @@ + + + diff --git a/web/src/components/layout/Panel.vue b/web/src/components/layout/Panel.vue new file mode 100644 index 0000000000..9cc1ac9f71 --- /dev/null +++ b/web/src/components/layout/Panel.vue @@ -0,0 +1,17 @@ + + + diff --git a/web/src/components/layout/header/ActiveBuilds.vue b/web/src/components/layout/header/ActiveBuilds.vue new file mode 100644 index 0000000000..567ce63e55 --- /dev/null +++ b/web/src/components/layout/header/ActiveBuilds.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/web/src/components/layout/header/Navbar.vue b/web/src/components/layout/header/Navbar.vue new file mode 100644 index 0000000000..7e822a4573 --- /dev/null +++ b/web/src/components/layout/header/Navbar.vue @@ -0,0 +1,69 @@ + + + diff --git a/web/src/components/repo/build/BuildItem.vue b/web/src/components/repo/build/BuildItem.vue new file mode 100644 index 0000000000..5bb904c36e --- /dev/null +++ b/web/src/components/repo/build/BuildItem.vue @@ -0,0 +1,86 @@ + + + diff --git a/web/src/components/repo/build/BuildList.vue b/web/src/components/repo/build/BuildList.vue new file mode 100644 index 0000000000..82b8177447 --- /dev/null +++ b/web/src/components/repo/build/BuildList.vue @@ -0,0 +1,41 @@ + + + diff --git a/web/src/components/repo/build/BuildLogs.vue b/web/src/components/repo/build/BuildLogs.vue new file mode 100644 index 0000000000..7433b2b63a --- /dev/null +++ b/web/src/components/repo/build/BuildLogs.vue @@ -0,0 +1,86 @@ +