Merge branch 'main' into vue3
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Dominik Pschenitschni 2021-10-15 20:43:11 +02:00
commit 8e1ab8e09b
Signed by: dpschen
GPG Key ID: B257AC0149F43A77
16 changed files with 126 additions and 80 deletions

View File

@ -80,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
@ -120,12 +108,12 @@ 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

View File

@ -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
})

View File

@ -19,6 +19,7 @@
import {mapState} from 'vuex'
import logoUrl from '@/assets/logo-full.svg'
import { saveLastVisited } from '@/helpers/saveLastVisited'
export default {
name: 'contentNoAuth',
@ -57,6 +58,7 @@ export default {
localStorage.getItem('passwordResetToken') === null &&
localStorage.getItem('emailConfirmToken') === null
) {
saveLastVisited(this.$route.name, this.$route.params)
this.$router.push({name: 'user.login'})
}
},

View File

@ -10,7 +10,7 @@
v-focus
v-model="newTaskTitle"
ref="newTaskInput"
:style="{'height': `${textAreaHeight}px`}"
:style="{'height': `calc(${textAreaHeight}px - 2px + 1rem)`}"
@keyup="errorMessage = ''"
@keydown.enter="handleEnter"
/>
@ -40,7 +40,8 @@
import TaskService from '../../services/task'
import QuickAddMagic from '@/components/tasks/partials/quick-add-magic.vue'
const INITIAL_SCROLL_HEIGHT = 40
const INPUT_BORDER_PX = 2
const LINE_HEIGHT = 1.5 // using getComputedStyles().lineHeight returns an (wrong) absolute pixel value, we need the factor to do calculations with it.
const cleanupTitle = title => {
return title.replace(/^((\* |\+ |- )(\[ \] )?)/g, '')
@ -54,7 +55,8 @@ export default {
newTaskTitle: '',
taskService: new TaskService(),
errorMessage: '',
textAreaHeight: INITIAL_SCROLL_HEIGHT,
textAreaHeight: null,
initialTextAreaHeight: null,
}
},
components: {
@ -68,14 +70,17 @@ export default {
},
watch: {
newTaskTitle(newVal) {
let scrollHeight = this.$refs.newTaskInput.scrollHeight
if (scrollHeight < INITIAL_SCROLL_HEIGHT || newVal === '') {
scrollHeight = INITIAL_SCROLL_HEIGHT
}
// Calculating the textarea height based on lines of input in it. That is more reliable when removing a
// line from the input.
const numberOfLines = newVal.split(/\r\n|\r|\n/).length
const fontSize = parseInt(window.getComputedStyle(this.$refs.newTaskInput, null).getPropertyValue('font-size'))
this.textAreaHeight = scrollHeight
this.textAreaHeight = numberOfLines * fontSize * LINE_HEIGHT + INPUT_BORDER_PX
},
},
mounted() {
this.initialTextAreaHeight = this.$refs.newTaskInput.scrollHeight + INPUT_BORDER_PX
},
methods: {
addTask() {
if (this.newTaskTitle === '') {

View File

@ -0,0 +1,18 @@
const LAST_VISITED_KEY = 'lastVisited'
export const saveLastVisited = (name: string, params: object) => {
localStorage.setItem(LAST_VISITED_KEY, JSON.stringify({name, params}))
}
export const getLastVisited = () => {
const lastVisited = localStorage.getItem(LAST_VISITED_KEY)
if (lastVisited === null) {
return null
}
return JSON.parse(lastVisited)
}
export const clearLastVisited = () => {
return localStorage.removeItem(LAST_VISITED_KEY)
}

View File

@ -128,7 +128,7 @@
}
},
"list": {
"archived": "This list is archived. It is not possible to create new or edit tasks for it.",
"archived": "Diese Liste ist archiviert. Es ist nicht möglich, neue Aufgaben zu erstellen oder sie zu bearbeiten.",
"title": "Listentitel",
"color": "Farbe",
"lists": "Listen",
@ -626,7 +626,7 @@
"addSuccess": "Das Label wurde erfolgreich hinzugefügt.",
"createSuccess": "Das Label wurde erfolgreich erstellt.",
"removeSuccess": "Das Label wurde erfolgreich entfernt.",
"addCreateSuccess": "The label has been created and added successfully."
"addCreateSuccess": "Das Label wurde erfolgreich erstellt und hinzugefügt."
},
"priority": {
"unset": "Nicht eingestellt",
@ -646,19 +646,19 @@
"delete": "Aufgabenbeziehung entfernen",
"deleteText1": "Willst du diese Aufgabenbeziehung wirklich entfernen?",
"deleteText2": "Dies kann nicht rückgängig gemacht werden!",
"select": "Select a relation kind",
"select": "Beziehungsart auswählen",
"kinds": {
"subtask": "Subtask | Subtasks",
"parenttask": "Parent Task | Parent Tasks",
"related": "Related Task | Related Tasks",
"duplicateof": "Duplicate Of | Duplicates Of",
"duplicates": "Duplicates | Duplicates",
"blocking": "Blocking | Blocking",
"blocked": "Blocked By | Blocked By",
"precedes": "Precedes | Precedes",
"follows": "Follows | Follows",
"copiedfrom": "Copied From | Copied From",
"copiedto": "Copied To | Copied To"
"subtask": "Unteraufgabe | Unteraufgaben",
"parenttask": "Übergeordnete Aufgabe | Übergeordnete Aufgaben",
"related": "Zugehörige Aufgabe | Zugehörige Aufgaben",
"duplicateof": "Duplikat von | Duplikate von",
"duplicates": "Dupliziert | Duplizierte",
"blocking": "Blockiert | Blockiert",
"blocked": "Blockiert von | Blockiert von",
"precedes": "Vorgänger | Vorgänger",
"follows": "Folgt | Folgen",
"copiedfrom": "Kopiert von | Kopiert von",
"copiedto": "Kopiert nach | Kopiert nach"
}
},
"repeat": {

View File

@ -128,7 +128,7 @@
}
},
"list": {
"archived": "This list is archived. It is not possible to create new or edit tasks for it.",
"archived": "Diese Liste ist archiviert. Es ist nicht möglich, neue Aufgaben zu erstellen oder sie zu bearbeiten.",
"title": "Liste Titl",
"color": "Farb",
"lists": "Listene",
@ -626,7 +626,7 @@
"addSuccess": "Das Label isch erfolgriich hinzuegfüegt worde.",
"createSuccess": "Das Label isch erfolgriich erstellt worde.",
"removeSuccess": "Das Label isch erfolgriich glöscht.",
"addCreateSuccess": "The label has been created and added successfully."
"addCreateSuccess": "Das Label wurde erfolgreich erstellt und hinzugefügt."
},
"priority": {
"unset": "Nid iihgstellt",
@ -646,19 +646,19 @@
"delete": "Uufgabe Beziehig chüble",
"deleteText1": "Bisch du dir sicher, dass du die Zueghörigkeit chüblä wetsch?",
"deleteText2": "Das chan nid rückgängig gmacht werde!",
"select": "Select a relation kind",
"select": "Beziehungsart auswählen",
"kinds": {
"subtask": "Subtask | Subtasks",
"parenttask": "Parent Task | Parent Tasks",
"related": "Related Task | Related Tasks",
"duplicateof": "Duplicate Of | Duplicates Of",
"duplicates": "Duplicates | Duplicates",
"blocking": "Blocking | Blocking",
"blocked": "Blocked By | Blocked By",
"precedes": "Precedes | Precedes",
"follows": "Follows | Follows",
"copiedfrom": "Copied From | Copied From",
"copiedto": "Copied To | Copied To"
"subtask": "Unteraufgabe | Unteraufgaben",
"parenttask": "Übergeordnete Aufgabe | Übergeordnete Aufgaben",
"related": "Zugehörige Aufgabe | Zugehörige Aufgaben",
"duplicateof": "Duplikat von | Duplikate von",
"duplicates": "Dupliziert | Duplizierte",
"blocking": "Blockiert | Blockiert",
"blocked": "Blockiert von | Blockiert von",
"precedes": "Vorgänger | Vorgänger",
"follows": "Folgt | Folgen",
"copiedfrom": "Kopiert von | Kopiert von",
"copiedto": "Kopiert nach | Kopiert nach"
}
},
"repeat": {
@ -720,13 +720,13 @@
"delete": {
"header": "Das Team chüble",
"text1": "Bischder sicher, dasst wetsch da Team mit allne Mitglieder lösche?",
"text2": "Alli Teammitglider werded ihren Zuegang zu de Liste und Namensrüüm wo mit dem Team verbunde sind verlüüre. Das CHAN NID RÜCKGÄNIG gmacht werde!",
"text2": "All team members will lose access to lists and namespaces shared with this team. This CANNOT BE UNDONE!",
"success": "Da Team isch erfolgriich g'chüblet wore."
},
"deleteUser": {
"header": "Benutzer usem Team entferne",
"text1": "Bisch du dir sicher, dass du de Benutzer usm Team werfe wetsch?",
"text2": "Er wird Zuegriff uf alli Liste und Namensrüüm verlüüre, wo da Team zuegriff druff het. Das CHAN NID RÜCKGÄNIG GMACHT WERDE!",
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
"success": "Benutzer erfolgriich usegworfe."
}
},

View File

@ -720,13 +720,13 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will loose access to lists and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to lists and namespaces shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will loose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
}
},

