diff --git a/.drone.yml b/.drone.yml index 8599f574b..72f4874ce 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,3 +1,4 @@ +--- kind: pipeline name: build @@ -12,29 +13,30 @@ trigger: services: - name: api - image: vikunja/api + image: vikunja/api:unstable environment: VIKUNJA_SERVICE_TESTINGTOKEN: averyLongSecretToSe33dtheDB VIKUNJA_LOG_LEVEL: DEBUG steps: - - name: restore-cache - image: meltwater/drone-cache:dev - pull: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: cache_aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: cache_aws_secret_access_key - settings: - restore: true - bucket: kolaente.dev-drone-dependency-cache - endpoint: https://s3.fr-par.scw.cloud - region: fr-par - path_style: true - cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' - mount: - - '.cache' +# Disabled until we figure out why it is so slow +# - name: restore-cache +# image: meltwater/drone-cache:dev +# pull: true +# environment: +# AWS_ACCESS_KEY_ID: +# from_secret: cache_aws_access_key_id +# AWS_SECRET_ACCESS_KEY: +# from_secret: cache_aws_secret_access_key +# settings: +# restore: true +# bucket: kolaente.dev-drone-dependency-cache +# endpoint: https://s3.fr-par.scw.cloud +# region: fr-par +# path_style: true +# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' +# mount: +# - '.cache' - name: dependencies image: node:16 @@ -44,28 +46,28 @@ steps: CYPRESS_CACHE_FOLDER: .cache/cypress/ commands: - yarn --frozen-lockfile --network-timeout 100000 - depends_on: - - restore-cache +# depends_on: +# - restore-cache - - name: rebuild-cache - image: meltwater/drone-cache:dev - pull: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: cache_aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: cache_aws_secret_access_key - settings: - rebuild: true - bucket: kolaente.dev-drone-dependency-cache - endpoint: https://s3.fr-par.scw.cloud - region: fr-par - path_style: true - cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' - mount: - - '.cache' - depends_on: - - dependencies +# - name: rebuild-cache +# image: meltwater/drone-cache:dev +# pull: true +# environment: +# AWS_ACCESS_KEY_ID: +# from_secret: cache_aws_access_key_id +# AWS_SECRET_ACCESS_KEY: +# from_secret: cache_aws_secret_access_key +# settings: +# rebuild: true +# bucket: kolaente.dev-drone-dependency-cache +# endpoint: https://s3.fr-par.scw.cloud +# region: fr-par +# path_style: true +# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' +# mount: +# - '.cache' +# depends_on: +# - dependencies - name: lint image: node:16 @@ -78,25 +80,13 @@ steps: depends_on: - dependencies - # Building in dev mode to avoid the service worker for testing - - name: build-dev - image: node:16 - pull: true - environment: - YARN_CACHE_FOLDER: .cache/yarn/ - CYPRESS_CACHE_FOLDER: .cache/cypress/ - commands: - - yarn build:dev - depends_on: - - dependencies - - name: build-prod image: node:16 pull: true environment: YARN_CACHE_FOLDER: .cache/yarn/ commands: - - yarn build --dest dist-prod + - yarn build depends_on: - dependencies @@ -118,15 +108,15 @@ steps: CYPRESS_CACHE_FOLDER: .cache/cypress/ CYPRESS_DEFAULT_COMMAND_TIMEOUT: 60000 commands: - - sed -i 's/localhost/api/g' dist-dev/index.html - - yarn serve:dist-dev & npx wait-on http://localhost:5000 + - sed -i 's/localhost/api/g' dist/index.html + - yarn serve:dist & npx wait-on http://localhost:5000 - yarn test:frontend --browser chrome depends_on: - dependencies - - build-dev + - build-prod - name: upload-test-results - image: plugins/s3:1 + image: plugins/s3 pull: true settings: bucket: drone-test-results @@ -147,6 +137,26 @@ steps: - failure - success + - name: deploy-preview + image: node:16 + pull: true + environment: + NETLIFY_AUTH_TOKEN: + from_secret: netlify_auth_token + NETLIFY_SITE_ID: + from_secret: netlify_site_id + GITEA_TOKEN: + from_secret: gitea_token + commands: + - shasum -a 384 -c ./scripts/deploy-preview-netlify.js.sha384 + - node ./scripts/deploy-preview-netlify.js + depends_on: + - build-prod + when: + event: + include: + - pull_request + --- kind: pipeline name: release-latest @@ -166,23 +176,23 @@ steps: commands: - git fetch --tags - - name: restore-cache - image: meltwater/drone-cache:dev - pull: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: cache_aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: cache_aws_secret_access_key - settings: - restore: true - bucket: kolaente.dev-drone-dependency-cache - endpoint: https://s3.fr-par.scw.cloud - region: fr-par - path_style: true - cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' - mount: - - '.cache' +# - name: restore-cache +# image: meltwater/drone-cache:dev +# pull: true +# environment: +# AWS_ACCESS_KEY_ID: +# from_secret: cache_aws_access_key_id +# AWS_SECRET_ACCESS_KEY: +# from_secret: cache_aws_secret_access_key +# settings: +# restore: true +# bucket: kolaente.dev-drone-dependency-cache +# endpoint: https://s3.fr-par.scw.cloud +# region: fr-par +# path_style: true +# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' +# mount: +# - '.cache' - name: build image: node:16 @@ -192,12 +202,13 @@ steps: YARN_CACHE_FOLDER: .cache/yarn/ commands: - yarn --frozen-lockfile --network-timeout 100000 + - npx browserslist@latest --update-db - yarn run lint - "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json" - yarn run build - sed -i 's/http\:\\/\\/localhost\\:3456\\/api\\/v1/\\/api\\/v1/g' dist/index.html # Override the default api url used for developing - depends_on: - - restore-cache +# depends_on: +# - restore-cache - name: static image: kolaente/zip @@ -209,7 +220,7 @@ steps: depends_on: [ build ] - name: release - image: plugins/s3:1 + image: plugins/s3 pull: true settings: bucket: vikunja-releases @@ -241,23 +252,23 @@ steps: commands: - git fetch --tags - - name: restore-cache - image: meltwater/drone-cache:dev - pull: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: cache_aws_access_key_id - AWS_SECRET_ACCESS_KEY: - from_secret: cache_aws_secret_access_key - settings: - restore: true - bucket: kolaente.dev-drone-dependency-cache - endpoint: https://s3.fr-par.scw.cloud - region: fr-par - path_style: true - cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' - mount: - - '.cache' +# - name: restore-cache +# image: meltwater/drone-cache:dev +# pull: true +# environment: +# AWS_ACCESS_KEY_ID: +# from_secret: cache_aws_access_key_id +# AWS_SECRET_ACCESS_KEY: +# from_secret: cache_aws_secret_access_key +# settings: +# restore: true +# bucket: kolaente.dev-drone-dependency-cache +# endpoint: https://s3.fr-par.scw.cloud +# region: fr-par +# path_style: true +# cache_key: '{{ .Repo.Name }}_{{ checksum "yarn.lock" }}_{{ arch }}_{{ os }}' +# mount: +# - '.cache' - name: build image: node:16 @@ -271,8 +282,8 @@ steps: - "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json" - yarn run build - sed -i 's/http\:\\/\\/localhost\\:3456\\/api\\/v1/\\/api\\/v1/g' dist/index.html # Override the default api url used for developing - depends_on: - - restore-cache +# depends_on: +# - restore-cache - name: static image: kolaente/zip @@ -284,7 +295,7 @@ steps: depends_on: [ build ] - name: release - image: plugins/s3:1 + image: plugins/s3 pull: true settings: bucket: vikunja-releases @@ -339,6 +350,9 @@ trigger: ref: - refs/heads/main - "refs/tags/**" + event: + exclude: + - cron steps: - name: docker-unstable @@ -436,6 +450,9 @@ trigger: ref: - refs/heads/main - "refs/tags/**" + event: + exclude: + - cron steps: - name: docker-unstable @@ -482,6 +499,9 @@ trigger: ref: - refs/heads/main - "refs/tags/**" + event: + exclude: + - cron depends_on: - docker-amd64-release @@ -543,6 +563,9 @@ trigger: ref: - refs/heads/main - "refs/tags/**" + event: + exclude: + - cron depends_on: - build @@ -579,7 +602,9 @@ trigger: branch: - main event: - - push + - cron + cron: + - update_translations steps: - name: download @@ -630,3 +655,8 @@ steps: environment: CROWDIN_KEY: from_secret: crowdin_key +--- +kind: signature +hmac: 188ee90100c5fc5922a445e531e7a47453121edddb2a64a182eb23ed2bf602de + +... diff --git a/.editorconfig b/.editorconfig index 95bef4270..2c1d3b49f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,4 +19,11 @@ indent_size = 2 [*.json] indent_style = space -indent_size = 2 \ No newline at end of file +indent_size = 2 + +[*.{scss,css}] +indent_style = space +indent_size = 2 + +[.nvmrc] +insert_final_newline = false \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3ae9059a6..9ccc7d36b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ stats.html # Test files cypress/screenshots cypress/videos + +# Local Netlify folder +.netlify diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..5edcff036 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v16 \ No newline at end of file diff --git a/.vscode.example/extensions.json b/.vscode.example/extensions.json new file mode 100644 index 000000000..6b2cee9f7 --- /dev/null +++ b/.vscode.example/extensions.json @@ -0,0 +1,12 @@ +{ + "recommendations": [ + "codezombiech.gitignore", + "dbaeumer.vscode-eslint", + "editorconfig.editorconfig", + "johnsoncodehk.volar", + "lokalise.i18n-ally", + "mgmcdermott.vscode-language-babel", + "mikestead.dotenv", + "Syler.sass-indented" + ] +} \ No newline at end of file diff --git a/.vscode.example/settings.json b/.vscode.example/settings.json new file mode 100644 index 000000000..110c8221a --- /dev/null +++ b/.vscode.example/settings.json @@ -0,0 +1,30 @@ +{ + "eslint.packageManager": "yarn", + "editor.formatOnSave": false, + "editor.codeActionsOnSave": { + "source.fixAll": true + }, + "eslint.format.enable": true, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + + // https://eslint.vuejs.org/user-guide/#editor-integrations + "eslint.validate": [ + "javascript", + "javascriptreact", + "vue" + ], + "vetur.validation.template": false, + + // i18n ally + "i18n-ally.localesPaths": [ + "src/i18n/lang" + ], + "i18n-ally.sortKeys": true, + "i18n-ally.keepFulfilled": true, + "i18n-ally.keystyle": "nested", +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d73a4fe80..159930f6a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,12 +24,6 @@ RUN \ # Stage 2: copy FROM nginx -RUN apt-get update && apt-get install -y apt-utils openssl && \ - mkdir -p /etc/nginx/ssl && \ - openssl genrsa -out /etc/nginx/ssl/dummy.key 2048 && \ - openssl req -new -key /etc/nginx/ssl/dummy.key -out /etc/nginx/ssl/dummy.csr -subj "/C=DE/L=Berlin/O=Vikunja/CN=Vikunja Snakeoil" && \ - openssl x509 -req -days 3650 -in /etc/nginx/ssl/dummy.csr -signkey /etc/nginx/ssl/dummy.key -out /etc/nginx/ssl/dummy.crt - COPY nginx.conf /etc/nginx/nginx.conf COPY run.sh /run.sh diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index d39e57b42..000000000 --- a/babel.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - presets: [ - '@vue/app', - ], -} diff --git a/cypress.json b/cypress.json index 404249f38..27f12495c 100644 --- a/cypress.json +++ b/cypress.json @@ -2,7 +2,7 @@ "baseUrl": "http://localhost:5000", "env": { "API_URL": "http://localhost:3456/api/v1", - "TEST_SECRET": "testingS3cr3et" + "TEST_SECRET": "averyLongSecretToSe33dtheDB" }, "video": false, "retries": { diff --git a/cypress/README.md b/cypress/README.md index 97c6469f1..6dd21922e 100644 --- a/cypress/README.md +++ b/cypress/README.md @@ -9,8 +9,8 @@ ## Fixtures -We're using the [test endpoint](https://vikunja.io/docs/config-options/#testingtoken) of the vikunja api to -seed the database with test data before running the tests. +We're using the [test endpoint](https://vikunja.io/docs/config-options/#testingtoken) of the vikunja api to +seed the database with test data before running the tests. This ensures better reproducability of tests. ## Running The Tests Locally @@ -22,20 +22,20 @@ It uses the same configuration as the CI. To use it, run -``` +```shell docker-compose up -d ``` Then, once all containers are started, run -``` -docker-composer run cypress bash +```shell +docker-compose run cypress bash ``` to get a shell inside the cypress container. In that shell you can then execute the tests with -``` +```shell yarn test:frontend ``` @@ -43,6 +43,6 @@ yarn test:frontend To open the Cypress Dashboard and run tests from there, run -``` +```shell yarn cypress:open ``` diff --git a/cypress/docker-compose.yml b/cypress/docker-compose.yml index 1c496de49..98a24edd3 100644 --- a/cypress/docker-compose.yml +++ b/cypress/docker-compose.yml @@ -2,10 +2,12 @@ version: '3' services: api: - image: vikunja/api + image: vikunja/api:unstable environment: VIKUNJA_LOG_LEVEL: DEBUG VIKUNJA_SERVICE_TESTINGTOKEN: averyLongSecretToSe33dtheDB + ports: + - 3456:3456 cypress: image: cypress/browsers:node12.18.3-chrome87-ff82 volumes: diff --git a/cypress/factories/user.js b/cypress/factories/user.js index 37fcaaab4..9e133b552 100644 --- a/cypress/factories/user.js +++ b/cypress/factories/user.js @@ -11,7 +11,7 @@ export class UserFactory extends Factory { return { id: '{increment}', - username: faker.lorem.word(10) + faker.random.uuid(), + username: faker.lorem.word(10) + faker.datatype.uuid(), password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.', // 1234 status: 0, created: formatISO(now), diff --git a/cypress/integration/list/list.spec.js b/cypress/integration/list/list.spec.js index 8242984e6..864b533b3 100644 --- a/cypress/integration/list/list.spec.js +++ b/cypress/integration/list/list.spec.js @@ -38,8 +38,7 @@ describe('Lists', () => { .contains('Create') .click() - cy.wait(1000) // Waiting until the request to create the new list is done - cy.get('.global-notification') + cy.get('.global-notification', { timeout: 1000 }) // Waiting until the request to create the new list is done .should('contain', 'Success') cy.url() .should('contain', '/lists/') @@ -220,10 +219,10 @@ describe('Lists', () => { cy.get('.table-view .filter-container .items .button') .contains('Columns') .click() - cy.get('.table-view .filter-container .card .card-content .fancycheckbox .check') + cy.get('.table-view .filter-container .card.columns-filter .card-content .fancycheckbox .check') .contains('Priority') .click() - cy.get('.table-view .filter-container .card .card-content .fancycheckbox .check') + cy.get('.table-view .filter-container .card.columns-filter .card-content .fancycheckbox .check') .contains('Done') .click() @@ -446,7 +445,7 @@ describe('Lists', () => { cy.get('.kanban .bucket .tasks .task') .contains(tasks[0].title) .first() - .drag('.kanban .bucket:nth-child(2) .tasks .dropper div') + .drag('.kanban .bucket:nth-child(2) .tasks .dropper') cy.get('.kanban .bucket:nth-child(2) .tasks') .should('contain', tasks[0].title) @@ -501,7 +500,7 @@ describe('Lists', () => { .first() .click() - cy.get('.global-notification') + cy.get('.global-notification', { timeout: 1000 }) .should('contain', 'Success') cy.go('back') cy.get('.kanban .bucket') diff --git a/cypress/integration/list/namespaces.spec.js b/cypress/integration/list/namespaces.spec.js index e8c15443e..7d092113a 100644 --- a/cypress/integration/list/namespaces.spec.js +++ b/cypress/integration/list/namespaces.spec.js @@ -67,7 +67,7 @@ describe('Namepaces', () => { .contains('Save') .click() - cy.get('.global-notification') + cy.get('.global-notification', { timeout: 1000 }) .should('contain', 'Success') cy.get('.namespace-container .menu.namespaces-lists') .should('contain', newNamespaceName) diff --git a/cypress/integration/misc/menu.spec.js b/cypress/integration/misc/menu.spec.js index 98e228f2f..86e3ab57f 100644 --- a/cypress/integration/misc/menu.spec.js +++ b/cypress/integration/misc/menu.spec.js @@ -7,7 +7,7 @@ describe('The Menu', () => { }) it('Can be hidden on desktop', () => { - cy.get('a.menu-show-button:visible') + cy.get('button.menu-show-button:visible') .click() cy.get('.namespace-container') .should('not.have.class', 'is-active') @@ -21,7 +21,7 @@ describe('The Menu', () => { it('Is can be shown on mobile', () => { cy.viewport('iphone-8') - cy.get('a.menu-show-button:visible') + cy.get('button.menu-show-button:visible') .click() cy.get('.namespace-container') .should('have.class', 'is-active') diff --git a/cypress/integration/task/task.spec.js b/cypress/integration/task/task.spec.js index 98664e183..68027e3d8 100644 --- a/cypress/integration/task/task.spec.js +++ b/cypress/integration/task/task.spec.js @@ -27,7 +27,7 @@ describe('Task', () => { it('Should be created new', () => { cy.visit('/lists/1/list') - cy.get('input.input[placeholder="Add a new task…"') + cy.get('.input[placeholder="Add a new task…"') .type('New Task') cy.get('.button') .contains('Add') @@ -43,7 +43,7 @@ describe('Task', () => { cy.visit('/lists/1/list') cy.get('.list-is-empty-notice') .should('not.exist') - cy.get('input.input[placeholder="Add a new task…"') + cy.get('.input[placeholder="Add a new task…"') .type('New Task') cy.get('.button') .contains('Add') @@ -263,8 +263,7 @@ describe('Task', () => { cy.visit(`/tasks/${tasks[0].id}`) - cy.get('.task-view .action-buttons .button') - .contains('Assign this task to a user') + cy.get('[data-cy="taskDetail.assign"]') .click() cy.get('.task-view .column.assignees .multiselect input') .type(users[1].username) @@ -353,7 +352,7 @@ describe('Task', () => { .first() .click() - cy.get('.global-notification') + cy.get('.global-notification', { timeout: 4000 }) .should('contain', 'Success') cy.get('.task-view .details.labels-list .multiselect .input-wrapper span.tag') .should('exist') diff --git a/cypress/integration/user/registration.spec.js b/cypress/integration/user/registration.spec.js index 3e7cf1f54..fc1b0fbde 100644 --- a/cypress/integration/user/registration.spec.js +++ b/cypress/integration/user/registration.spec.js @@ -24,8 +24,8 @@ context('Registration', () => { cy.visit('/register') cy.get('#username').type(fixture.username) cy.get('#email').type(fixture.email) - cy.get('#password1').type(fixture.password) - cy.get('#password2').type(fixture.password) + cy.get('#password').type(fixture.password) + cy.get('#passwordValidation').type(fixture.password) cy.get('#register-submit').click() cy.url().should('include', '/') cy.clock(1625656161057) // 13:00 @@ -42,8 +42,8 @@ context('Registration', () => { cy.visit('/register') cy.get('#username').type(fixture.username) cy.get('#email').type(fixture.email) - cy.get('#password1').type(fixture.password) - cy.get('#password2').type(fixture.password) + cy.get('#password').type(fixture.password) + cy.get('#passwordValidation').type(fixture.password) cy.get('#register-submit').click() cy.get('div.notification.is-danger').contains('A user with this username already exists.') }) diff --git a/cypress/integration/user/settings.spec.js b/cypress/integration/user/settings.spec.js index 36467bae7..29cb1ad03 100644 --- a/cypress/integration/user/settings.spec.js +++ b/cypress/integration/user/settings.spec.js @@ -8,11 +8,11 @@ describe('User Settings', () => { }) it('Changes the user avatar', () => { - cy.visit('/user/settings') + cy.visit('/user/settings/avatar') cy.get('input[name=avatarProvider][value=upload]') .click() - cy.get('input[type=file]') + cy.get('input[type=file]', { timeout: 1000 }) .attachFile('image.jpg') cy.get('.vue-handler-wrapper.vue-handler-wrapper--south .vue-simple-handler.vue-simple-handler--south') .trigger('mousedown', {which: 1}) @@ -28,9 +28,10 @@ describe('User Settings', () => { }) it('Updates the name', () => { - cy.visit('/user/settings') + cy.visit('/user/settings/general') - cy.get('input#newName') + cy.get('.general-settings .control input.input') + .first() .type('Lorem Ipsum') cy.get('.card.general-settings .button.is-primary') .contains('Save') diff --git a/cypress/support/factory.js b/cypress/support/factory.js index 0c50bf8fc..934f2fae9 100644 --- a/cypress/support/factory.js +++ b/cypress/support/factory.js @@ -1,5 +1,4 @@ import {seed} from './seed' -import merge from 'lodash/merge' /** * A factory makes it easy to seed the database with data. @@ -25,7 +24,10 @@ export class Factory { const data = [] for (let i = 1; i <= count; i++) { - const entry = merge(this.factory(), override) + const entry = { + ...this.factory(), + ...override, + } for (const e in entry) { if(typeof entry[e] === 'function') { entry[e] = entry[e](i) diff --git a/cypress/support/index.js b/cypress/support/index.js index 22ec961fa..0c885c654 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -2,3 +2,10 @@ import './commands' import 'cypress-file-upload' import '@4tw/cypress-drag-drop' + +// see https://github.com/cypress-io/cypress/issues/702#issuecomment-587127275 +Cypress.on('window:before:load', (win) => { + // disable service workers + // @ts-ignore + delete win.navigator.__proto__.ServiceWorker +}) \ No newline at end of file diff --git a/index.html b/index.html index 016ea547d..c526fa6bd 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,6 @@ - @@ -31,7 +30,10 @@ // It has to be the full url, including the last /api/v1 part and port. // You can change this if your api is not reachable on the same port as the frontend. window.API_URL = 'http://localhost:3456/api/v1' - // + // Enable error tracking with sentry. If this is set to true, will send anonymized data to + // our sentry instance to notify us of potential problems. + window.SENTRY_ENABLED = false + window.SENTRY_DSN = 'https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480' diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 000000000..24ee45e7f --- /dev/null +++ b/netlify.toml @@ -0,0 +1,15 @@ +[build] + command = "yarn build" + publish = "dist" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 + +[[headers]] + for = "/*" + [headers.values] + X-Frame-Options = "DENY" + X-XSS-Protection = "1; mode=block" + X-Robots-Tag = "noindex" diff --git a/nginx.conf b/nginx.conf index 1b3d0e4f1..9b0674b72 100644 --- a/nginx.conf +++ b/nginx.conf @@ -34,7 +34,7 @@ http { gzip_buffers 16 8k; gzip_http_version 1.1; gzip_min_length 256; - gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml font/woff2 image/x-icon audio/wav; + gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon audio/wav; map_hash_max_size 128; map_hash_bucket_size 128; @@ -60,19 +60,20 @@ http { server { listen 80; listen 81 default_server http2 proxy_protocol; ## Needed when behind HAProxy with SSL termination + HTTP/2 support - listen 443 default_server ssl http2; server_name _; expires $expires; - ssl_certificate /etc/nginx/ssl/dummy.crt; - ssl_certificate_key /etc/nginx/ssl/dummy.key; + location ~* .(txt|webmanifest|css|js|mjs|map|svg|jpg|jpeg|png|ico|ttf|woff|woff2|wav)$ { + root /usr/share/nginx/html; + try_files $uri $uri/ =404; + } location / { root /usr/share/nginx/html; - try_files $uri $uri/ /; - index index.html index.htm; + try_files $uri $uri/ /index.html; + index index.html; } error_page 500 502 503 504 /50x.html; diff --git a/originalMedia/audio/pop.mp3 b/originalMedia/audio/pop.mp3 new file mode 100644 index 000000000..019dc257a Binary files /dev/null and b/originalMedia/audio/pop.mp3 differ diff --git a/public/audio/pop.wav b/originalMedia/audio/pop.wav similarity index 100% rename from public/audio/pop.wav rename to originalMedia/audio/pop.wav diff --git a/originalMedia/icons/android-chrome-192x192.png b/originalMedia/icons/android-chrome-192x192.png new file mode 100644 index 000000000..981d0057d Binary files /dev/null and b/originalMedia/icons/android-chrome-192x192.png differ diff --git a/originalMedia/icons/android-chrome-512x512.png b/originalMedia/icons/android-chrome-512x512.png new file mode 100644 index 000000000..2ed624508 Binary files /dev/null and b/originalMedia/icons/android-chrome-512x512.png differ diff --git a/originalMedia/icons/apple-touch-icon-120x120.png b/originalMedia/icons/apple-touch-icon-120x120.png new file mode 100644 index 000000000..2994716bb Binary files /dev/null and b/originalMedia/icons/apple-touch-icon-120x120.png differ diff --git a/originalMedia/icons/apple-touch-icon-152x152.png b/originalMedia/icons/apple-touch-icon-152x152.png new file mode 100644 index 000000000..f32e17a95 Binary files /dev/null and b/originalMedia/icons/apple-touch-icon-152x152.png differ diff --git a/originalMedia/icons/apple-touch-icon-180x180.png b/originalMedia/icons/apple-touch-icon-180x180.png new file mode 100644 index 000000000..c6d9e555d Binary files /dev/null and b/originalMedia/icons/apple-touch-icon-180x180.png differ diff --git a/originalMedia/icons/apple-touch-icon-60x60.png b/originalMedia/icons/apple-touch-icon-60x60.png new file mode 100644 index 000000000..a8cea5d2a Binary files /dev/null and b/originalMedia/icons/apple-touch-icon-60x60.png differ diff --git a/originalMedia/icons/apple-touch-icon-76x76.png b/originalMedia/icons/apple-touch-icon-76x76.png new file mode 100644 index 000000000..c82e89718 Binary files /dev/null and b/originalMedia/icons/apple-touch-icon-76x76.png differ diff --git a/originalMedia/icons/apple-touch-icon.png b/originalMedia/icons/apple-touch-icon.png new file mode 100644 index 000000000..c6d9e555d Binary files /dev/null and b/originalMedia/icons/apple-touch-icon.png differ diff --git a/originalMedia/icons/badge-monochrome.png b/originalMedia/icons/badge-monochrome.png new file mode 100644 index 000000000..6e346df50 Binary files /dev/null and b/originalMedia/icons/badge-monochrome.png differ diff --git a/originalMedia/icons/favicon-16x16.png b/originalMedia/icons/favicon-16x16.png new file mode 100644 index 000000000..8e320aa44 Binary files /dev/null and b/originalMedia/icons/favicon-16x16.png differ diff --git a/originalMedia/icons/favicon-32x32.png b/originalMedia/icons/favicon-32x32.png new file mode 100644 index 000000000..308d32ca8 Binary files /dev/null and b/originalMedia/icons/favicon-32x32.png differ diff --git a/originalMedia/icons/icon-maskable.png b/originalMedia/icons/icon-maskable.png new file mode 100644 index 000000000..959479b3a Binary files /dev/null and b/originalMedia/icons/icon-maskable.png differ diff --git a/originalMedia/icons/msapplication-icon-144x144.png b/originalMedia/icons/msapplication-icon-144x144.png new file mode 100644 index 000000000..552f4d2b8 Binary files /dev/null and b/originalMedia/icons/msapplication-icon-144x144.png differ diff --git a/originalMedia/icons/mstile-150x150.png b/originalMedia/icons/mstile-150x150.png new file mode 100644 index 000000000..42d5792b3 Binary files /dev/null and b/originalMedia/icons/mstile-150x150.png differ diff --git a/originalMedia/icons/safari-pinned-tab.svg b/originalMedia/icons/safari-pinned-tab.svg new file mode 100644 index 000000000..732afd8eb --- /dev/null +++ b/originalMedia/icons/safari-pinned-tab.svg @@ -0,0 +1,149 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/public/images/cool.svg b/originalMedia/images/cool.svg similarity index 100% rename from public/images/cool.svg rename to originalMedia/images/cool.svg diff --git a/public/images/llama-nightscape.png b/originalMedia/images/llama-nightscape.png similarity index 100% rename from public/images/llama-nightscape.png rename to originalMedia/images/llama-nightscape.png diff --git a/public/images/llama-nightscape.svg b/originalMedia/images/llama-nightscape.svg similarity index 100% rename from public/images/llama-nightscape.svg rename to originalMedia/images/llama-nightscape.svg diff --git a/public/images/llama.svg b/originalMedia/images/llama.svg similarity index 100% rename from public/images/llama.svg rename to originalMedia/images/llama.svg diff --git a/public/images/logo-full-pride.svg b/originalMedia/images/logo-full-pride.svg similarity index 100% rename from public/images/logo-full-pride.svg rename to originalMedia/images/logo-full-pride.svg diff --git a/public/images/logo-full-white.svg b/originalMedia/images/logo-full-white.svg similarity index 100% rename from public/images/logo-full-white.svg rename to originalMedia/images/logo-full-white.svg diff --git a/public/images/logo-full.svg b/originalMedia/images/logo-full.svg similarity index 100% rename from public/images/logo-full.svg rename to originalMedia/images/logo-full.svg diff --git a/public/images/logo.svg b/originalMedia/images/logo.svg similarity index 100% rename from public/images/logo.svg rename to originalMedia/images/logo.svg diff --git a/originalMedia/images/migration/microsoft-todo.svg b/originalMedia/images/migration/microsoft-todo.svg new file mode 100644 index 000000000..08ead855f --- /dev/null +++ b/originalMedia/images/migration/microsoft-todo.svg @@ -0,0 +1 @@ +Todo \ No newline at end of file diff --git a/originalMedia/images/migration/todoist.svg b/originalMedia/images/migration/todoist.svg new file mode 100644 index 000000000..720046abe --- /dev/null +++ b/originalMedia/images/migration/todoist.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/originalMedia/images/migration/trello.svg b/originalMedia/images/migration/trello.svg new file mode 100644 index 000000000..8cb63b043 --- /dev/null +++ b/originalMedia/images/migration/trello.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/originalMedia/images/migration/wunderlist.png b/originalMedia/images/migration/wunderlist.png new file mode 100644 index 000000000..9c74530f7 Binary files /dev/null and b/originalMedia/images/migration/wunderlist.png differ diff --git a/package.json b/package.json index 49bbd92b9..de879f47a 100644 --- a/package.json +++ b/package.json @@ -7,81 +7,99 @@ "serve:dist-dev": "node scripts/serve-dist.js", "serve:dist": "vite preview", "build": "vite build && workbox copyLibraries dist/", + "build:modern-only": "BUILD_MODERN_ONLY=true vite build && workbox copyLibraries dist/", "build:dev": "vite build -m development --outDir dist-dev/", "lint": "eslint --ignore-pattern '*.test.*' ./src --ext .vue,.js,.ts", + "lint:markup": "vue-tsc --noEmit", "cypress:open": "cypress open", "test:unit": "jest", - "test:frontend": "cypress run" + "test:frontend": "cypress run", + "browserslist:update": "npx browserslist@latest --update-db" }, "dependencies": { - "browserslist": "4.17.0", - "bulma": "0.9.3", + "@github/hotkey": "1.6.0", + "@kyvg/vue3-notification": "2.3.4", + "@sentry/tracing": "6.15.0", + "@sentry/vue": "6.15.0", + "@vue/compat": "3.2.22", + "@vueuse/core": "7.0.1", + "bulma-css-variables": "0.9.33", "camel-case": "4.1.2", + "codemirror": "5.64.0", "copy-to-clipboard": "3.3.1", - "date-fns": "2.23.0", - "dompurify": "2.3.1", - "highlight.js": "11.2.0", + "date-fns": "2.26.0", + "dompurify": "2.3.3", + "easymde": "2.15.0", + "flatpickr": "4.6.9", + "flexsearch": "0.7.21", + "highlight.js": "11.3.1", "is-touch-device": "1.0.1", - "lodash": "4.17.21", - "marked": "3.0.3", + "lodash.clonedeep": "4.5.0", + "lodash.debounce": "4.0.8", + "marked": "4.0.4", "register-service-worker": "1.7.2", "snake-case": "3.0.4", - "verte": "0.0.12", - "vue": "2.6.14", - "vue-advanced-cropper": "1.8.2", - "vue-drag-resize": "1.5.4", - "vue-easymde": "1.4.0", - "vue-i18n": "8.25.0", - "vue-shortkey": "3.1.7", - "vuedraggable": "2.24.3", - "vuex": "3.6.2", - "workbox-precaching": "6.3.0" + "ufo": "0.7.9", + "v-tooltip": "4.0.0-beta.2", + "vue": "3.2.22", + "vue-advanced-cropper": "2.7.0", + "vue-drag-resize": "2.0.3", + "vue-flatpickr-component": "9.0.5", + "vue-i18n": "9.2.0-beta.20", + "vue-router": "4.0.12", + "vuedraggable": "4.1.0", + "vuex": "4.0.2", + "workbox-precaching": "6.4.1" }, "devDependencies": { "@4tw/cypress-drag-drop": "2.0.0", "@fortawesome/fontawesome-svg-core": "1.2.36", "@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4", - "@fortawesome/vue-fontawesome": "2.0.2", - "@types/jest": "27.0.1", - "@typescript-eslint/eslint-plugin": "4.31.0", - "@typescript-eslint/parser": "4.31.0", - "@vue/babel-preset-app": "4.5.13", - "@vue/eslint-config-typescript": "7.0.0", - "autoprefixer": "10.3.4", - "axios": "0.21.4", - "babel-eslint": "10.1.0", - "cypress": "8.3.1", + "@fortawesome/vue-fontawesome": "3.0.0-5", + "@types/flexsearch": "0.7.2", + "@types/jest": "27.0.3", + "@typescript-eslint/eslint-plugin": "5.4.0", + "@typescript-eslint/parser": "5.4.0", + "@vitejs/plugin-legacy": "1.6.3", + "@vitejs/plugin-vue": "1.10.0", + "@vue/eslint-config-typescript": "9.1.0", + "axios": "0.24.0", + "browserslist": "4.18.1", + "cypress": "8.7.0", "cypress-file-upload": "5.0.8", - "esbuild": "0.12.26", - "eslint": "7.32.0", - "eslint-plugin-vue": "7.17.0", + "esbuild": "0.13.15", + "eslint": "8.3.0", + "eslint-plugin-vue": "8.1.1", "express": "4.17.1", "faker": "5.5.3", - "jest": "27.1.1", - "rollup-plugin-terser": "7.0.2", + "jest": "27.3.1", + "netlify-cli": "7.0.4", + "postcss": "8.3.11", + "postcss-preset-env": "7.0.1", + "rollup": "2.60.1", "rollup-plugin-visualizer": "5.5.2", - "sass": "1.39.2", - "ts-jest": "27.0.5", - "typescript": "4.4.2", - "vite": "2.5.6", - "vite-plugin-pwa": "0.11.2", - "vite-plugin-vue2": "1.8.2", - "vue-flatpickr-component": "8.1.7", - "vue-notification": "1.3.20", - "vue-router": "3.5.2", - "vue-template-compiler": "2.6.14", + "sass": "1.43.4", + "slugify": "1.6.3", + "ts-jest": "27.0.7", + "typescript": "4.5.2", + "vite": "2.6.14", + "vite-plugin-pwa": "0.11.6", + "vite-svg-loader": "3.1.0", + "vue-tsc": "0.29.6", "wait-on": "6.0.0", - "workbox-cli": "6.3.0" + "workbox-cli": "6.4.1" }, "eslintConfig": { "root": true, "env": { + "browser": true, + "es2021": true, "node": true }, "extends": [ - "plugin:vue/essential", "eslint:recommended", + "plugin:vue/vue3-essential", "@vue/typescript" ], "rules": { @@ -100,10 +118,13 @@ "semi": [ "error", "never" - ] + ], + "vue/multi-word-component-names": 0 }, + "parser": "vue-eslint-parser", "parserOptions": { - "parser": "@typescript-eslint/parser" + "parser": "@typescript-eslint/parser", + "ecmaVersion": 2021 }, "ignorePatterns": [ "*.test.*", @@ -115,13 +136,6 @@ "autoprefixer": {} } }, - "browserslist": [ - "> 1%", - "last 2 versions", - "not ie > 0", - "not dead", - "Firefox ESR" - ], "jest": { "testPathIgnorePatterns": [ "cypress" diff --git a/ping-weblate.sh b/ping-weblate.sh deleted file mode 100755 index af0e2e019..000000000 --- a/ping-weblate.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -e - -# Shell script because yaml doesn't understand the header is a string literal and not a yaml symbol - -curl -d operation=pull -H "Authorization: Token $WEBLATE_TOKEN" https://hosted.weblate.org/api/projects/vikunja/repository/ -curl -d operation=push -H "Authorization: Token $WEBLATE_TOKEN" https://hosted.weblate.org/api/projects/vikunja/repository/ diff --git a/public/audio/pop.mp3 b/public/audio/pop.mp3 new file mode 100644 index 000000000..019dc257a Binary files /dev/null and b/public/audio/pop.mp3 differ diff --git a/public/fonts/quicksand-v7-latin-300.woff2 b/public/fonts/quicksand-v7-latin-300.woff2 deleted file mode 100644 index 10738e44b..000000000 Binary files a/public/fonts/quicksand-v7-latin-300.woff2 and /dev/null differ diff --git a/public/images/icons/android-chrome-192x192.png b/public/images/icons/android-chrome-192x192.png index 981d0057d..07d7dbd8d 100644 Binary files a/public/images/icons/android-chrome-192x192.png and b/public/images/icons/android-chrome-192x192.png differ diff --git a/public/images/icons/android-chrome-512x512.png b/public/images/icons/android-chrome-512x512.png index 2ed624508..1bf42a0e4 100644 Binary files a/public/images/icons/android-chrome-512x512.png and b/public/images/icons/android-chrome-512x512.png differ diff --git a/public/images/icons/apple-touch-icon-120x120.png b/public/images/icons/apple-touch-icon-120x120.png index 2994716bb..58ff5209d 100644 Binary files a/public/images/icons/apple-touch-icon-120x120.png and b/public/images/icons/apple-touch-icon-120x120.png differ diff --git a/public/images/icons/apple-touch-icon-152x152.png b/public/images/icons/apple-touch-icon-152x152.png index f32e17a95..248cc77ad 100644 Binary files a/public/images/icons/apple-touch-icon-152x152.png and b/public/images/icons/apple-touch-icon-152x152.png differ diff --git a/public/images/icons/apple-touch-icon-180x180.png b/public/images/icons/apple-touch-icon-180x180.png index c6d9e555d..39d6e68b8 100644 Binary files a/public/images/icons/apple-touch-icon-180x180.png and b/public/images/icons/apple-touch-icon-180x180.png differ diff --git a/public/images/icons/apple-touch-icon-60x60.png b/public/images/icons/apple-touch-icon-60x60.png index a8cea5d2a..ad20376f7 100644 Binary files a/public/images/icons/apple-touch-icon-60x60.png and b/public/images/icons/apple-touch-icon-60x60.png differ diff --git a/public/images/icons/apple-touch-icon-76x76.png b/public/images/icons/apple-touch-icon-76x76.png index c82e89718..ce616ccec 100644 Binary files a/public/images/icons/apple-touch-icon-76x76.png and b/public/images/icons/apple-touch-icon-76x76.png differ diff --git a/public/images/icons/apple-touch-icon.png b/public/images/icons/apple-touch-icon.png index c6d9e555d..39d6e68b8 100644 Binary files a/public/images/icons/apple-touch-icon.png and b/public/images/icons/apple-touch-icon.png differ diff --git a/public/images/icons/badge-monochrome.png b/public/images/icons/badge-monochrome.png index 6e346df50..e1ae189d2 100644 Binary files a/public/images/icons/badge-monochrome.png and b/public/images/icons/badge-monochrome.png differ diff --git a/public/images/icons/favicon-16x16.png b/public/images/icons/favicon-16x16.png index 8e320aa44..56d71330b 100644 Binary files a/public/images/icons/favicon-16x16.png and b/public/images/icons/favicon-16x16.png differ diff --git a/public/images/icons/favicon-32x32.png b/public/images/icons/favicon-32x32.png index 308d32ca8..e0ccb6193 100644 Binary files a/public/images/icons/favicon-32x32.png and b/public/images/icons/favicon-32x32.png differ diff --git a/public/images/icons/icon-maskable.png b/public/images/icons/icon-maskable.png index 959479b3a..261aec338 100644 Binary files a/public/images/icons/icon-maskable.png and b/public/images/icons/icon-maskable.png differ diff --git a/public/images/icons/msapplication-icon-144x144.png b/public/images/icons/msapplication-icon-144x144.png index 552f4d2b8..05143040c 100644 Binary files a/public/images/icons/msapplication-icon-144x144.png and b/public/images/icons/msapplication-icon-144x144.png differ diff --git a/public/images/icons/mstile-150x150.png b/public/images/icons/mstile-150x150.png index 42d5792b3..5f4d833d1 100644 Binary files a/public/images/icons/mstile-150x150.png and b/public/images/icons/mstile-150x150.png differ diff --git a/public/images/migration/microsoft-todo.png b/public/images/migration/microsoft-todo.png deleted file mode 100644 index 38a2da383..000000000 Binary files a/public/images/migration/microsoft-todo.png and /dev/null differ diff --git a/public/images/migration/todoist.png b/public/images/migration/todoist.png deleted file mode 100644 index c06f9f346..000000000 Binary files a/public/images/migration/todoist.png and /dev/null differ diff --git a/public/images/migration/trello.png b/public/images/migration/trello.png deleted file mode 100644 index 02cfa1140..000000000 Binary files a/public/images/migration/trello.png and /dev/null differ diff --git a/public/images/migration/vikunja-file.png b/public/images/migration/vikunja-file.png deleted file mode 100644 index ee9eb1583..000000000 Binary files a/public/images/migration/vikunja-file.png and /dev/null differ diff --git a/public/images/migration/wunderlist.png b/public/images/migration/wunderlist.png deleted file mode 100644 index 907ed0ca1..000000000 Binary files a/public/images/migration/wunderlist.png and /dev/null differ diff --git a/run.sh b/run.sh index 58596264b..22a86cdbf 100755 --- a/run.sh +++ b/run.sh @@ -2,14 +2,24 @@ # This shell script sets the api url based on an environment variable and starts nginx in foreground. -if [ -z "$VIKUNJA_API_URL" ]; then - VIKUNJA_API_URL="/api/v1" -fi +VIKUNJA_API_URL="${VIKUNJA_API_URL:-"/api/v1"}" +VIKUNJA_SENTRY_ENABLED="${VIKUNJA_SENTRY_ENABLED:-"false"}" +VIKUNJA_SENTRY_DSN="${VIKUNJA_SENTRY_DSN:-"https://7e684483a06a4225b3e05cc47cae7a11@sentry.kolaente.de/2"}" +VIKUNJA_HTTP_PORT="${VIKUNJA_HTTP_PORT:-80}" +VIKUNJA_HTTPS_PORT="${VIKUNJA_HTTPS_PORT:-443}" + +echo "Using $VIKUNJA_API_URL as default api url" # Escape the variable to prevent sed from complaining VIKUNJA_API_URL=$(echo $VIKUNJA_API_URL |sed 's/\//\\\//g') -sed -i "s/http\:\/\/localhost\:3456\/api\/v1/$VIKUNJA_API_URL/g" /usr/share/nginx/html/index.html +sed -i "s/http\:\/\/localhost\:3456//g" /usr/share/nginx/html/index.html # replacing in two steps to make sure api urls from releases are properly replaced as well +sed -i "s/'\/api\/v1/'$VIKUNJA_API_URL/g" /usr/share/nginx/html/index.html +sed -i "s/\.SENTRY_ENABLED = false/\.SENTRY_ENABLED = $VIKUNJA_SENTRY_ENABLED/g" /usr/share/nginx/html/index.html +sed -i "s/\.SENTRY_DSN = '.*'/\.SENTRY_DSN = '$VIKUNJA_SENTRY_DSN'/g" /usr/share/nginx/html/index.html + +sed -i "s/listen 80/listen $VIKUNJA_HTTP_PORT/g" /etc/nginx/nginx.conf +sed -i "s/listen 443/listen $VIKUNJA_HTTPS_PORT/g" /etc/nginx/nginx.conf # Set the uid and gid of the nginx run user usermod --non-unique --uid ${PUID} nginx diff --git a/scripts/deploy-preview-netlify.js b/scripts/deploy-preview-netlify.js new file mode 100644 index 000000000..b2dd23364 --- /dev/null +++ b/scripts/deploy-preview-netlify.js @@ -0,0 +1,66 @@ +const slugify = require('slugify') +const {exec} = require('child_process') +const axios = require('axios') + +const BOT_USER_ID = 513 +const giteaToken = process.env.GITEA_TOKEN +const siteId = process.env.NETLIFY_SITE_ID +const branchSlug = slugify(process.env.DRONE_SOURCE_BRANCH) +const prNumber = process.env.DRONE_PULL_REQUEST + +const prIssueCommentsUrl = `https://kolaente.dev/api/v1/repos/vikunja/frontend/issues/${prNumber}/comments` +const alias = `${prNumber}-${branchSlug}` +const fullPreviewUrl = `https://${alias}--vikunja-frontend-preview.netlify.app` + +const promiseExec = cmd => { + return new Promise((resolve, reject) => { + exec(cmd, (error, stdout, stderr) => { + if (error) { + reject(error) + return + } + + resolve(stdout) + }) + }) +} + +(async function () { + let stdout = await promiseExec(`./node_modules/.bin/netlify link --id ${siteId}`) + console.log(stdout) + stdout = await promiseExec(`./node_modules/.bin/netlify deploy --alias ${alias}`) + console.log(stdout) + + const {data} = await axios.get(prIssueCommentsUrl) + const hasComment = data.some(c => c.user.id === BOT_USER_ID) + + if (hasComment) { + console.log(`PR #${prNumber} already has a comment with a link, not sending another comment.`) + return + } + + await axios.post(prIssueCommentsUrl, { + body: ` +Hi ${process.env.DRONE_COMMIT_AUTHOR}! + +Thank you for creating a PR! + +I've deployed the changes of this PR on a preview environment under this URL: ${fullPreviewUrl} + +You can use this url to view the changes live and test them out. +You will need to manually connect this to an api running somehwere. The easiest to use is https://try.vikunja.io/. + +Have a nice day! + +> Beep boop, I'm a bot. +`, + }, { + headers: { + 'Content-Type': 'application/json', + 'accept': 'application/json', + 'Authorization': `token ${giteaToken}`, + }, + }) + + console.log(`Preview comment sent successfully to PR #${prNumber}!`) +})() \ No newline at end of file diff --git a/scripts/deploy-preview-netlify.js.sha384 b/scripts/deploy-preview-netlify.js.sha384 new file mode 100644 index 000000000..fe5f72f1d --- /dev/null +++ b/scripts/deploy-preview-netlify.js.sha384 @@ -0,0 +1 @@ +55ce0faaa2c1919341617ccfaeccbb6029ac12107964ff488985cff13dd952f1a991df3ab0d4b0705deb761e508e6434 ./scripts/deploy-preview-netlify.js diff --git a/src/App.vue b/src/App.vue index a02b72695..5eacb532c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,28 +1,25 @@ + + diff --git a/src/assets/llama-cool.svg b/src/assets/llama-cool.svg new file mode 100644 index 000000000..e086954ab --- /dev/null +++ b/src/assets/llama-cool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/llama-nightscape.jpg b/src/assets/llama-nightscape.jpg new file mode 100644 index 000000000..1f1654720 Binary files /dev/null and b/src/assets/llama-nightscape.jpg differ diff --git a/src/assets/llama.svg b/src/assets/llama.svg new file mode 100644 index 000000000..bd208994c --- /dev/null +++ b/src/assets/llama.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/logo-full-pride.svg b/src/assets/logo-full-pride.svg new file mode 100644 index 000000000..1ecacb3e9 --- /dev/null +++ b/src/assets/logo-full-pride.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/logo-full.svg b/src/assets/logo-full.svg new file mode 100644 index 000000000..20b6ae130 --- /dev/null +++ b/src/assets/logo-full.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 000000000..53176d66e --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/components/home/Logo.vue b/src/components/home/Logo.vue new file mode 100644 index 000000000..5a5612b46 --- /dev/null +++ b/src/components/home/Logo.vue @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/src/components/home/MenuButton.vue b/src/components/home/MenuButton.vue new file mode 100644 index 000000000..ab012c92b --- /dev/null +++ b/src/components/home/MenuButton.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/src/components/home/PoweredByLink.vue b/src/components/home/PoweredByLink.vue new file mode 100644 index 000000000..06ff3b111 --- /dev/null +++ b/src/components/home/PoweredByLink.vue @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/src/components/home/contentAuth.vue b/src/components/home/contentAuth.vue index 970fcd312..7a2bd2427 100644 --- a/src/components/home/contentAuth.vue +++ b/src/components/home/contentAuth.vue @@ -1,7 +1,7 @@