View File

@ -626,7 +626,7 @@
"addSuccess": "Étiquette ajoutée.",
"createSuccess": "Étiquette créée.",
"removeSuccess": "Étiquette retirée.",
"addCreateSuccess": "The label has been created and added successfully."
"addCreateSuccess": "L'étiquette a bien été créée et ajoutée."
},
"priority": {
"unset": "Non définie",
@ -646,19 +646,19 @@
"delete": "Supprimer la relation de tâche",
"deleteText1": "Supprimer cette relation de tâche ?",
"deleteText2": "Ceci ne peut pas être annulé !",
"select": "Select a relation kind",
"select": "Sélectionnez un genre de relation",
"kinds": {
"subtask": "Subtask | Subtasks",
"parenttask": "Parent Task | Parent Tasks",
"related": "Related Task | Related Tasks",
"duplicateof": "Duplicate Of | Duplicates Of",
"duplicates": "Duplicates | Duplicates",
"blocking": "Blocking | Blocking",
"blocked": "Blocked By | Blocked By",
"precedes": "Precedes | Precedes",
"follows": "Follows | Follows",
"copiedfrom": "Copied From | Copied From",
"copiedto": "Copied To | Copied To"
"subtask": "Sous-tâche | Sous-tâches",
"parenttask": "Tâche parente | Tâches parentes",
"related": "Tâche connexe | Tâches connexes",
"duplicateof": "Doublon de | Doublons de",
"duplicates": "Doublon | Doublons",
"blocking": "Blocage | Blocages",
"blocked": "Bloqué par | Bloqués par",
"precedes": "Précède | Précède",
"follows": "Suit | Suit",
"copiedfrom": "Copié depuis | Copiés depuis",
"copiedto": "Copié vers | Copiés vers"
}
},
"repeat": {

View File

@ -291,7 +291,11 @@ $list-spacing: 1rem;
}
.list-cards-wrapper-2-rows {
flex-wrap: wrap;
max-height: calc(#{$list-height * 2} + #{$list-spacing * 2});
overflow: hidden;
flex-wrap: wrap;
max-height: calc(#{$list-height * 2} + #{$list-spacing * 2} - 4px);
overflow: hidden;
@media screen and (max-width: $mobile) {
max-height: calc(#{$list-height * 4} + #{$list-spacing * 4} - 4px);
}
}

View File

@ -54,7 +54,7 @@
line-height: 1;
.button {
padding: 0 0.25rem;
padding: 0 .5rem;
height: 1rem;
.icon {

View File

@ -38,9 +38,9 @@ $scrollbar-hover-color: $grey-500;
$button-height: 34px;
$switch-view-height: 43px;
$switch-view-height: 2.69rem;
$user-dropdown-width-mobile: 4rem;
$user-dropdown-width-mobile: 5rem;
$hamburger-menu-icon-spacing: 1rem;
$hamburger-menu-icon-width: 28px;
$navbar-height: 4rem;

View File

@ -163,6 +163,9 @@ export default {
// object passed to this function here still has a reference to the store.
this.labelEditLabel = new LabelModel({
...label,
// The model does not support passing dates into it directly so we need to convert them first
created: +label.created,
updated: +label.updated,
})
this.isLabelEdit = true

View File

@ -104,13 +104,13 @@
<script>
import {mapState} from 'vuex'
import router from '../../router'
import {HTTPFactory} from '@/http-common'
import {ERROR_MESSAGE, LOADING} from '@/store/mutation-types'
import legal from '../../components/misc/legal'
import ApiConfig from '@/components/misc/api-config.vue'
import {getErrorText} from '@/message'
import {redirectToProvider} from '../../helpers/redirectToProvider'
import {getLastVisited, clearLastVisited} from '../../helpers/saveLastVisited'
export default {
components: {
@ -142,9 +142,18 @@ export default {
})
}
// Check if the user is already logged in, if so, redirect him to the homepage
// Check if the user is already logged in, if so, redirect them to the homepage
if (this.authenticated) {
router.push({name: 'home'})
const last = getLastVisited()
if (last !== null) {
this.$router.push({
name: last.name,
params: last.params,
})
clearLastVisited()
} else {
this.$router.push({name: 'home'})
}
}
},
created() {

View File

@ -14,6 +14,7 @@ import {mapState} from 'vuex'
import {ERROR_MESSAGE, LOADING} from '@/store/mutation-types'
import {getErrorText} from '@/message'
import {clearLastVisited, getLastVisited} from '../../helpers/saveLastVisited'
export default {
name: 'Auth',
@ -63,7 +64,16 @@ export default {
code: this.$route.query.code,
})
.then(() => {
this.$router.push({name: 'home'})
const last = getLastVisited()
if (last !== null) {
this.$router.push({
name: last.name,
params: last.params,
})
clearLastVisited()
} else {
this.$router.push({name: 'home'})
}
})
.catch(e => {
const err = getErrorText(e)

View File

@ -116,7 +116,7 @@ export default {
}
},
beforeMount() {
// Check if the user is already logged in, if so, redirect him to the homepage
// Check if the user is already logged in, if so, redirect them to the homepage
if (this.authenticated) {
router.push({name: 'home'})
}