From aca5bfbbe066b9b60b5e27e377b758502acaaa56 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 10 May 2025 03:30:51 +0200 Subject: [PATCH 001/121] docs: Add demo notice --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e824b9c9..388fc3dd 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ [**Client demo**](https://plankanban.github.io/planka) (without server features). +> ⚠️ The demo GIF and client demo are based on **v1** and will be updated soon. + ## Key Features - **Collaborative Kanban Boards**: Create projects, boards, lists, cards, and manage tasks with an intuitive drag-and-drop interface From b8270a0532e5fec3ecfb4cc94657666951630aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Pedrini?= Date: Sat, 10 May 2025 17:46:56 +0200 Subject: [PATCH 002/121] fix: Update Italian translation (#1114) --- client/src/locales/it-IT/core.js | 352 ++++++++++++++++++++++-------- client/src/locales/it-IT/login.js | 8 +- 2 files changed, 272 insertions(+), 88 deletions(-) diff --git a/client/src/locales/it-IT/core.js b/client/src/locales/it-IT/core.js index 58706af1..4df38ea7 100644 --- a/client/src/locales/it-IT/core.js +++ b/client/src/locales/it-IT/core.js @@ -17,216 +17,394 @@ export default { translation: { common: { + aboutPlanka: 'Informazioni su PLANKA', account: 'Account', actions: 'Azioni', - addAttachment_title: 'Aggiungi Allegato', - addManager_title: 'Aggiungi Manager', - addMember_title: 'Aggiungi Membro', - addUser_title: 'Aggiungi Utente', + activateUser_title: 'Attiva utente', + active: 'Attivo', + addAttachment_title: 'Aggiungi allegato', + addCustomField_title: 'Aggiungi campo personalizzato', + addCustomFieldGroup_title: 'Aggiungi campi personalizzati', + addManager_title: 'Aggiungi manager', + addMember_title: 'Aggiungi membro', + addTaskList_title: 'Aggiungi lista di task', + addUser_title: 'Aggiungi utente', + admin: 'Amministratore', + administration: 'Amministrazione', all: 'tutto', allChangesWillBeAutomaticallySavedAfterConnectionRestored: 'Tutte le modifiche verranno salvate
al ripristino della connessione.', + alphabetically: 'In ordine alfabetico', + alwaysDisplayCardCreator: 'Mostra sempre il creatore della scheda', + archive: 'Archivia', + archiveCard_title: 'Archivia scheda', + archiveCards_title: 'Archivia schede', + areYouSureYouWantToActivateThisUser: 'Sei sicuro di voler attivare questo utente?', + areYouSureYouWantToArchiveCards: 'Sei sicuro di voler archiviare le schede?', + areYouSureYouWantToArchiveThisCard: 'Sei sicuro di voler archiviare questa scheda?', + areYouSureYouWantToAssignThisProjectManagerAsOwner: + 'Sei sicuro di voler assegnare questo project manager come proprietario?', + areYouSureYouWantToDeactivateThisUser: 'Sei sicuro di voler disattivare questo utente?', areYouSureYouWantToDeleteThisAttachment: 'Sei sicuro di voler eliminare questo allegato?', + areYouSureYouWantToDeleteThisBackgroundImage: + 'Sei sicuro di voler eliminare questa immagine di sfondo?', areYouSureYouWantToDeleteThisBoard: 'Sei sicuro di voler eliminare questa bacheca?', - areYouSureYouWantToDeleteThisCard: 'Sei sicuro di voler eliminare questa card?', + areYouSureYouWantToDeleteThisCard: 'Sei sicuro di voler eliminare questa scheda?', + areYouSureYouWantToDeleteThisCardForever: + 'Sei sicuro di voler eliminare questa scheda per sempre?', areYouSureYouWantToDeleteThisComment: 'Sei sicuro di voler eliminare questo commento?', + areYouSureYouWantToDeleteThisCustomField: + 'Sei sicuro di voler eliminare questo campo personalizzato?', + areYouSureYouWantToDeleteThisCustomFieldGroup: + 'Sei sicuro di voler eliminare questo campi personalizzati?', areYouSureYouWantToDeleteThisLabel: 'Sei sicuro di voler eliminare questa etichetta?', - areYouSureYouWantToDeleteThisList: 'Sei sicuro di voler eliminare questo elenco?', + areYouSureYouWantToDeleteThisList: + 'Sei sicuro di voler eliminare questa lista? Tutte le schede verranno spostate nel cestino.', + areYouSureYouWantToDeleteThisNotificationService: + 'Sei sicuro di voler eliminare questo servizio di notifica?', areYouSureYouWantToDeleteThisProject: 'Sei sicuro di voler eliminare questo progetto?', areYouSureYouWantToDeleteThisTask: 'Sei sicuro di voler eliminare questo task?', + areYouSureYouWantToDeleteThisTaskList: 'Sei sicuro di voler eliminare questa lista di task?', areYouSureYouWantToDeleteThisUser: 'Sei sicuro di voler eliminare questo utente?', + areYouSureYouWantToEmptyTrash: 'Sei sicuro di voler svuotare il cestino?', areYouSureYouWantToLeaveBoard: 'Sei sicuro di voler abbandonare la bacheca?', areYouSureYouWantToLeaveProject: 'Sei sicuro di voler abbandonare il progetto?', + areYouSureYouWantToMakeThisProjectShared: + 'Sei sicuro di voler rendere questo progetto condiviso?', areYouSureYouWantToRemoveThisManagerFromProject: 'Sei sicuro di voler rimuovere questo amministratore dal progetto?', areYouSureYouWantToRemoveThisMemberFromBoard: 'Sei sicuro di voler rimuovere questo membro dalla bacheca?', + assignAsOwner_title: 'Assegna come proprietario', + atLeastOneListMustBePresent: 'Deve essere presente almeno una lista', attachment: 'Allegato', attachments: 'Allegati', authentication: 'Autenticazione', - background: 'Background', + background: 'Sfondo', + baseCustomFields_title: 'Campi personalizzati base', + baseGroup: 'Gruppo base', board: 'Bacheca', + boardActions_title: 'Azioni bacheca', boardNotFound_title: 'Bacheca non trovata', + boardSubscribed: 'Iscritto alla bacheca', + boardUser: 'Utente della bacheca', + byCreationTime: 'Per data di creazione', + byDefault: 'Per impostazione predefinita', + byDueDate: 'Per data di scadenza', + canBeInvitedToWorkInBoards: 'Può essere invitato a lavorare in bacheche.', canComment: 'Può commentare', - canOnlyViewBoard: 'Può solo vedere la bacheca.', - cardActions_title: 'Card Azioni', - cardNotFound_title: 'Card non trovata', + canCreateOwnProjectsAndBeInvitedToWorkInOthers: + 'Può creare i propri progetti ed essere invitato a lavorare in altri.', + canEditBoardLayoutAndAssignMembersToCards: + 'Può modificare il layout della bacheca e assegnare membri alle schede.', + canManageSystemWideSettingsAndActAsProjectOwner: + 'Può gestire le impostazioni di sistema e agire come proprietario del progetto.', + canOnlyViewBoard: 'Può solo visualizzare la bacheca.', + cardActions_title: 'Azioni scheda', + cardNotFound_title: 'Scheda non trovata', + cardsOnThisListAreAvailableToAllBoardMembers: + 'Le schede in questa lista sono disponibili per tutti i membri della bacheca.', + cardsOnThisListAreCompleteAndReadyToBeArchived: + 'Le schede in questa lista sono complete e pronte per essere archiviate.', + cardsOnThisListAreReadyToBeWorkedOn: + 'Le schede in questa lista sono pronte per essere lavorate.', + clickHereOrRefreshPageToUpdate: '<0>Clicca qui o ricarica la pagina per aggiornare.', + closed: 'Chiuso', color: 'Colore', + comments: 'Commenti', + contentExceedsLimit: 'Il contenuto supera {{limit}}', copy_inline: 'copia', - createBoard_title: 'Crea Bacheca', - createLabel_title: 'Crea Etichetta', - createNewOneOrSelectExistingOne: 'Crea nuovo o seleziona
esistente.', - createProject_title: 'Crea Progetto', - createTextFile_title: 'Create File di Testo', - currentPassword: 'Password corrente', + createBoard_title: 'Crea bacheca', + createCustomFieldGroup_title: 'Crea campi personalizzati', + createLabel_title: 'Crea etichetta', + createNewOneOrSelectExistingOne: 'Crea nuovo o seleziona uno
esistente.', + createProject_title: 'Crea progetto', + createTextFile_title: 'Crea file di testo', + creator: 'Creatore', + currentPassword: 'Password attuale', + customField_title: 'Campo personalizzato', + customFields_title: 'Campi personalizzati', + customFieldGroup_title: 'campi personalizzati', + customFieldGroups_title: 'Campi personalizzati', dangerZone_title: 'Zona pericolosa', date: 'Data', - dueDate_title: 'Data di scadenza', - deleteAttachment_title: 'Elimina Allegato', - deleteBoard_title: 'Elimina Bacheca', - deleteCard_title: 'Elimina card', - deleteComment_title: 'Elimina Commento', - deleteLabel_title: 'Elimina Etichetta', - deleteList_title: 'Elimina Elenco', - deleteProject_title: 'Elimina Progetto', - deleteTask_title: 'Elimina Task', - deleteUser_title: 'Elimina Utente', + deactivateUser_title: 'Disattiva utente', + defaultCardType_title: 'Tipo di scheda predefinito', + defaultView_title: 'Vista predefinita', + deletedUser_title: 'Utente eliminato', + deleteAllBoardsToBeAbleToDeleteThisProject: + 'Elimina tutte le bacheche per poter eliminare questo progetto.', + deleteAttachment_title: 'Elimina allegato', + deleteBackgroundImage_title: 'Elimina immagine di sfondo', + deleteBoard_title: 'Elimina bacheca', + deleteCard_title: 'Elimina scheda', + deleteCardForever_title: 'Elimina scheda per sempre', + deleteComment_title: 'Elimina commento', + deleteCustomField_title: 'Elimina campo personalizzato', + deleteCustomFieldGroup_title: 'Elimina campi personalizzati', + deleteLabel_title: 'Elimina etichetta', + deleteList_title: 'Elimina elenco', + deleteNotificationService_title: 'Elimina servizio di notifica', + deleteProject_title: 'Elimina progetto', + deleteTask_title: 'Elimina task', + deleteTaskList_title: 'Elimina lista di task', + deleteUser_title: 'Elimina utente', description: 'Descrizione', detectAutomatically: 'Rileva automaticamente', + display: 'Mostra', dropFileToUpload: 'Trascina il file da caricare', + dueDate_title: 'Data di scadenza', + dynamicAndUnevenlySpacedLayout: 'Layout dinamico e irregolarmente distribuito', editor: 'Editor', - editAttachment_title: 'Modifica Allegato', - editAvatar_title: 'Modifica Avatar', - editDueDate_title: 'Modifica Data di Scadenza', - editEmail_title: 'Modifica E-mail', - editInformation_title: 'Modifica Informazioni', - editLabel_title: 'Modifica Etichetta', - editPassword_title: 'Modifica Password', - editPermissions_title: 'Modifica Permessi', - editStopwatch_title: 'Modifica Timer', - editUsername_title: 'Modifica Username', + editors: 'Editors', + editAttachment_title: 'Modifica allegato', + editAvatar_title: 'Modifica avatar', + editColor_title: 'Modifica colore', + editCustomField_title: 'Modifica campo personalizzato', + editCustomFieldGroup_title: 'Modifica campi personalizzati', + editDueDate_title: 'Modifica data di scadenza', + editEmail_title: 'Modifica indirizzo e-mail', + editInformation_title: 'Modifica informazioni', + editLabel_title: 'Modifica etichetta', + editPassword_title: 'Modifica password', + editPermissions_title: 'Modifica permessi', + editRole_title: 'Modifica ruolo', + editStopwatch_title: 'Modifica timer', + editType_title: 'Modifica tipo', + editUsername_title: 'Modifica username', email: 'E-mail', - enterCardTitle: 'Inserire titolo della card...', + emptyTrash_title: 'Svuota cestino', + enterCardTitle: 'Inserire titolo della scheda...', enterDescription: 'Inserire descrizione...', enterFilename: 'Inserire nome del file', enterListTitle: 'Inserire titolo della lista...', - enterTaskDescription: 'Inserire descrizione del task...', - filterByLabels_title: 'Filtra per Etichetta', - filterByMembers_title: 'Filtra per Membro', + enterTaskDescription: 'Inserire descrizione della task...', + filterByLabels_title: 'Filtra per etichetta', + filterByMembers_title: 'Filtra per membro', + forTeamBasedProjects: 'Per progetti di gruppo', + forPersonalProjects: 'Per progetti personali', fromComputer_title: 'Dal Computer', fromTrello: 'Da Trello', general: 'Generale', + gradients: 'Gradiente', + grid: 'Griglia', + hideFromProjectListAndFavorites: 'Nascondi dalla lista dei progetti e dai preferiti', hours: 'Ore', - importBoard_title: 'Importa Board', + importBoard_title: 'Importa board', invalidCurrentPassword: 'Password corrente non valida', + kanban: 'Kanban', labels: 'Etichette', language: 'Lingua', - leaveBoard_title: 'Lascia Bacheca', - leaveProject_title: 'Lascia Progetto', + leaveBoard_title: 'Abbandona bacheca', + leaveProject_title: 'Abbandona progetto', + limitCardTypesToDefaultOne: 'Limita i tipi di scheda a quello predefinito', list: 'Lista', - listActions_title: 'Lista delle Azioni', + lists: 'Liste', + listActions_title: 'Azioni lista', + makeProjectShared_title: 'Rendi progetto condiviso', managers: 'Managers', members: 'Membri', + memberActions_title: 'Azioni membro', minutes: 'Minuti', - moveCard_title: 'Sposta card', + moveCard_title: 'Sposta scheda', + myOwn_title: 'Personali', name: 'Nome', newestFirst: 'Dal più recente', newEmail: 'Nuova e-mail', newPassword: 'Nuova password', newUsername: 'Nuovo username', + newVersionAvailable: 'Nuova versione disponibile', noConnectionToServer: 'Nessuna connessione al server', - noBoards: 'No bacheche', - noLists: 'No liste', - noProjects: 'No progetti', + noBoards: 'Nessuna bacheca', + noLists: 'Nessuna lista', + noProjects: 'Nessun progetto', notifications: 'Notifiche', - noUnreadNotifications: 'Nessuna notifica non letta.', + noUnreadNotifications: 'Nessuna notifica da leggere.', oldestFirst: 'Dal meno recente', openBoard_title: 'Bacheca aperta', optional_inline: 'opzionale', organization: 'Organizazzione', + others: 'Altri', phone: 'Telefono', + plankaUsesAppriseToSendNotificationsToOver100PopularServices: + 'PLANKA utilizza <1><0>Apprise per inviare notifiche a oltre 100 servizi popolari.', preferences: 'Preferenze', pressPasteShortcutToAddAttachmentFromClipboard: 'Consiglio: premi Ctrl-V (Cmd-V on Mac) per aggiungere un allegato dalla clipboard.', + private: 'Privato', project: 'Progetto', projectNotFound_title: 'Progetto non trovato', - removeManager_title: 'Rimuovi Manager', - removeMember_title: 'Rimuovi Membro', - searchCards: 'Cerca cards...', + projectOwner: 'Proprietario del progetto', + referenceDataAndKnowledgeStorage: 'Dati di riferimento e di archiviazione', + removeManager_title: 'Rimuovi manager', + removeMember_title: 'Rimuovi membro', + role: 'Ruolo', + searchCards: 'Cerca schede...', + searchCustomFields: 'Cerca campi personalizzati...', + searchCustomFieldGroups: 'Cerca campi personalizzati...', searchLabels: 'Cerca etichette...', + searchLists: 'Cerca liste...', searchMembers: 'Cerca membri...', + searchProjects: 'Cerca progetti...', searchUsers: 'Cerca utenti...', seconds: 'Secondi', + selectAssignee_title: 'Seleziona assegnatario', selectBoard: 'Seleziona bacheca', selectList: 'Seleziona lista', - selectPermissions_title: 'Seleziona Permessi', + selectListToRestoreThisCard: 'Seleziona lista per ripristinare questa scheda', + selectOrder_title: 'Seleziona ordine', + selectPermissions_title: 'Seleziona permessi', selectProject: 'Seleziona progetto', + selectRole_title: 'Seleziona ruolo', + selectType_title: 'Seleziona tipo', + sequentialDisplayOfCards: 'Visualizzazione sequenziale delle schede', settings: 'Impostazioni', + shared: 'Condiviso', + sharedWithMe_title: 'Condiviso con me', + showOnFrontOfCard: 'Mostra davanti alla scheda', sortList_title: 'Ordina', stopwatch: 'Timer', - subscribeToMyOwnCardsByDefault: 'Abbonati alle mie card per impostazione predefinita', - taskActions_title: 'Task Azioni', + story: 'Storia', + subscribeToCardWhenCommenting: 'Iscrivimi alla scheda quando commento', + subscribeToMyOwnCardsByDefault: 'Abbonati alle mie scheda per impostazione predefinita', + taskActions_title: 'Azioni task', + taskAssignmentAndProjectCompletion: 'Assegnazione di task e completamento del progetto', + taskList_title: 'Lista di task', + taskListActions_title: 'Azioni lista di task', + team: 'Team', thereIsNoPreviewAvailableForThisAttachment: 'Non è disponibile alcuna anteprima per questo allegato.', time: 'Tempo', title: 'Titolo', - userActions_title: 'Azioni Utente', - userAddedThisCardToList: '<0>{{user}}<1> ha aggiunto questa card a {{list}}', + trash: 'Cestino', + trashHasBeenSuccessfullyEmptied: 'Il cestino è stato svuotato con successo.', + turnOffRecentCardHighlighting: "Disattiva l'evidenziazione delle scheda recenti", + typeNameToConfirm: 'Digita il nome per confermare', + typeTitleToConfirm: 'Digita il titolo per confermare', + unsavedChanges: 'Modifiche non salvate', + uploadedImages: 'Immagini caricate', + userActions_title: 'Azioni utente', + userAddedThisCardToList: '<0>{{user}}<1> ha aggiunto questa scheda a {{list}}', userLeftNewCommentToCard: - '{{user}} ha lasciato un nuovo commento «{{comment}}» a <2>{{card}}', - userMovedCardFromListToList: '{{user}} ha mosso <2>{{card}} da {{fromList}} a {{toList}}', + '{{user}} ha lasciato un commento «{{comment}}» a <2>{{scheda}}', + userMovedCardFromListToList: + '{{user}} ha spostato <2>{{scheda}} da {{fromList}} a {{toList}}', userMovedThisCardFromListToList: - '<0>{{user}}<1> ha mosso questa card da {{fromList}} a {{toList}}', + '<0>{{user}}<1> ha spostato questa scheda da {{fromList}} a {{toList}}', username: 'Username', users: 'Utenti', - viewer: 'Viewer', + viewer: 'Visualizzatore', + viewers: 'Visualizzatori', + visualTaskManagementWithLists: 'Gestione visiva dei task con liste', + withoutBaseGroup: 'Senza gruppo base', writeComment: 'Scrivi un commento...', }, action: { - addAnotherCard: "Aggiungi un'altra card", + activateUser: 'Attiva utente', + activateUser_title: 'Attiva utente', + addAnotherCard: "Aggiungi un'altra scheda", addAnotherList: "Aggiungi un'altra lista", addAnotherTask: 'Aggiungi un altro task', - addCard: 'Aggiungi card', - addCard_title: 'Aggiungi Card', + addCard: 'Aggiungi scheda', + addCard_title: 'Aggiungi scheda', addComment: 'Aggiungi commento', + addCustomField: 'Aggiungi campo personalizzato', + addCustomFieldGroup: 'Aggiungi campi personalizzati', addList: 'Aggiungi lista', - addMember: 'Add membro', + addMember: 'Aggiungi membro', addMoreDetailedDescription: 'Aggiungi una descrizione più dettagliata', addTask: 'Aggiungi task', - addToCard: 'Aggiungi alla card', + addTaskList: 'Aggiungi lista di task', + addToCard: 'Aggiungi alla scheda', addUser: 'Aggiungi utente', + archive: 'Archivia', + archiveCard: 'Archivia scheda', + archiveCard_title: 'Archivia scheda', + archiveCards: 'Archivia schede', + archiveCards_title: 'Archivia schede', + assignAsOwner: 'Assegna come proprietario', + cancel: 'Annulla', createBoard: 'Crea bacheca', + createCustomFieldGroup: 'Crea campi personalizzati', createFile: 'Crea file', createLabel: 'Crea etichetta', createNewLabel: 'Crea nuova etichetta', createProject: 'Crea progetto', + deactivateUser: 'Disattiva utente', delete: 'Elimina', deleteAttachment: 'Elimina allegato', deleteAvatar: 'Elimina avatar', + deleteBackgroundImage: 'Elimina immagine di sfondo', deleteBoard: 'Elimina bacheca', - deleteCard: 'Elimina card', - deleteCard_title: 'Elimina Card', + deleteBoard_title: 'Elimina bacheca', + deleteCard: 'Elimina scheda', + deleteCard_title: 'Elimina scheda', + deleteCardForever: 'Elimina scheda per sempre', deleteComment: 'Elimina commento', + deleteCustomField: 'Elimina campo personalizzato', + deleteCustomFieldGroup: 'Elimina campi personalizzati', + deleteForever_title: 'Elimina per sempre', + deleteGroup: 'Elimina gruppo', deleteLabel: 'Elimina etichetta', deleteList: 'Elimina lista', - deleteList_title: 'Elimina Lista', + deleteList_title: 'Elimina lista', + deleteNotificationService: 'Elimina servizio di notifica', deleteProject: 'Elimina progetto', - deleteProject_title: 'Elimina Progetto', + deleteProject_title: 'Elimina progetto', deleteTask: 'Elimina task', - deleteTask_title: 'Elimina Task', + deleteTask_title: 'Elimina task', deleteUser: 'Elimina utente', + deleteUser_title: 'Elimina utente', + dismissAll: 'Ignora tutto', duplicate: 'Duplica', - duplicateCard_title: 'Duplica Card', + duplicateCard_title: 'Duplica scheda', edit: 'Modifica', + editColor_title: 'Modifica colore', editDueDate_title: 'Modifica data di scadenza', - editDescription_title: 'Modifica Descrizione', - editEmail_title: 'Modifica E-mail', - editInformation_title: 'Modifca Informazioni', - editPassword_title: 'Modifica Password', + editDescription_title: 'Modifica descrizione', + editEmail_title: 'Modifica indirizzo e-mail', + editGroup: 'Modifica gruppo', + editInformation_title: 'Modifca informazioni', + editPassword_title: 'Modifica password', editPermissions: 'Modifica permessi', - editStopwatch_title: 'Modifica Timer', - editTitle_title: 'Modifica Titolo', - editUsername_title: 'Modifica Username', + editRole_title: 'Modifica ruolo', + editStopwatch_title: 'Modifica timer', + editTitle_title: 'Modifica titolo', + editType_title: 'Modifica tipo', + editUsername_title: 'Modifica username', + emptyTrash: 'Svuota cestino', + emptyTrash_title: 'Svuota cestino', import: 'Importa', - leaveBoard: 'Lascia bacheca', - leaveProject: 'Lascia progetto', + join: 'Entra', + leave: 'Abbandona', + leaveBoard: 'Abbandona bacheca', + leaveProject: 'Abbandona progetto', logOut_title: 'Disconnettiti', - makeCover_title: 'Crea Cover', + makeCover_title: 'Crea cover', + makeProjectShared: 'Rendi progetto condiviso', + makeProjectShared_title: 'Rendi progetto condiviso', move: 'Muovi', - moveCard_title: 'Muovi Card', + moveCard_title: 'Muovi scheda', remove: 'Rimuovi', - removeCover_title: 'Rimuovi Cover', + removeAssignee: 'Rimuovi assegnatario', + removeColor: 'Remove colore', + removeCover_title: 'Rimuovi copertina', removeFromBoard: 'Rimuovi dalla bacheca', - removeFromProject: 'Rimuovi dal Progetto', + removeFromProject: 'Rimuovi dal progetto', removeManager: 'Rimuovi manager', removeMember: 'Rimuovi membro', + restoreToList: 'Ripristina a {{list}}', + returnToBoard: 'Torna alla bacheca', save: 'Salva', - showAllAttachments: 'Mostra tutti gli allegati ({{hidden}} hidden)', + showActive: 'Mostra attivi', + showAllAttachments: 'Mostra tutti gli allegati ({{hidden}} nascosti)', + showCardsWithThisUser: 'Mostra schede con questo utente', + showDeactivated: 'Mostra disattivati', showFewerAttachments: 'Mostra meno allegati', sortList_title: 'Ordina', start: 'Inizio', - stop: 'Ferma', + stop: 'Interrompi', subscribe: 'Iscriviti', unsubscribe: 'Annulla iscrizione', uploadNewAvatar: 'Carica nuovo avatar', diff --git a/client/src/locales/it-IT/login.js b/client/src/locales/it-IT/login.js index fddd9ff6..d8aa8290 100644 --- a/client/src/locales/it-IT/login.js +++ b/client/src/locales/it-IT/login.js @@ -1,20 +1,26 @@ export default { translation: { common: { + activeUsersLimitReached: 'Limite utenti attivi raggiunto', emailAlreadyInUse: 'E-mail già in uso', emailOrUsername: 'E-mail o username', + invalidCredentials: 'Credenziali non valide', invalidEmailOrUsername: 'E-mail o username non valido', invalidPassword: 'Password non valida', + logIn_title: 'Accedi', noInternetConnection: 'Nessuna connessione internet', + or: 'Oppure', pageNotFound_title: 'Pagina non trovata', password: 'Password', + poweredByPlanka: 'Powered by Planka', serverConnectionFailed: 'Connesione al server fallita', unknownError: 'Errore sconosciuto, prova ancora', usernameAlreadyInUse: 'Username già in uso', + useSingleSignOn: 'Accedi con SSO', }, action: { - logIn: 'Log in', + logIn: 'Accedi', }, }, }; From e03f3d1c949876a3a736e84c99c62cbd9d6b83fe Mon Sep 17 00:00:00 2001 From: "Viktor S." <134023943+spokeswamp@users.noreply.github.com> Date: Sat, 10 May 2025 19:57:12 +0300 Subject: [PATCH 003/121] fix: Update Russian translation (#1115) --- client/src/locales/ru-RU/core.js | 189 +++++++++++++++++- client/src/locales/ru-RU/login.js | 4 + client/src/locales/ru-RU/markdown-editor.json | 165 +++++++++++++++ 3 files changed, 352 insertions(+), 6 deletions(-) create mode 100644 client/src/locales/ru-RU/markdown-editor.json diff --git a/client/src/locales/ru-RU/core.js b/client/src/locales/ru-RU/core.js index 2eaeca4e..35aa094c 100644 --- a/client/src/locales/ru-RU/core.js +++ b/client/src/locales/ru-RU/core.js @@ -1,9 +1,11 @@ import dateFns from 'date-fns/locale/ru'; import timeAgo from 'javascript-time-ago/locale/ru'; +import markdownEditor from './markdown-editor.json'; export default { dateFns, timeAgo, + markdownEditor, format: { date: 'P', @@ -20,73 +22,159 @@ export default { aboutPlanka: 'О проекте PLANKA', account: 'Учетная запись', actions: 'Действия', + activateUser_title: 'Активировать пользователя', + active: 'Активен', addAttachment_title: 'Добавление вложения', + addCustomField_title: 'Добавить настраиваемое поле', + addCustomFieldGroup_title: 'Добавить группу настраиваемых полей', addManager_title: 'Добавление менеджера', addMember_title: 'Добавление участника', + addTaskList_title: 'Добавить список задач', addUser_title: 'Добавление пользователя', + admin: 'Админ', + administration: 'Администрирование', all: 'Все', allChangesWillBeAutomaticallySavedAfterConnectionRestored: 'Все изменения сохранятся автоматически,
как только подключение восстановится.', + alphabetically: 'По алфавиту', + alwaysDisplayCardCreator: 'Всегда отображать создателя карточек', + archive: 'Архив', + archiveCard_title: 'Архивировать карточку', + archiveCards_title: 'Архивировать карточки', + areYouSureYouWantToActivateThisUser: + 'Вы уверены, что хотите активировать этого пользователя?', + areYouSureYouWantToArchiveCards: 'Вы уверены, что хотите архивировать карточки?', + areYouSureYouWantToArchiveThisCard: 'Вы уверены, что хотите архивировать эту карточку?', + areYouSureYouWantToAssignThisProjectManagerAsOwner: + 'Вы уверены, что хотите назначить этого менеджера проекта владельцем?', + areYouSureYouWantToDeactivateThisUser: + 'Вы уверены, что хотите деактивировать этого пользователя?', areYouSureYouWantToDeleteThisAttachment: 'Вы уверены, что хотите удалить это вложение?', + areYouSureYouWantToDeleteThisBackgroundImage: + 'Вы уверены, что хотите удалить этот фоновый рисунок?', areYouSureYouWantToDeleteThisBoard: 'Вы уверены, что хотите удалить эту доску?', areYouSureYouWantToDeleteThisCard: 'Вы уверены, что хотите удалить эту карточку?', + areYouSureYouWantToDeleteThisCardForever: + 'Вы уверены, что хотите навсегда удалить эту карточку?', areYouSureYouWantToDeleteThisComment: 'Вы уверены, что хотите удалить этот комментарий?', + areYouSureYouWantToDeleteThisCustomField: + 'Вы уверены, что хотите удалить это настраиваемое поле?', + areYouSureYouWantToDeleteThisCustomFieldGroup: + 'Вы уверены, что хотите удалить эту группу настраиваемых полей?', areYouSureYouWantToDeleteThisLabel: 'Вы уверены, что хотите удалить эту метку?', areYouSureYouWantToDeleteThisList: 'Вы уверены, что хотите удалить этот список?', + areYouSureYouWantToDeleteThisNotificationService: + 'Вы уверены, что хотите удалить этот сервис уведомлений?', areYouSureYouWantToDeleteThisProject: 'Вы уверены, что хотите удалить этот проект?', areYouSureYouWantToDeleteThisTask: 'Вы уверены, что хотите удалить эту задачу?', + areYouSureYouWantToDeleteThisTaskList: 'Вы уверены, что хотите удалить этот список задач?', areYouSureYouWantToDeleteThisUser: 'Вы уверены, что хотите удалить этого пользователя?', + areYouSureYouWantToEmptyTrash: 'Вы уверены, что хотите очистить корзину?', areYouSureYouWantToLeaveBoard: 'Вы уверены, что хотите покинуть эту доску?', areYouSureYouWantToLeaveProject: 'Вы уверены, что хотите покинуть этот проект?', + areYouSureYouWantToMakeThisProjectShared: 'Вы уверены, что хотите сделать этот проект общим?', areYouSureYouWantToRemoveThisManagerFromProject: 'Вы уверены, что хотите удалить этого менеджера из проекта?', areYouSureYouWantToRemoveThisMemberFromBoard: 'Вы уверены, что хотите удалить этого участника из доски?', + assignAsOwner_title: 'Назначить владельцем', + atLeastOneListMustBePresent: 'Должен быть хотя бы один список', attachment: 'Вложение', attachments: 'Вложения', authentication: 'Аутентификация', background: 'Фон', + baseCustomFields_title: 'Основные настраиваемые поля', + baseGroup: 'Основная группа', board: 'Доска', + boardActions_title: 'Действия с доской', boardNotFound_title: 'Доска не найдена', + boardSubscribed: 'Подписан на доску', + boardUser: 'Пользователь доски', + byCreationTime: 'По времени создания', + byDefault: 'По умолчанию', + byDueDate: 'По дате выполнения', + canBeInvitedToWorkInBoards: 'Может быть приглашен для работы на досках.', canComment: 'Может комментировать', + canCreateOwnProjectsAndBeInvitedToWorkInOthers: + 'Может создавать собственные проекты и быть приглашенным работать в других.', + canEditBoardLayoutAndAssignMembersToCards: + 'Может редактировать макет доски и назначать участников для карточек.', + canManageSystemWideSettingsAndActAsProjectOwner: + 'Может управлять глобальными настройками системы и выступать в роли владельца проекта.', canOnlyViewBoard: 'Может только просматривать доску.', cardActions_title: 'Действия с карточкой', cardNotFound_title: 'Карточка не найдена', + cardsOnThisListAreAvailableToAllBoardMembers: + 'Карточки в этом списке доступны всем членам доски.', + cardsOnThisListAreCompleteAndReadyToBeArchived: + 'Карточки в этом списке завершены и готовы к архивированию.', + cardsOnThisListAreReadyToBeWorkedOn: 'Карточки в этом списке готовы к работе.', + clickHereOrRefreshPageToUpdate: '<0>Нажмите здесь или обновите страницу для обновления.', + closed: 'Закрыто', color: 'Цвет', + comments: 'Комментарии', + contentExceedsLimit: 'Содержимое превышает {{limit}}', copy_inline: 'копия', createBoard_title: 'Создание доски', + createCustomFieldGroup_title: 'Создать группу настраиваемых полей', createLabel_title: 'Создание метки', createNewOneOrSelectExistingOne: 'Создайте новую или выберите
уже существующую.', createProject_title: 'Создание проекта', createTextFile_title: 'Создание текстового файла', + creator: 'Создатель', currentPassword: 'Текущий пароль', + customField_title: 'Настраиваемое поле', + customFieldGroup_title: 'Группа настраиваемых полей', + customFieldGroups_title: 'Группы настраиваемых полей', + customFields_title: 'Настраиваемые поля', dangerZone_title: 'Опасная зона', date: 'Дата', - dueDate_title: 'Срок исполнения', + deactivateUser_title: 'Деактивировать пользователя', + defaultCardType_title: 'Тип карточки по умолчанию', + defaultView_title: 'Вид по умолчанию', + deleteAllBoardsToBeAbleToDeleteThisProject: + 'Удалите все доски, чтобы иметь возможность удалить этот проект', deleteAttachment_title: 'Удаление вложения', + deleteBackgroundImage_title: 'Удалить фоновое изображение', deleteBoard_title: 'Удаление доски', deleteCard_title: 'Удаление карточки', + deleteCardForever_title: 'Удалить карточку навсегда', deleteComment_title: 'Удаление комментария', + deleteCustomField_title: 'Удалить настраиваемое поле', + deleteCustomFieldGroup_title: 'Удалить группу настраиваемых полей', + deletedUser_title: 'Удалённый пользователь', deleteLabel_title: 'Удаление метки', deleteList_title: 'Удаление списка', + deleteNotificationService_title: 'Удалить сервис уведомлений', deleteProject_title: 'Удаление проекта', deleteTask_title: 'Удаление задачи', + deleteTaskList_title: 'Удалить список задач', deleteUser_title: 'Удаление пользователя', description: 'Описание', detectAutomatically: 'Определить автоматически', + display: 'Отображение', dropFileToUpload: 'Перетяните файл, чтобы загрузить', - editor: 'Редактор', + dueDate_title: 'Срок исполнения', + dynamicAndUnevenlySpacedLayout: 'Динамичное и неравномерно распределённое расположение', editAttachment_title: 'Изменение вложения', editAvatar_title: 'Изменение аватара', + editColor_title: 'Изменить цвет', + editCustomField_title: 'Изменить настраиваемое поле', + editCustomFieldGroup_title: 'Изменить группу настраиваемых полей', editDueDate_title: 'Изменить срок выполнения', editEmail_title: 'Изменение e-mail', editInformation_title: 'Изменение информации', editLabel_title: 'Изменение метки', + editor: 'Редактор', + editors: 'Редакторы', editPassword_title: 'Изменение пароля', editPermissions_title: 'Редактирование разрешений', + editRole_title: 'Изменить роль', editStopwatch_title: 'Изменение секундомера', + editType_title: 'Изменить тип', editUsername_title: 'Изменение имени пользователя', email: 'E-mail', + emptyTrash_title: 'Очистить корзину', enterCardTitle: 'Введите заголовок для этой карточки...', enterDescription: 'Введите описание...', enterFilename: 'Введите название файла', @@ -94,30 +182,41 @@ export default { enterTaskDescription: 'Введите описание задачи...', filterByLabels_title: 'Фильтр по меткам', filterByMembers_title: 'Фильтр по участникам', + forPersonalProjects: 'Для личных проектов', + forTeamBasedProjects: 'Для командных проектов', fromComputer_title: 'С компьютера', fromTrello: 'Из Trello', general: 'Основные', + gradients: 'Градиенты', + grid: 'Сетка', + hideFromProjectListAndFavorites: 'Скрыть из списка проектов и избранного', hours: 'Часы', importBoard_title: 'Импорт доски', invalidCurrentPassword: 'Неверный текущий пароль', + kanban: 'Канбан', labels: 'Метки', language: 'Язык', leaveBoard_title: 'Покинуть доску', leaveProject_title: 'Покинуть проект', + limitCardTypesToDefaultOne: 'Разрешён только тип карточки по умолчанию', list: 'Список', listActions_title: 'Действия со списком', + lists: 'Списки', + makeProjectShared_title: 'Сделать проект общим', managers: 'Менеджеры', - members: 'Участники', memberActions_title: 'Действия участников', + members: 'Участники', minutes: 'Минуты', moveCard_title: 'Перемещение карточки', + myOwn_title: 'Мой собственный', name: 'Имя', - newestFirst: 'Новые первые', newEmail: 'Новый e-mail', + newestFirst: 'Новые первые', newPassword: 'Новый пароль', newUsername: 'Новое имя пользователя', - noConnectionToServer: 'Нет соединения с сервером', + newVersionAvailable: 'Доступна новая версия', noBoards: 'Досок нет', + noConnectionToServer: 'Нет соединения с сервером', noLists: 'Списков нет', noProjects: 'Проектов нет', notifications: 'Уведомления', @@ -126,31 +225,64 @@ export default { openBoard_title: 'Откройте доску', optional_inline: 'необязательно', organization: 'Организация', + others: 'Другие', phone: 'Телефон', + plankaUsesAppriseToSendNotificationsToOver100PopularServices: + 'PLANKA использует <1><0>Apprise для отправки уведомлений в более чем 100 популярных сервисов.', preferences: 'Предпочтения', pressPasteShortcutToAddAttachmentFromClipboard: 'Совет: нажмите Ctrl-V (Cmd-V на Mac), чтобы добавить вложение из буфера обмена.', + private: 'Частный', project: 'Проект', projectNotFound_title: 'Проект не найден', + projectOwner: 'Владелец проекта', + referenceDataAndKnowledgeStorage: 'Хранение справочных данных и знаний', removeManager_title: 'Удалить менеджера', removeMember_title: 'Удаление участника', + role: 'Роль', searchCards: 'Поиск карточек...', + searchCustomFieldGroups: 'Поиск групп настраиваемых полей...', + searchCustomFields: 'Поиск настраиваемых полей...', searchLabels: 'Поиск меток...', + searchLists: 'Поиск списков...', searchMembers: 'Поиск участников...', + searchProjects: 'Поиск проектов...', searchUsers: 'Поиск пользователей...', seconds: 'Секунды', + selectAssignee_title: 'Выбрать исполнителя', selectBoard: 'Выберите доску', selectList: 'Выберите список', + selectListToRestoreThisCard: 'Выберите список для восстановления этой карточки', + selectOrder_title: 'Выбрать порядок', selectPermissions_title: 'Выбор разрешений', selectProject: 'Выберите проект', + selectRole_title: 'Выбрать роль', + selectType_title: 'Выбрать тип', + sequentialDisplayOfCards: 'Последовательное отображение карточек', settings: 'Настройки', + shared: 'Общий', + sharedWithMe_title: 'Общий со мной', + showOnFrontOfCard: 'Показать на лицевой стороне карточки', sortList_title: 'Сортировка списка', stopwatch: 'Секундомер', + story: 'История', + subscribeToCardWhenCommenting: 'Подписаться на карточку при комментировании', subscribeToMyOwnCardsByDefault: 'По умолчанию подписываться на мои собственные карточки', taskActions_title: 'Действия по задаче', + taskAssignmentAndProjectCompletion: 'Назначение задач и завершение проекта', + taskList_title: 'Список задач', + taskListActions_title: 'Действия с списком задач', + team: 'Команда', thereIsNoPreviewAvailableForThisAttachment: 'Предпросмотр для этого вложения недоступен.', time: 'Время', title: 'Название', + trash: 'Корзина', + trashHasBeenSuccessfullyEmptied: 'Корзина успешно очищена', + turnOffRecentCardHighlighting: 'Выключить подсветку последних карточек', + typeNameToConfirm: 'Введите имя для подтверждения', + typeTitleToConfirm: 'Введите название для подтверждения', + unsavedChanges: 'Несохранённые изменения', + uploadedImages: 'Загруженные изображения', userActions_title: 'Действия с пользователем', userAddedThisCardToList: '<0>{{user}}<1> добавил(а) эту карточку в {{list}}', userLeftNewCommentToCard: '{{user}} оставил(а) комментарий «{{comment}}» к <2>{{card}}', @@ -161,70 +293,115 @@ export default { username: 'Имя пользователя', users: 'Пользователи', viewer: 'Читатель', + viewers: 'Читатели', + visualTaskManagementWithLists: 'Визуальное управление задачами с помощью списков', + withoutBaseGroup: 'Без основной группы', writeComment: 'Напишите комментарий...', }, action: { + activateUser: 'Активировать пользователя', + activateUser_title: 'Активировать пользователя', addAnotherCard: 'Добавить еще одну карточку', addAnotherList: 'Добавить еще один список', addAnotherTask: 'Добавить еще одну задачу', addCard: 'Добавить карточку', addCard_title: 'Добавить карточку', addComment: 'Добавить комментарий', + addCustomField: 'Добавить настраиваемое поле', + addCustomFieldGroup: 'Добавить группу настраиваемых полей', addList: 'Добавить список', addMember: 'Добавить участника', addMoreDetailedDescription: 'Добавить более подробное описание', addTask: 'Добавить задачу', + addTaskList: 'Добавить список задач', addToCard: 'Добавить на карточку', addUser: 'Добавить пользователя', + archive: 'Архив', + archiveCard: 'Архивировать карточку', + archiveCard_title: 'Архивировать карточку', + archiveCards: 'Архивировать карточки', + archiveCards_title: 'Архивировать карточки', + assignAsOwner: 'Назначить владельцем', + cancel: 'Отменить', createBoard: 'Создать доску', + createCustomFieldGroup: 'Создать группу настраиваемых полей', createFile: 'Создать файл', createLabel: 'Создать метку', createNewLabel: 'Создать новую метку', createProject: 'Создать проект', + deactivateUser: 'Деактивировать пользователя', + deactivateUser_title: 'Деактивировать пользователя', delete: 'Удалить', deleteAttachment: 'Удалить вложение', deleteAvatar: 'Удалить аватар', + deleteBackgroundImage: 'Удалить фоновое изображение', deleteBoard: 'Удалить доску', + deleteBoard_title: 'Удалить доску', deleteCard: 'Удалить карточку', deleteCard_title: 'Удалить карточку', + deleteCardForever: 'Удалить карточку навсегда', deleteComment: 'Удалить комментарий', + deleteCustomField: 'Удалить настраиваемое поле', + deleteCustomFieldGroup: 'Удалить группу настраиваемых полей', + deleteForever_title: 'Удалить навсегда', + deleteGroup: 'Удалить группу', deleteLabel: 'Удалить метку', deleteList: 'Удалить список', deleteList_title: 'Удалить список', + deleteNotificationService: 'Удалить сервис уведомлений', deleteProject: 'Удалить проект', deleteProject_title: 'Удалить проект', deleteTask: 'Удалить задачу', deleteTask_title: 'Удалить задачу', + deleteTaskList: 'Удалить список задач', deleteUser: 'Удалить пользователя', + deleteUser_title: 'Удалить пользователя', dismissAll: 'Отклонить все', duplicate: 'Дублировать', duplicateCard_title: 'Дублировать карточку', edit: 'Изменить', - editDueDate_title: 'Изменить срок', + editColor_title: 'Изменить цвет', editDescription_title: 'Изменить описание', + editDueDate_title: 'Изменить срок', editEmail_title: 'Изменить e-mail', + editGroup: 'Изменить группу', editInformation_title: 'Изменить информацию', editPassword_title: 'Изменить пароль', editPermissions: 'Изменить разрешения', + editRole_title: 'Изменить роль', editStopwatch_title: 'Изменить секундомер', editTitle_title: 'Изменить название', + editType_title: 'Изменить тип', editUsername_title: 'Изменить имя пользователя', + emptyTrash: 'Очистить корзину', + emptyTrash_title: 'Очистить корзину', import: 'Импорт', + join: 'Присоединиться', + leave: 'Покинуть', leaveBoard: 'Покинуть доску', leaveProject: 'Покинуть проект', logOut_title: 'Выйти', makeCover_title: 'Сделать обложкой', + makeProjectShared: 'Сделать проект общим', + makeProjectShared_title: 'Сделать проект общим', move: 'Переместить', moveCard_title: 'Переместить карточку', remove: 'Убрать', + removeAssignee: 'Удалить исполнителя', + removeColor: 'Удалить цвет', removeCover_title: 'Убрать обложку', removeFromBoard: 'Удалить из доски', removeFromProject: 'Удалить из проекта', removeManager: 'Удалить менеджера', removeMember: 'Удалить участника', + restoreToList: 'Восстановить в {{list}}', + returnToBoard: 'Вернуться на доску', save: 'Сохранить', + showActive: 'Показать активные', showAllAttachments: 'Показать все вложения ({{hidden}} скрыто)', + showCardsWithThisUser: 'Показать карточки с этим пользователем', + showDeactivated: 'Показать деактивированные', showFewerAttachments: 'Показать меньше вложений', sortList_title: 'Сортировать список', start: 'Начать', diff --git a/client/src/locales/ru-RU/login.js b/client/src/locales/ru-RU/login.js index 336405af..b1215b05 100644 --- a/client/src/locales/ru-RU/login.js +++ b/client/src/locales/ru-RU/login.js @@ -1,14 +1,18 @@ export default { translation: { common: { + activeUsersLimitReached: 'Достигнут лимит активных пользователей', emailAlreadyInUse: 'E-mail уже занят', emailOrUsername: 'E-mail или имя пользователя', invalidCredentials: 'Недействительные учетные данные', invalidEmailOrUsername: 'Неверный e-mail или имя пользователя', invalidPassword: 'Неверный пароль', + logIn_title: 'Войти', noInternetConnection: 'Нет соединения', + or: 'Или', pageNotFound_title: 'Страница не найдена', password: 'Пароль', + poweredByPlanka: 'Powered by PLANKA', serverConnectionFailed: 'Не могу подключиться к серверу', unknownError: 'Что-то пошло не так, попробуйте позже', usernameAlreadyInUse: 'Имя пользователя уже занято', diff --git a/client/src/locales/ru-RU/markdown-editor.json b/client/src/locales/ru-RU/markdown-editor.json new file mode 100644 index 00000000..0beafbbf --- /dev/null +++ b/client/src/locales/ru-RU/markdown-editor.json @@ -0,0 +1,165 @@ +{ + "action-previews": { + "text": "Это текст без заголовка.\nКак заголовок, так и текст\nмогут быть выделены жирным, курсивом, цветом,\nзачеркнутым и подчеркнутым.", + "text-with-head": "Это текст с заголовком.\nКак заголовок, так и текст\nмогут быть выделены жирным, курсивом, цветом,\nзачеркнутым и подчеркнутым.", + "heading": "Заголовок" + }, + "bundle": { + "error-title": "Ошибка в редакторе markdown", + "settings_wysiwyg": "Визуальный редактор (wysiwyg)", + "settings_markup": "Разметка Markdown", + "markup_placeholder": "Введите разметку markdown..." + }, + "codeblock": { + "remove": "Удалить", + "empty_option": "Совпадений не найдено" + }, + "common": { + "delete": "Удалить", + "edit": "Редактировать", + "toolbar_action_disabled": "Несовместимый элемент разметки" + }, + "forms": { + "common_action_cancel": "Отмена", + "common_action_submit": "Отправить", + "common_action_upload": "Выбрать", + "common_tab_attach": "Добавить с устройства", + "common_tab_link": "Добавить по ссылке", + "common_link": "Ссылка", + "common_sizes": "Размер, px", + "image_name": "Заголовок", + "image_link_href": "Ссылка на изображение", + "image_link_href_help": "Адрес, на который ведет ссылка на изображение.", + "image_alt": "Alt текст", + "image_alt_help": "Alt текст отображается, если изображение не может быть загружено.", + "image_upload_help": "Изображение в формате JPEG, GIF или PNG размером не более 1 МБ.", + "image_upload_failed": "Не удалось добавить изображение", + "image_size_width": "Ширина", + "image_size_height": "Высота", + "link_url_help": "Адрес, на который ведет ссылка.", + "link_text": "Текст ссылки", + "link_text_help": "Текст, отображаемый как ссылка.", + "link_open_help": "Открыть ссылку в новой вкладке" + }, + "md-hints": { + "header_title": "Заголовок", + "header_hint": "# Ваш текст", + "italic_title": "Курсив", + "italic_hint": "_Ваш текст_", + "bold_title": "Жирный", + "bold_hint": "**Ваш текст**", + "strikethrough_title": "Зачеркнутый", + "strikethrough_hint": "~~Ваш текст~~", + "blockquote_title": "Цитата", + "blockquote_hint": "> Ваш текст", + "code_title": "Код", + "code_hint": "```Ваш текст```", + "link_title": "Ссылка", + "link_hint": "[Ваш текст](url)", + "image_title": "Изображение", + "image_hint": "![Ваш текст](url)", + "list_title": "Элемент списка", + "list_hint": "- Ваш текст", + "numbered-list_title": "Нумерованный список", + "numbered-list_hint": "1. Ваш текст", + "documentation": "Документация", + "documentation_link": " https://diplodoc.com/docs/en/syntax/" + }, + "menubar": { + "bold": "Жирный", + "code": "Код", + "code_inline": "Встроенный код", + "codeblock": "Блок кода", + "colorify": "Цвет текста", + "colorify__color_blue": "Синий", + "colorify__color_default": "По умолчанию", + "colorify__color_gray": "Серый", + "colorify__color_green": "Зеленый", + "colorify__color_orange": "Оранжевый", + "colorify__color_red": "Красный", + "colorify__color_violet": "Фиолетовый", + "colorify__color_yellow": "Желтый", + "colorify__group_text": "Текст", + "cut": "Вырезать", + "emoji": "Эмодзи", + "emoji__hint": "Эмодзи можно добавить в WYSIWYG или вручную с разметкой", + "heading": "Заголовок", + "heading1": "Заголовок 1", + "heading2": "Заголовок 2", + "heading3": "Заголовок 3", + "heading4": "Заголовок 4", + "heading5": "Заголовок 5", + "heading6": "Заголовок 6", + "hrule": "Разделитель", + "image": "Изображение", + "italic": "Курсив", + "link": "Ссылка", + "list": "Список", + "list__action_lift": "Поднять элемент", + "list__action_sink": "Опустить элемент", + "list_action_disabled": "Противоречит логике списка", + "mark": "Выделить", + "mono": "Моноширинный", + "more_action": "Больше действий", + "note": "Заметка", + "olist": "Упорядоченный список", + "quote": "Цитата", + "redo": "Повторить", + "strike": "Зачеркнутый", + "table": "Таблица", + "text": "Текст", + "ulist": "Маркированный список", + "underline": "Подчеркнутый", + "undo": "Отменить" + }, + "placeholder": { + "doc_empty": "Введите / для использования команд через слэш...", + "checkbox": "Введите описание задачи...", + "deflist_term": "Термин", + "deflist_desc": "Описание термина", + "heading": "Заголовок", + "cut_title": "Заголовок", + "cut_content": "Содержимое для отображения по клику", + "note_title": "Заголовок", + "note_content": "Содержание заметки", + "table_cell": "Содержимое ячейки", + "select_filter": "Поиск языков..." + }, + "search": { + "label_case-sensitive": "Чувствительность к регистру", + "label_whole-word": "Полное слово", + "title": "Поиск в коде" + }, + "suggest": { + "empty-msg": "Не найдено" + }, + "widgets": { + "image": "Добавить изображение", + "link": "Добавить ссылку" + }, + "yfm-note": { + "info": "Информация", + "tip": "Совет", + "warning": "Предупреждение", + "alert": "Предупреждение", + "remove": "Удалить" + }, + "yfm-table": { + "column.add.before": "Добавить колонку перед", + "column.add.after": "Добавить колонку после", + "column.remove": "Удалить колонку", + "row.add.before": "Добавить строку перед", + "row.add.after": "Добавить строку после", + "row.remove": "Удалить строку", + "table.remove": "Удалить таблицу", + "table.menu.cell.align.left": "Выравнять содержимое ячейки по левому краю", + "table.menu.cell.align.right": "Выравнять содержимое ячейки по правому краю", + "table.menu.cell.align.center": "Выравнять содержимое ячейки по центру", + "table.menu.row.add": "Добавить строку после", + "table.menu.row.remove": "Удалить строку", + "table.menu.column.add": "Добавить колонку после", + "table.menu.column.remove": "Удалить колонку", + "table.menu.convert.yfm": "Преобразовать в таблицу YFM", + "table.menu.table.remove": "Удалить таблицу" + } +} From fa02d96a2e88bed26fb43dbbe0fa11c62086366c Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 10 May 2025 21:15:19 +0200 Subject: [PATCH 004/121] test: Rename config file to match case --- client/tests/acceptance/{config.js => Config.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/tests/acceptance/{config.js => Config.js} (100%) diff --git a/client/tests/acceptance/config.js b/client/tests/acceptance/Config.js similarity index 100% rename from client/tests/acceptance/config.js rename to client/tests/acceptance/Config.js From dd8cd2f4fdc49bd4fd0022ad75966faa23119a18 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 10 May 2025 21:45:31 +0200 Subject: [PATCH 005/121] chore: Bump vite to version 6 --- client/package-lock.json | 368 +++++++++++++++++++++++++-------------- client/package.json | 2 +- client/vite.config.js | 7 - 3 files changed, 240 insertions(+), 137 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index a897008c..924bb434 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -82,7 +82,7 @@ "semantic-ui-react": "^2.1.5", "socket.io-client": "^2.5.0", "validator": "^13.15.0", - "vite": "^5.4.19", + "vite": "^6.3.5", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-node-polyfills": "^0.23.0", "vite-plugin-svgr": "^4.3.0", @@ -2592,9 +2592,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", "cpu": [ "ppc64" ], @@ -2603,13 +2603,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", "cpu": [ "arm" ], @@ -2618,13 +2618,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", "cpu": [ "arm64" ], @@ -2633,13 +2633,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", "cpu": [ "x64" ], @@ -2648,13 +2648,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", "cpu": [ "arm64" ], @@ -2663,13 +2663,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", "cpu": [ "x64" ], @@ -2678,13 +2678,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", "cpu": [ "arm64" ], @@ -2693,13 +2693,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", "cpu": [ "x64" ], @@ -2708,13 +2708,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", "cpu": [ "arm" ], @@ -2723,13 +2723,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", "cpu": [ "arm64" ], @@ -2738,13 +2738,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", "cpu": [ "ia32" ], @@ -2753,13 +2753,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", "cpu": [ "loong64" ], @@ -2768,13 +2768,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", "cpu": [ "mips64el" ], @@ -2783,13 +2783,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", "cpu": [ "ppc64" ], @@ -2798,13 +2798,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", "cpu": [ "riscv64" ], @@ -2813,13 +2813,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", "cpu": [ "s390x" ], @@ -2828,13 +2828,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", "cpu": [ "x64" ], @@ -2843,13 +2843,28 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", "cpu": [ "x64" ], @@ -2858,13 +2873,28 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", "cpu": [ "x64" ], @@ -2873,13 +2903,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", "cpu": [ "x64" ], @@ -2888,13 +2918,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", "cpu": [ "arm64" ], @@ -2903,13 +2933,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", "cpu": [ "ia32" ], @@ -2918,13 +2948,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", "cpu": [ "x64" ], @@ -2933,7 +2963,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -6964,40 +6994,42 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" } }, "node_modules/escalade": { @@ -14340,6 +14372,45 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -14858,19 +14929,22 @@ "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" }, "node_modules/vite": { - "version": "5.4.19", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", - "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -14879,19 +14953,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -14912,6 +14992,12 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, @@ -14964,6 +15050,30 @@ "vite": ">=2.6.0" } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", diff --git a/client/package.json b/client/package.json index 29f3df8b..18991335 100755 --- a/client/package.json +++ b/client/package.json @@ -153,7 +153,7 @@ "semantic-ui-react": "^2.1.5", "socket.io-client": "^2.5.0", "validator": "^13.15.0", - "vite": "^5.4.19", + "vite": "^6.3.5", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-node-polyfills": "^0.23.0", "vite-plugin-svgr": "^4.3.0", diff --git a/client/vite.config.js b/client/vite.config.js index ad203f24..231cd045 100644 --- a/client/vite.config.js +++ b/client/vite.config.js @@ -21,13 +21,6 @@ export default defineConfig({ 'source-map-js': 'source-map', }, }, - css: { - preprocessorOptions: { - scss: { - api: 'modern-compiler', - }, - }, - }, server: { port: 3000, open: true, From 9b32249e9fc3e22bbba8e44d6feb10346d2fea46 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 10 May 2025 21:55:03 +0200 Subject: [PATCH 006/121] build: Suppress npm update notifier --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 349c5ad1..a7d03143 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,7 +34,8 @@ COPY --chown=node:node server . RUN python3 -m venv .venv \ && .venv/bin/pip3 install -r requirements.txt --no-cache-dir \ - && mv .env.sample .env + && mv .env.sample .env \ + && npm config set update-notifier false COPY --from=server-dependencies --chown=node:node /app/node_modules node_modules From 1b583890cb30bbb2f83c8384969b86fc8203091e Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 10 May 2025 23:11:44 +0200 Subject: [PATCH 007/121] docs: Fix number of notification providers --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 388fc3dd..76898085 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - **Collaborative Kanban Boards**: Create projects, boards, lists, cards, and manage tasks with an intuitive drag-and-drop interface - **Real-Time Updates**: Instant syncing across all users, no refresh needed - **Rich Markdown Support**: Write beautifully formatted card descriptions with a powerful markdown editor -- **Flexible Notifications**: Get alerts through 140+ providers, fully customizable to your workflow +- **Flexible Notifications**: Get alerts through 100+ providers, fully customizable to your workflow - **Seamless Authentication**: Single sign-on with OpenID Connect integration - **Multilingual & Easy to Translate**: Full internationalization support for a global audience From 307f4b1d01de89ca82d3109a29f8d383ebb3cefc Mon Sep 17 00:00:00 2001 From: leroyloren <57643470+leroyloren@users.noreply.github.com> Date: Mon, 12 May 2025 11:35:52 +0200 Subject: [PATCH 008/121] fix: Update Czech translation (#1120) --- client/src/locales/cs-CZ/core.js | 209 +++++++++++++++++++++++++++--- client/src/locales/cs-CZ/login.js | 4 + 2 files changed, 193 insertions(+), 20 deletions(-) diff --git a/client/src/locales/cs-CZ/core.js b/client/src/locales/cs-CZ/core.js index 00432671..ec9911af 100644 --- a/client/src/locales/cs-CZ/core.js +++ b/client/src/locales/cs-CZ/core.js @@ -20,208 +20,377 @@ export default { aboutPlanka: 'O aplikaci PLANKA', account: 'Účet', actions: 'Akce', + activateUser_title: 'Aktivovat uživatele', + active: 'Aktivní', addAttachment_title: 'Přidat přílohu', + addCustomField_title: 'Přidat vlastní pole', + addCustomFieldGroup_title: 'Přidat vlastní skupinu polí', addManager_title: 'Přidat vedoucího', addMember_title: 'Přidat člena', + addTaskList_title: 'Přidat seznam úkolů', addUser_title: 'Přidat uživatele', + admin: 'Admin', + administration: 'Správa', all: 'Vše', allChangesWillBeAutomaticallySavedAfterConnectionRestored: - 'Všechny změny budou automaticky uloženy
po obnově spojení.', + 'Všechny změny budou automaticky uloženy
po obnovení spojení.', + alphabetically: 'Abecedně', + alwaysDisplayCardCreator: 'Vždy zobrazit tvůrce karty', + archive: 'Archivovat', + archiveCard_title: 'Archivovat kartu', + archiveCards_title: 'Archiv karet', + areYouSureYouWantToActivateThisUser: 'Opravdu chcete tohoto uživatele aktivovat?', + areYouSureYouWantToArchiveCards: 'Opravdu chcete archivovat karty?', + areYouSureYouWantToArchiveThisCard: 'Opravdu chcete archivovat tuto kartu?', + areYouSureYouWantToAssignThisProjectManagerAsOwner: + 'Opravdu chcete přiřadit tohoto projektového manažera jako vlastníka?', + areYouSureYouWantToDeactivateThisUser: 'Opravdu chcete deaktivovat tohoto uživatele?', areYouSureYouWantToDeleteThisAttachment: 'Opravdu chcete smazat tuto přílohu?', + areYouSureYouWantToDeleteThisBackgroundImage: + 'Opravdu chcete tento obrázek na pozadí odstranit?', areYouSureYouWantToDeleteThisBoard: 'Opravdu chcete smazat tuto tabuli?', areYouSureYouWantToDeleteThisCard: 'Opravdu chcete smazat tuto kartu?', + areYouSureYouWantToDeleteThisCardForever: 'Opravdu chcete tuto kartu navždy odstranit?', areYouSureYouWantToDeleteThisComment: 'Opravdu chcete smazat tento komentář?', + areYouSureYouWantToDeleteThisCustomField: 'Opravdu chcete odstranit toto vlastní pole?', + areYouSureYouWantToDeleteThisCustomFieldGroup: + 'Opravdu chcete tuto skupinu vlastních polí odstranit?', areYouSureYouWantToDeleteThisLabel: 'Opravdu chcete smazat tento štítek?', areYouSureYouWantToDeleteThisList: 'Opravdu chcete smazat tento seznam?', + areYouSureYouWantToDeleteThisNotificationService: + 'Opravdu chcete tuto oznamovací službu odstranit?', areYouSureYouWantToDeleteThisProject: 'Opravdu chcete smazat tento projekt?', areYouSureYouWantToDeleteThisTask: 'Opravdu chcete smazat tento úkol?', + areYouSureYouWantToDeleteThisTaskList: 'Opravdu chcete tento seznam úkolů odstranit?', areYouSureYouWantToDeleteThisUser: 'Opravdu chcete smazat tohoto uživatele?', + areYouSureYouWantToEmptyTrash: 'Opravdu chcete vysypat koš?', areYouSureYouWantToLeaveBoard: 'Opravdu chcete opustit tuto tabuli?', areYouSureYouWantToLeaveProject: 'Opravdu chcete opustit projekt?', + areYouSureYouWantToMakeThisProjectShared: 'Opravdu chcete tento projekt sdílet?', areYouSureYouWantToRemoveThisManagerFromProject: - 'Jste si jisti, že chcete tohoto správce z projektu odebrat?', - areYouSureYouWantToRemoveThisMemberFromBoard: - 'Jste si jisti, že chcete tohoto člena odebrat z tabule?', + 'Opravdu chcete tohoto správce z projektu odebrat?', + areYouSureYouWantToRemoveThisMemberFromBoard: 'Opravdu chcete tohoto člena odebrat z tabule?', + assignAsOwner_title: 'Přiřadit jako vlastníka', + atLeastOneListMustBePresent: 'Musí být k dispozici alespoň jeden seznam', attachment: 'Příloha', attachments: 'Přílohy', authentication: 'Ověření', background: 'Pozadí', + baseCustomFields_title: 'Základní vlastní pole', + baseGroup: 'Základní skupina', board: 'Tabule', + boardActions_title: 'Akce tabule', boardNotFound_title: 'Tabule nenalezena', + boardSubscribed: 'Tabule odebíraná', + boardUser: 'Uživatel tabule', + byCreationTime: 'Podle času vytvoření', + byDefault: 'Ve výchozím nastavení', + byDueDate: 'Do data platnosti', + canBeInvitedToWorkInBoards: 'Může být přizván k práci ve tabulích.', canComment: 'Může komentovat', + canCreateOwnProjectsAndBeInvitedToWorkInOthers: + 'Může vytvářet vlastní projekty a být přizván k práci na jiných.', + canEditBoardLayoutAndAssignMembersToCards: + 'Může upravovat rozvržení tabule a přiřazovat členy ke kartám.', + canManageSystemWideSettingsAndActAsProjectOwner: + 'Může spravovat nastavení celého systému a být jako vlastník projektu.', canOnlyViewBoard: 'Může zobrazit pouze tabuli.', cardActions_title: 'Akce na kartě', cardNotFound_title: 'Karta nenalezena', + cardsOnThisListAreAvailableToAllBoardMembers: + 'Karty na tomto seznamu jsou k dispozici všem členům tabule.', + cardsOnThisListAreCompleteAndReadyToBeArchived: + 'Karty na tomto seznamu jsou kompletní a připravené k archivaci.', + cardsOnThisListAreReadyToBeWorkedOn: 'Karty na tomto seznamu jsou připraveny k práci.', + clickHereOrRefreshPageToUpdate: '<0>Klikněte sem nebo aktualizujte stránku.', + closed: 'Uzavřeno', color: 'Barva', + comments: 'Komentáře', + contentExceedsLimit: 'Obsah překračuje {{limit}}', copy_inline: 'kopie', createBoard_title: 'Vytvořit tabuli', + createCustomFieldGroup_title: 'Vytvořit vlastní skupinu polí', createLabel_title: 'Vytvořit štítek', - createNewOneOrSelectExistingOne: 'Vytvořit nový nebo vyberte
již existující.', + createNewOneOrSelectExistingOne: 'Vytvořit nový nebo vybrat
již existující.', createProject_title: 'Vytvořit projekt', createTextFile_title: 'Vytvořit textový soubor', + creator: 'Tvůrce', currentPassword: 'Aktuální heslo', + customField_title: 'Vlastní pole', + customFields_title: 'Vlastní pole', + customFieldGroup_title: 'Skupina vlastního pole', + customFieldGroups_title: 'Skupina vlastních polí', dangerZone_title: 'Nebezpečná zóna', date: 'Datum', - dueDate_title: 'Termín', + deactivateUser_title: 'Deaktivace uživatele', + defaultCardType_title: 'Výchozí typ karty', + defaultView_title: 'Výchozí zobrazení', + deletedUser_title: 'Smazaný uživatel', + deleteAllBoardsToBeAbleToDeleteThisProject: + 'Smazat všechny tabule aby bylo možné tento projekt smazat', deleteAttachment_title: 'Smazat přílohu', + deleteBackgroundImage_title: 'Smazat obrázek pozadí', deleteBoard_title: 'Smazat tabuli', deleteCard_title: 'Smazat kartu', + deleteCardForever_title: 'Smazat kartu navždy', deleteComment_title: 'Smazat komentář', + deleteCustomField_title: 'Smazat vlastní pole', + deleteCustomFieldGroup_title: 'Smazat skupinu vlastního pole', deleteLabel_title: 'Smazat štítek', deleteList_title: 'Smazat seznam', + deleteNotificationService_title: 'Smazat službu oznámení', deleteProject_title: 'Smazat projekt', deleteTask_title: 'Smazat úkol', + deleteTaskList_title: 'Smazat seznam úkolů', deleteUser_title: 'Smazat uživatele', description: 'Popis', detectAutomatically: 'Automatická detekce', - dropFileToUpload: 'Přetáhnutím nahraj soubor', - editor: 'Editor', + display: 'Zobrazit', + dropFileToUpload: 'Přetažením nahrát soubor', + dueDate_title: 'Termín', + dynamicAndUnevenlySpacedLayout: 'Dynamické a nerovnoměrné rozložení.', editAttachment_title: 'Upravit přílohu', editAvatar_title: 'Upravit avatar', + editColor_title: 'Upravit barvu', + editCustomField_title: 'Upravit vlastní pole', + editCustomFieldGroup_title: 'Upravit skupinu vlastního pole', editDueDate_title: 'Upravit termín', editEmail_title: 'Upravit e-mail', editInformation_title: 'Upravit informace', editLabel_title: 'Upravit štítek', editPassword_title: 'Upravit heslo', editPermissions_title: 'Upravit oprávnění', + editRole_title: 'Upravit roli', editStopwatch_title: 'Upravit časovač', + editType_title: 'Upravit typ', editUsername_title: 'Upravit uživatelské jméno', email: 'E-mail', + emptyTrash_title: 'Vyprázdnit koš', enterCardTitle: 'Vlož titulek karty...', enterDescription: 'Vlož popis...', enterFilename: 'Vlož název souboru', enterListTitle: 'Vlož název seznamu...', enterTaskDescription: 'Vlož popis úkolu...', - filterByLabels_title: 'Filtruj podle štítku', - filterByMembers_title: 'Filtruj podle člena', + filterByLabels_title: 'Filtrovat podle štítku', + filterByMembers_title: 'Filtrovat podle člena', + forTeamBasedProjects: 'Pro týmové projekty.', + forPersonalProjects: 'Pro osobní projekty.', fromComputer_title: 'Z počítače', fromTrello: 'Z Trella', general: 'Obecné', + gradients: 'Přechody', + grid: 'Mřížka', + hideFromProjectListAndFavorites: 'Skrýt ze seznamu projektů a oblíbených položek', hours: 'Hodiny', importBoard_title: 'Importovat tabuli', invalidCurrentPassword: 'Neplatné aktuální heslo', + kanban: 'Kanban', labels: 'Štítky', language: 'Jazyk', leaveBoard_title: 'Opustit tabuli', leaveProject_title: 'Opustit projekt', + limitCardTypesToDefaultOne: 'Omezit typy karet na jeden výchozí', list: 'Seznam', + lists: 'Seznamy', listActions_title: 'Seznam akcí', + makeProjectShared_title: 'Vytvořit sdílený projekt', managers: 'Vedoucí', members: 'Členové', + memberActions_title: 'Akce člena', minutes: 'Minuty', moveCard_title: 'Přesunout kartu', + myOwn_title: 'Moje vlastní', name: 'Jméno', newestFirst: 'Nejnovější', newEmail: 'Nový e-mail', newPassword: 'Nové heslo', newUsername: 'Nové uživatelské jméno', + newVersionAvailable: 'Nová verze je k dispozici', noConnectionToServer: 'Není spojení k serveru', noBoards: 'Žádné tabule', noLists: 'Žádné seznamy', noProjects: 'Žádné projekty', notifications: 'Oznámení', - noUnreadNotifications: 'Žádné nepřečtené oznámení', + noUnreadNotifications: 'Žádné nepřečtené oznámení.', oldestFirst: 'Nejstarší', openBoard_title: 'Otevřít tabuli', optional_inline: 'volitelné', organization: 'Společnost', + others: 'Jiné', phone: 'Telefon', + plankaUsesAppriseToSendNotificationsToOver100PopularServices: + 'PLANKA používá <1><0>Apprise k zasílání oznámení do více než 100 oblíbených služeb.', preferences: 'Volby', pressPasteShortcutToAddAttachmentFromClipboard: - 'Tip: stisknutím Ctrl-V (Cmd-V na Mac) přidáte přílohu ze schránky.', + 'Tip: stisknutím Ctrl-V (Cmd-V na Macu) přidáte přílohu ze schránky.', + private: 'Soukromé', project: 'Projekt', projectNotFound_title: 'Projekt nenalezen', + projectOwner: 'Vlastník projektu', + referenceDataAndKnowledgeStorage: 'Uchovávání referenčních údajů a znalostí.', removeManager_title: 'Odstranit vedoucího', removeMember_title: 'Odstranit člena', + role: 'Role', searchCards: 'Hledat karty...', + searchCustomFields: 'Hledat vlastní pole...', + searchCustomFieldGroups: 'Hledat skupiny vlastních polí...', searchLabels: 'Hledat štítky...', + searchLists: 'Hledat seznamy...', searchMembers: 'Hledat členy...', + searchProjects: 'Hledat projekty...', searchUsers: 'Hledat uživatele...', seconds: 'Vteřin', + selectAssignee_title: 'Vybrat přiřazení', selectBoard: 'Vybrat tabuli', selectList: 'Vybrat seznam', + selectListToRestoreThisCard: 'Vybrat seznam pro obnovení této karty', + selectOrder_title: 'Vybrat řazení', selectPermissions_title: 'Vybrat oprávnění', selectProject: 'Vybrat projekt', + selectRole_title: 'Vybrat roli', + selectType_title: 'Vybrat typ', + sequentialDisplayOfCards: 'Sekvenční zobrazení karet.', settings: 'Nastavení', + shared: 'Sdílené', + sharedWithMe_title: 'Sdíleno se mnou', + showOnFrontOfCard: 'Zobrazit na přední straně karty', sortList_title: 'Řadit podle', stopwatch: 'Časovač', + story: 'Příběh', + subscribeToCardWhenCommenting: 'Odebírat karty při komentování', subscribeToMyOwnCardsByDefault: 'Ve výchozím nastavení odebírat vlastní karty', - taskActions_title: 'Akce na úkolu', + taskActions_title: 'Akce úkolu', + taskAssignmentAndProjectCompletion: 'Zadání úkolu a dokončení projektu.', + taskList_title: 'Seznam úkolů', + taskListActions_title: 'Akce seznamu úkolů', + team: 'Tým', thereIsNoPreviewAvailableForThisAttachment: 'Pro tuto přílohu není k dispozici žádný náhled.', time: 'Čas', title: 'Titulek', - userActions_title: 'Akce na uživateli', - userAddedThisCardToList: '<0>{{user}}<1> přidal kartu do {{list}}', - userLeftNewCommentToCard: '{{user}} zanechal nový komentář «{{comment}}» k <2>{{card}}', - userMovedCardFromListToList: '{{user}} přesunul <2>{{card}} z {{fromList}} do {{toList}}', - userMovedThisCardFromListToList: - '<0>{{user}}<1> přesunul tuto kartu z {{fromList}} do {{toList}}', + trash: 'Koš', + trashHasBeenSuccessfullyEmptied: 'Koš byl úspěšně vyprázdněn.', + turnOffRecentCardHighlighting: 'Vypnout zvýraznění posledních karet', + typeNameToConfirm: 'Zadejte název pro potvrzení.', + typeTitleToConfirm: 'Zadejte titulek pro potvrzení.', + unsavedChanges: 'Neuložené změny', + uploadedImages: 'Nahrané obrázky', + userActions_title: 'Akce uživatele', + userAddedThisCardToList: '{{user}} přidal kartu do {{list}}', + userLeftNewCommentToCard: '{{user}} zanechal nový komentář «{{comment}}» k {{card}}', + userMovedCardFromListToList: '{{user}} přesunul {{card}} z {{fromList}} do {{toList}}', + userMovedThisCardFromListToList: '{{user}} přesunul tuto kartu z {{fromList}} do {{toList}}', username: 'Uživatelské jméno', users: 'Uživatelé', viewer: 'Prohlížeč', + viewers: 'Diváci', + visualTaskManagementWithLists: 'Vizuální správa úkolů pomocí seznamů.', + withoutBaseGroup: 'Bez základní skupiny', writeComment: 'Napsat komentář...', }, action: { + activateUser: 'Aktivovat uživatele', + activateUser_title: 'Aktivovat uživatele', addAnotherCard: 'Přidat další kartu', addAnotherList: 'Přidat další seznam', addAnotherTask: 'Přidat další úkol', addCard: 'Přidat kartu', addCard_title: 'Přidat kartu', addComment: 'Přidat komentář', + addCustomField: 'Přidat vlastní pole', + addCustomFieldGroup: 'Přidat vlastní skupinu polí', addList: 'Přidat seznam', addMember: 'Přidat člena', addMoreDetailedDescription: 'Přidat další detailní popis', addTask: 'Přidat úkol', + addTaskList: 'Přidat seznam úkolů', addToCard: 'Přidat na kartu', addUser: 'Přidat uživatele', + archive: 'Archivovat', + archiveCard: 'Archivovat kartu', + archiveCard_title: 'Archivovat kartu', + archiveCards: 'Archiv karet', + archiveCards_title: 'Archiv karet', + assignAsOwner: 'Přiřadit jako vlastníka', + cancel: 'Zrušit', createBoard: 'Vytvořit tabuli', + createCustomFieldGroup: 'Vytvořit vlastní skupinu polí', createFile: 'Vytvořit soubor', createLabel: 'Vytvořit štítek', createNewLabel: 'Vytvořit nový štítek', createProject: 'Vytvořit projekt', + deactivateUser: 'Deaktivace uživatele', + deactivateUser_title: 'Deaktivace uživatele', delete: 'Smazat', deleteAttachment: 'Smazat přílohu', deleteAvatar: 'Smazat avatar', + deleteBackgroundImage: 'Smazat obrázek pozadí', deleteBoard: 'Smazat tabuli', + deleteBoard_title: 'Smazat tabuli', deleteCard: 'Smazat kartu', deleteCard_title: 'Smazat kartu', + deleteCardForever: 'Smazat kartu navždy', deleteComment: 'Smazat komentář', + deleteCustomField: 'Smazat vlastní pole', + deleteCustomFieldGroup: 'Smazat skupinu vlastního pole', + deleteForever_title: 'Smazat navždy', + deleteGroup: 'Smazat skupinu', deleteLabel: 'Smazat štítek', deleteList: 'Smazat seznam', deleteList_title: 'Smazat seznam', + deleteNotificationService: 'Smazat službu oznámení', deleteProject: 'Smazat projekt', deleteProject_title: 'Smazat projekt', deleteTask: 'Smazat úkol', deleteTask_title: 'Smazat úkol', + deleteTaskList: 'Smazat seznam úkolů', deleteUser: 'Smazat uživatele', + deleteUser_title: 'Smazat uživatele', + dismissAll: 'Vše přečteno', duplicate: 'Duplikovat', duplicateCard_title: 'Duplikovat kartu', edit: 'Upravit', - editDueDate_title: 'Upravit termín', + editColor_title: 'Upravit barvu', editDescription_title: 'Upravit popis', + editDueDate_title: 'Upravit termín', editEmail_title: 'Upravit e-mail', + editGroup: 'Upravit skupinu', editInformation_title: 'Upravit informace', editPassword_title: 'Upravit heslo', editPermissions: 'Upravit oprávnění', + editRole_title: 'Upravit roli', editStopwatch_title: 'Upravit časovač', editTitle_title: 'Upravit titulek', + editType_title: 'Upravit typ', editUsername_title: 'Upravit uživatelské jméno', + emptyTrash: 'Vyprázdnit koš', + emptyTrash_title: 'Vyprázdnit koš', import: 'Import', + join: 'Připojit', + leave: 'Opustit', leaveBoard: 'Opustit tabuli', leaveProject: 'Opustit projekt', logOut_title: 'Odhlásit se', makeCover_title: 'Vytvořit obal', + makeProjectShared: 'Vytvořit sdílený projekt', + makeProjectShared_title: 'Vytvořit sdílený projekt', move: 'Přesunout', moveCard_title: 'Přesunout kartu', remove: 'Odstranit', + removeAssignee: 'Odstranit přiřazení', + removeColor: 'Smazat barvu', removeCover_title: 'Odstranit obal', removeFromBoard: 'Odstranit z tabule', removeFromProject: 'Odstranit z projektu', removeManager: 'Odstranit vedoucího', removeMember: 'Odstranit člena', + restoreToList: 'Obnovit do {{list}}', + returnToBoard: 'Návrat na tabuli', save: 'Uložit', + showActive: 'Zobrazit aktivní', showAllAttachments: 'Zozbrazit všechny přílohy ({{hidden}} skryté)', + showCardsWithThisUser: 'Zobrazit karty tohoto uživatele', + showDeactivated: 'Zobrazit deaktivované', showFewerAttachments: 'Zobrazit méně příloh', sortList_title: 'Řadit podle', start: 'Start', diff --git a/client/src/locales/cs-CZ/login.js b/client/src/locales/cs-CZ/login.js index 0cdbfc22..93935e00 100644 --- a/client/src/locales/cs-CZ/login.js +++ b/client/src/locales/cs-CZ/login.js @@ -1,14 +1,18 @@ export default { translation: { common: { + activeUsersLimitReached: 'Dosažený limit aktivních uživatelů', emailAlreadyInUse: 'E-mail se již používá', emailOrUsername: 'E-mail nebo uživatelské jméno', invalidCredentials: 'Neplatné přihlašovací údaje', invalidEmailOrUsername: 'Nesprávný e-mail nebo uživatelské jméno', invalidPassword: 'Nesprávné heslo', + logIn_title: 'Přihlásit', noInternetConnection: 'Bez připojení k internetu', + or: 'Nebo', pageNotFound_title: 'Stránka nenalezena', password: 'Heslo', + poweredByPlanka: 'Poháněno technologií PLANKA', serverConnectionFailed: 'Připojení k serveru selhalo', unknownError: 'Neznámá chyba, zkuste to později', usernameAlreadyInUse: 'Uživatelské jméno se již používá', From f17334b1d7c814d7f21be12e06cb71d68b1093a6 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Mon, 12 May 2025 14:19:28 +0200 Subject: [PATCH 009/121] fix: Prevent core rendering before redirecting to login page Closes #1122 --- client/src/components/common/Core/Core.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/components/common/Core/Core.jsx b/client/src/components/common/Core/Core.jsx index 7d67d93f..7e79372f 100644 --- a/client/src/components/common/Core/Core.jsx +++ b/client/src/components/common/Core/Core.jsx @@ -26,6 +26,7 @@ const Core = React.memo(() => { const modal = useSelector(selectors.selectCurrentModal); const project = useSelector(selectors.selectCurrentProject); const board = useSelector(selectors.selectCurrentBoard); + const currentUserId = useSelector(selectors.selectCurrentUserId); // TODO: move to selector? const isNewVersionAvailable = useSelector((state) => { @@ -107,7 +108,7 @@ const Core = React.memo(() => { return ( <> - {isInitializing ? ( + {isInitializing || !currentUserId ? ( ) : ( <> From 742aa21b9b91c850367f4b2a0d2479b8671d0702 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Mon, 12 May 2025 23:42:24 +0200 Subject: [PATCH 010/121] docs: Add chat badge to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76898085..032d3b2d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Project mastering driven by fun** -![Version](https://img.shields.io/github/package-json/v/plankanban/planka?style=flat-square) ![Docker Pulls](https://img.shields.io/badge/docker_pulls-5M%2B-%23066da5?style=flat-square&color=%23e05d44) ![Contributors](https://img.shields.io/github/contributors/plankanban/planka?style=flat-square) +![Version](https://img.shields.io/github/package-json/v/plankanban/planka?style=flat-square) [![Docker Pulls](https://img.shields.io/badge/docker_pulls-5M%2B-%23066da5?style=flat-square&color=red)](https://github.com/plankanban/planka/pkgs/container/planka) [![Contributors](https://img.shields.io/github/contributors/plankanban/planka?style=flat-square&color=blue)](https://github.com/plankanban/planka/graphs/contributors) [![Chat](https://img.shields.io/discord/1041440072953765979?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/WqqYNd7Jvt) ![Demo](https://raw.githubusercontent.com/plankanban/planka/master/assets/demo.gif) From c0f3dbe40100a2bab3c752e8b2cb8e3034ac0f9f Mon Sep 17 00:00:00 2001 From: sivertillia <38623446+sivertillia@users.noreply.github.com> Date: Tue, 13 May 2025 11:51:16 +0300 Subject: [PATCH 011/121] fix: Update Ukrainian translation (#1125) --- client/src/locales/uk-UA/core.js | 186 ++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 1 deletion(-) diff --git a/client/src/locales/uk-UA/core.js b/client/src/locales/uk-UA/core.js index 790f78ff..ae720306 100644 --- a/client/src/locales/uk-UA/core.js +++ b/client/src/locales/uk-UA/core.js @@ -20,72 +20,158 @@ export default { aboutPlanka: 'Про PLANKA', account: 'Обліковий запис', actions: 'Дії', + activateUser_title: 'Активувати користувача', + active: 'Активний', addAttachment_title: 'Додати Вкладення', + addCustomField_title: 'Додати Менеджера', + addCustomFieldGroup_title: 'Додати групу користувацьких полів', addManager_title: 'Додати Менеджера', addMember_title: 'Додати Учасника', + addTaskList_title: 'Додати список завдань', addUser_title: 'Додати Користувача', + admin: 'Адмін', + administration: 'Адміністратор', all: 'Все', allChangesWillBeAutomaticallySavedAfterConnectionRestored: 'Всі зміни будуть автоматично збережені
після відновлення підключення.', + alphabetically: 'За алфавітом', + alwaysDisplayCardCreator: 'Завжди відображати творця картки', + archive: 'Архів', + archiveCard_title: 'Архівна картка', + archiveCards_title: 'Архівні картки', + areYouSureYouWantToActivateThisUser: 'Ви впевнені, що хочете активувати цього користувача?', + areYouSureYouWantToArchiveCards: 'Ви впевнені, що хочете архівувати картки?', + areYouSureYouWantToArchiveThisCard: 'Ви впевнені, що хочете заархівувати цю картку?', + areYouSureYouWantToAssignThisProjectManagerAsOwner: + 'Ви впевнені, що хочете призначити цього менеджера проекту власником?', + areYouSureYouWantToDeactivateThisUser: + 'Ви впевнені, що хочете деактивувати цього користувача?', areYouSureYouWantToDeleteThisAttachment: 'Ви впевнені, що хочете видалити це вкладення?', + areYouSureYouWantToDeleteThisBackgroundImage: + 'Ви впевнені, що хочете видалити це фонове зображення?', areYouSureYouWantToDeleteThisBoard: 'Ви впевнені, що хочете видалити цю дошку?', areYouSureYouWantToDeleteThisCard: 'Ви впевнені, що хочете видалити цю картку?', + areYouSureYouWantToDeleteThisCardForever: + 'Ви впевнені, що хочете видалити цю картку назавжди?', areYouSureYouWantToDeleteThisComment: 'Ви впевнені, що хочете видалити цей коментар?', + areYouSureYouWantToDeleteThisCustomField: 'Ви впевнені, що хочете видалити це кастомне поле?', + areYouSureYouWantToDeleteThisCustomFieldGroup: + 'Ви впевнені, що хочете видалити цю групу кастомних полів?', areYouSureYouWantToDeleteThisLabel: 'Ви впевнені, що хочете видалити цю мітку?', areYouSureYouWantToDeleteThisList: 'Ви впевнені, що хочете видалити цей список?', + areYouSureYouWantToDeleteThisNotificationService: + 'Ви впевнені, що хочете видалити цю службу сповіщень?', areYouSureYouWantToDeleteThisProject: 'Ви впевнені, що хочете видалити цей проект?', areYouSureYouWantToDeleteThisTask: 'Ви впевнені, що хочете видалити це завдання?', + areYouSureYouWantToDeleteThisTaskList: 'Ви впевнені, що хочете видалити цей список завдань?', areYouSureYouWantToDeleteThisUser: 'Ви впевнені, що хочете видалити цього користувача?', + areYouSureYouWantToEmptyTrash: 'Ви впевнені, що хочете очистити смітник?', areYouSureYouWantToLeaveBoard: 'Ви впевнені, що хочете залишити дошку?', areYouSureYouWantToLeaveProject: 'Ви впевнені, що хочете залишити проект?', + areYouSureYouWantToMakeThisProjectShared: + 'Ви впевнені, що хочете зробити цей проект спільним?', areYouSureYouWantToRemoveThisManagerFromProject: 'Ви впевнені, що хочете видалити цього менеджера з проекту?', areYouSureYouWantToRemoveThisMemberFromBoard: 'Ви впевнені, що хочете видалити цього учасника з дошки?', + assignAsOwner_title: 'Призначити власником', + atLeastOneListMustBePresent: 'Принаймні один список повинен бути присутнім', attachment: 'Вкладення', attachments: 'Вкладення', authentication: 'Аутентифікація', background: 'Фон', + baseCustomFields_title: 'Базові користувацькі поля', + baseGroup: 'Базова група', board: 'Дошка', + boardActions_title: 'Дії з дошкою', boardNotFound_title: 'Дошку не знайдено', + boardSubscribed: 'Підписано на дошку', + boardUser: 'Користувач форуму', + byCreationTime: 'За часом створення', + byDefault: 'За замовчуванням', + byDueDate: 'За терміном', + canBeInvitedToWorkInBoards: 'Можуть бути запрошені до роботи в дошках.', canComment: 'Може коментувати', + canCreateOwnProjectsAndBeInvitedToWorkInOthers: + 'Може створювати власні проекти та бути запрошеним до роботи в інших.', + canEditBoardLayoutAndAssignMembersToCards: + 'Можна редагувати макет дошки та призначати учасників на картки.', + canManageSystemWideSettingsAndActAsProjectOwner: + 'Може керувати загальними налаштуваннями системи та виступати в ролі власника проекту.', canOnlyViewBoard: 'Може лише переглядати дошку.', cardActions_title: 'Дії з карткою', cardNotFound_title: 'Картку не знайдено', + cardsOnThisListAreAvailableToAllBoardMembers: + 'Картки з цього списку доступні всім членам правління.', + cardsOnThisListAreCompleteAndReadyToBeArchived: + 'Картки з цього списку завершені і готові до архівування.', + cardsOnThisListAreReadyToBeWorkedOn: 'Картки з цього списку готові до роботи.', + clickHereOrRefreshPageToUpdate: '<0>Натисніть тут або оновіть сторінку для оновлення.', + closed: 'Закрито', color: 'Колір', + comments: 'Коментарі', + contentExceedsLimit: 'Вміст перевищує {{limit}}', + copy_inline: 'копія', createBoard_title: 'Створити Дошку', + createCustomFieldGroup_title: 'Створити групу користувацьких полів', createLabel_title: 'Створити Мітку', createNewOneOrSelectExistingOne: 'Створіть нову або виберіть
існуючу.', createProject_title: 'Створити Проект', createTextFile_title: 'Створити Текстовий Файл', + creator: 'Творець', currentPassword: 'Поточний пароль', + customField_title: 'Користувацьке поле', + customFields_title: 'Користувацькі поля', + customFieldGroup_title: 'Користувацька група полів', + customFieldGroups_title: 'Користувацькі групи полів', dangerZone_title: 'Небезпечна Зона', date: 'Дата', - dueDate_title: 'Крайній Термін', + deactivateUser_title: 'Деактивувати користувача', + defaultCardType_title: 'Тип картки за замовчуванням', + defaultView_title: 'Вигляд за замовчуванням', + deletedUser_title: 'Видалений користувач', + deleteAllBoardsToBeAbleToDeleteThisProject: + 'Видаліть усі дошки, щоб мати змогу видалити цей проект', deleteAttachment_title: 'Видалити Вкладення', + deleteBackgroundImage_title: 'Видалити фонове зображення', deleteBoard_title: 'Видалити Дошку', deleteCard_title: 'Видалити Картку', + deleteCardForever_title: 'Видалити картку назавжди', deleteComment_title: 'Видалити Коментар', + deleteCustomField_title: 'Видалити користувацьке поле', + deleteCustomFieldGroup_title: 'Видалення групи користувацьких полів', deleteLabel_title: 'Видалити Мітку', deleteList_title: 'Видалити Список', + deleteNotificationService_title: 'Видалити службу сповіщень', deleteProject_title: 'Видалити Проект', deleteTask_title: 'Видалити Завдання', + deleteTaskList_title: 'Видалити список завдань', deleteUser_title: 'Видалити Користувача', description: 'Опис', detectAutomatically: 'Визначити автоматично', + display: 'Дисплей', dropFileToUpload: 'Перетягніть файл для завантаження', + dueDate_title: 'Крайній Термін', + dynamicAndUnevenlySpacedLayout: 'Динамічна та нерівномірна верстка.', editor: 'Редактор', + editors: 'Редактори', editAttachment_title: 'Редагувати Вкладення', editAvatar_title: 'Редагувати Аватар', + editColor_title: 'Редагувати колір', + editCustomField_title: 'Редагувати користувацьке поле', + editCustomFieldGroup_title: 'Редагування групи користувацьких полів', editDueDate_title: 'Редагувати Крайній Термін', editEmail_title: 'Редагувати Електронну пошту', editInformation_title: 'Редагувати Інформацію', editLabel_title: 'Редагувати Мітку', editPassword_title: 'Редагувати Пароль', editPermissions_title: 'Редагувати Дозволи', + editRole_title: 'Редагувати Роль', editStopwatch_title: 'Редагувати Секундомір', + editType_title: 'Редагувати Тип', editUsername_title: "Редагувати Ім'я користувача", email: 'Електронна пошта', + emptyTrash_title: 'Порожнє сміття', enterCardTitle: 'Введіть назву картки...', enterDescription: 'Введіть опис...', enterFilename: "Введіть ім'я файлу", @@ -93,58 +179,107 @@ export default { enterTaskDescription: 'Введіть опис завдання...', filterByLabels_title: 'Фільтрувати за Мітками', filterByMembers_title: 'Фільтрувати за Учасниками', + forTeamBasedProjects: 'Для командних проектів.', + forPersonalProjects: 'Для особистих проектів.', fromComputer_title: "З комп'ютера", fromTrello: 'З Trello', general: 'Загальне', + gradients: 'Градієнти', + grid: 'Сітка', + hideFromProjectListAndFavorites: 'Приховати зі списку проектів та обраного', hours: 'Години', importBoard_title: 'Імпортувати Дошку', invalidCurrentPassword: 'Невірний поточний пароль', + kanban: 'Канбан', labels: 'Мітки', language: 'Мова', leaveBoard_title: 'Покинути Дошку', leaveProject_title: 'Покинути Проект', + limitCardTypesToDefaultOne: 'Обмежте типи карток до одного за замовчуванням', list: 'Список', + lists: 'Списки', listActions_title: 'Дії зі Списком', + makeProjectShared_title: 'Зробити проект спільним', managers: 'Менеджери', members: 'Учасники', + memberActions_title: 'Дії учасників', minutes: 'Хвилини', moveCard_title: 'Перемістити Картку', + myOwn_title: 'Моя власна', name: 'Назва', + newestFirst: 'Найновіші перші', newEmail: 'Нова електронна пошта', newPassword: 'Новий пароль', newUsername: "Нове ім'я користувача", + newVersionAvailable: 'Доступна нова версія', noConnectionToServer: 'Відсутнє підключення до сервера', noBoards: 'Немає дошок', noLists: 'Немає списків', noProjects: 'Немає проектів', notifications: 'Сповіщення', noUnreadNotifications: 'Немає непрочитаних сповіщень.', + oldestFirst: 'Найстарший перший', openBoard_title: 'Відкрити Дошку', optional_inline: 'опціонально', organization: 'Організація', + others: 'Інші', phone: 'Телефон', + plankaUsesAppriseToSendNotificationsToOver100PopularServices: + 'PLANKA використовує <1><0>Apprise для надсилання сповіщень на понад 100 популярних сервісів.', preferences: 'Уподобання', pressPasteShortcutToAddAttachmentFromClipboard: 'Порада: натисніть Ctrl-V (⌘V на Mac), щоб додати вкладення з буфера обміну.', + private: 'Приватний', project: 'Проект', projectNotFound_title: 'Проект не знайдено', + projectOwner: 'Власник проекту', + referenceDataAndKnowledgeStorage: 'Довідкові дані та сховище знань.', removeManager_title: 'Видалити Менеджера', removeMember_title: 'Видалити Учасника', + role: 'Роль', + searchCards: 'Картки пошуку...', + searchCustomFields: 'Пошук користувацьких полів...', + searchCustomFieldGroups: 'Пошук користувацьких груп полів...', searchLabels: 'Пошук міток...', + searchLists: 'Пошук списків...', searchMembers: 'Пошук учасників...', + searchProjects: 'Пошук проектів...', searchUsers: 'Пошук користувачів...', seconds: 'Секунди', + selectAssignee_title: 'Виберіть правонаступника', selectBoard: 'Вибрати дошку', selectList: 'Вибрати список', + selectListToRestoreThisCard: 'Виберіть список для відновлення цієї картки', + selectOrder_title: 'Оберіть замовлення', selectPermissions_title: 'Вибрати Дозволи', selectProject: 'Вибрати проект', + selectRole_title: 'Виберіть роль', + selectType_title: 'Виберіть тип', + sequentialDisplayOfCards: 'Послідовне відображення карток.', settings: 'Налаштування', + shared: 'Спільне', + sharedWithMe_title: 'Поділіться зі мною', + showOnFrontOfCard: 'Показати на лицьовій стороні картки', + sortList_title: 'Сортування списку', stopwatch: 'Секундомір', + story: 'Історія', + subscribeToCardWhenCommenting: 'Підпишіться на картку при коментуванні', subscribeToMyOwnCardsByDefault: 'Підписатися на свої картки за замовчуванням', taskActions_title: 'Дії з завданням', + taskAssignmentAndProjectCompletion: 'Постановка завдань і завершення проекту.', + taskList_title: 'Список завдань', + taskListActions_title: 'Дії для списку завдань', + team: 'Команда', thereIsNoPreviewAvailableForThisAttachment: 'Для цього вкладення немає доступного перегляду.', time: 'Час', title: 'Назва', + trash: 'Сміття', + trashHasBeenSuccessfullyEmptied: 'Сміття успішно очищено.', + turnOffRecentCardHighlighting: 'Вимкнути підсвічування останніх карток', + typeNameToConfirm: "Введіть ім'я для підтвердження.", + typeTitleToConfirm: 'Введіть назву, щоб підтвердити.', + unsavedChanges: 'Незбережені зміни', + uploadedImages: 'Завантажені зображення', userActions_title: 'Дії користувача', userAddedThisCardToList: '<0>{{user}}<1> додав(ла) цю картку до {{list}}', userLeftNewCommentToCard: @@ -156,68 +291,117 @@ export default { username: "Ім'я користувача", users: 'Користувачі', viewer: 'Переглядач', + viewers: 'Переглядач', + visualTaskManagementWithLists: 'Візуальне управління завданнями за допомогою списків.', + withoutBaseGroup: 'Без базової групи', writeComment: 'Написати коментар...', }, action: { + activateUser: 'Активувати користувача', + activateUser_title: 'Активувати Користувача', addAnotherCard: 'Додати іншу картку', addAnotherList: 'Додати інший список', addAnotherTask: 'Додати інше завдання', addCard: 'Додати картку', addCard_title: 'Додати Картку', addComment: 'Додати коментар', + addCustomField: 'Додати користувацьке поле', + addCustomFieldGroup: 'Додати групу користувацьких полів', addList: 'Додати список', addMember: 'Додати учасника', addMoreDetailedDescription: 'Додати більш детальний опис', addTask: 'Додати завдання', + addTaskList: 'Додати список завдань', addToCard: 'Додати до картки', addUser: 'Додати користувача', + archive: 'Архів', + archiveCard: 'Архівна картка', + archiveCard_title: 'Архівна Картка', + archiveCards: 'Архівні картки', + archiveCards_title: 'Архівні Картки', + assignAsOwner: 'Призначити власником', + cancel: 'Скасувати', createBoard: 'Створити дошку', + createCustomFieldGroup: 'Створіть власну групу полів', createFile: 'Створити файл', createLabel: 'Створити мітку', createNewLabel: 'Створити нову мітку', createProject: 'Створити проект', + deactivateUser: 'Деактивувати користувача', + deactivateUser_title: 'Деактивувати Користувача', delete: 'Видалити', deleteAttachment: 'Видалити вкладення', deleteAvatar: 'Видалити аватар', + deleteBackgroundImage: 'Видалити фонове зображення', deleteBoard: 'Видалити дошку', + deleteBoard_title: 'Видалити Дошку', deleteCard: 'Видалити картку', deleteCard_title: 'Видалити Картку', + deleteCardForever: 'Видалити картку назавжди', deleteComment: 'Видалити коментар', + deleteCustomField: 'Видалити користувацьке поле', + deleteCustomFieldGroup: 'Видалення групи користувацьких полів', + deleteForever_title: 'Видалити Назавжди', + deleteGroup: 'Видалити групу', deleteLabel: 'Видалити мітку', deleteList: 'Видалити список', deleteList_title: 'Видалити Список', + deleteNotificationService: 'Видалити службу сповіщень', deleteProject: 'Видалити проект', deleteProject_title: 'Видалити Проект', deleteTask: 'Видалити завдання', deleteTask_title: 'Видалити Завдання', + deleteTaskList: 'Видалення списку завдань', deleteUser: 'Видалити користувача', + deleteUser_title: 'Видалити Користувача', + dismissAll: 'Скасувати всі', + duplicate: 'Дублювати', + duplicateCard_title: 'Дублювати Картку', edit: 'Редагувати', + editColor_title: 'Редагувати колір', editDueDate_title: 'Редагувати термін виконання', editDescription_title: 'Редагувати опис', editEmail_title: 'Редагувати E-mail', + editGroup: 'Редагувати групу', editInformation_title: 'Редагувати інформацію', editPassword_title: 'Редагувати пароль', editPermissions: 'Редагувати дозволи', + editRole_title: 'Редагувати Роль', editStopwatch_title: 'Редагувати секундомір', editTitle_title: 'Редагувати Заголовок', + editType_title: 'Редагувати Тип', editUsername_title: "Редагувати Ім'я користувача", + emptyTrash: 'Очистити смітник', + emptyTrash_title: 'Очистити смітник', import: 'Імпортувати', + join: 'Приєднатися', + leave: 'Покинути', leaveBoard: 'Залишити дошку', leaveProject: 'Залишити проект', logOut_title: 'Вийти', makeCover_title: 'Встановити обкладинку', + makeProjectShared: 'Зробити проект спільним', + makeProjectShared_title: 'Зробити Проект спільним', move: 'Перемістити', moveCard_title: 'Перемістити Картку', remove: 'Видалити', + removeAssignee: 'Видалити правонаступника', + removeColor: 'Видалити колір', removeCover_title: 'Видалити обкладинку', removeFromBoard: 'Вилучити з дошки', removeFromProject: 'Вилучити з проекту', removeManager: 'Вилучити керівника', removeMember: 'Вилучити учасника', + restoreToList: 'Відновити до {{list}}', + returnToBoard: 'Повернутися до дошки', save: 'Зберегти', + showActive: 'Показати активний', showAllAttachments: 'Показати всі вкладення ({{hidden}} приховані)', + showCardsWithThisUser: 'Показати картки з цим користувачем', + showDeactivated: 'Показати деактивовано', showFewerAttachments: 'Показати менше вкладень', + sortList_title: 'Сортування списку', start: 'Почати', stop: 'Зупинити', subscribe: 'Підписатися', From 57450a7651ec9bd0b4ded5f6e9903b233bd3a16b Mon Sep 17 00:00:00 2001 From: cjmaldonado <72032912+cjmaldonado@users.noreply.github.com> Date: Tue, 13 May 2025 03:56:01 -0500 Subject: [PATCH 012/121] fix: Increase max length of OIDC code challenge (#1126) Closes #1113 --- server/api/controllers/access-tokens/exchange-with-oidc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api/controllers/access-tokens/exchange-with-oidc.js b/server/api/controllers/access-tokens/exchange-with-oidc.js index 78ed6968..5f3be8ff 100644 --- a/server/api/controllers/access-tokens/exchange-with-oidc.js +++ b/server/api/controllers/access-tokens/exchange-with-oidc.js @@ -35,7 +35,7 @@ module.exports = { inputs: { code: { type: 'string', - maxLength: 1024, + maxLength: 2048, required: true, }, nonce: { From cb32ea6931f42f091ce8d79bead1db450b1695d9 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Tue, 13 May 2025 16:29:31 +0200 Subject: [PATCH 013/121] chore: Fix sample value for `TRUST_PROXY` environment variable --- charts/planka/Chart.yaml | 2 +- charts/planka/templates/deployment.yaml | 2 +- docker-compose-dev.yml | 2 +- docker-compose.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml index 2ac17a0c..7f61edc6 100644 --- a/charts/planka/Chart.yaml +++ b/charts/planka/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.0.0 +version: 1.0.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/planka/templates/deployment.yaml b/charts/planka/templates/deployment.yaml index 0c8ae9ae..b49011df 100644 --- a/charts/planka/templates/deployment.yaml +++ b/charts/planka/templates/deployment.yaml @@ -120,7 +120,7 @@ spec: value: {{ required "A secret key needs to be generated using 'openssl rand -hex 64' and assigned to secretkey." .Values.secretkey }} {{- end }} - name: TRUST_PROXY - value: "0" + value: "true" - name: DEFAULT_ADMIN_EMAIL value: {{ .Values.admin_email }} - name: DEFAULT_ADMIN_NAME diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 1cc47830..e971d974 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -17,7 +17,7 @@ services: # - LOG_LEVEL=warn - # - TRUST_PROXY=0 + # - TRUST_PROXY=true # - TOKEN_EXPIRES_IN=365 # In days # related: https://github.com/knex/knex/issues/2354 diff --git a/docker-compose.yml b/docker-compose.yml index 4d073916..038ee4f1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,7 @@ services: # - LOG_LEVEL=warn - # - TRUST_PROXY=0 + # - TRUST_PROXY=true # - TOKEN_EXPIRES_IN=365 # In days # related: https://github.com/knex/knex/issues/2354 From 3bd8eba4164069863c7e29bfb5ce888ee0d6957e Mon Sep 17 00:00:00 2001 From: leroyloren <57643470+leroyloren@users.noreply.github.com> Date: Wed, 14 May 2025 22:28:39 +0200 Subject: [PATCH 014/121] fix: Update Czech translation (#1129) --- client/src/locales/cs-CZ/core.js | 69 ++++++++++++++++---------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/client/src/locales/cs-CZ/core.js b/client/src/locales/cs-CZ/core.js index ec9911af..3fdfd8c7 100644 --- a/client/src/locales/cs-CZ/core.js +++ b/client/src/locales/cs-CZ/core.js @@ -25,7 +25,7 @@ export default { addAttachment_title: 'Přidat přílohu', addCustomField_title: 'Přidat vlastní pole', addCustomFieldGroup_title: 'Přidat vlastní skupinu polí', - addManager_title: 'Přidat vedoucího', + addManager_title: 'Přidat správce', addMember_title: 'Přidat člena', addTaskList_title: 'Přidat seznam úkolů', addUser_title: 'Přidat uživatele', @@ -43,12 +43,12 @@ export default { areYouSureYouWantToArchiveCards: 'Opravdu chcete archivovat karty?', areYouSureYouWantToArchiveThisCard: 'Opravdu chcete archivovat tuto kartu?', areYouSureYouWantToAssignThisProjectManagerAsOwner: - 'Opravdu chcete přiřadit tohoto projektového manažera jako vlastníka?', + 'Opravdu chcete tohoto správce přiřadit jako vlastníka?', areYouSureYouWantToDeactivateThisUser: 'Opravdu chcete deaktivovat tohoto uživatele?', areYouSureYouWantToDeleteThisAttachment: 'Opravdu chcete smazat tuto přílohu?', areYouSureYouWantToDeleteThisBackgroundImage: 'Opravdu chcete tento obrázek na pozadí odstranit?', - areYouSureYouWantToDeleteThisBoard: 'Opravdu chcete smazat tuto tabuli?', + areYouSureYouWantToDeleteThisBoard: 'Opravdu chcete smazat tuto nástěnku?', areYouSureYouWantToDeleteThisCard: 'Opravdu chcete smazat tuto kartu?', areYouSureYouWantToDeleteThisCardForever: 'Opravdu chcete tuto kartu navždy odstranit?', areYouSureYouWantToDeleteThisComment: 'Opravdu chcete smazat tento komentář?', @@ -64,12 +64,13 @@ export default { areYouSureYouWantToDeleteThisTaskList: 'Opravdu chcete tento seznam úkolů odstranit?', areYouSureYouWantToDeleteThisUser: 'Opravdu chcete smazat tohoto uživatele?', areYouSureYouWantToEmptyTrash: 'Opravdu chcete vysypat koš?', - areYouSureYouWantToLeaveBoard: 'Opravdu chcete opustit tuto tabuli?', + areYouSureYouWantToLeaveBoard: 'Opravdu chcete opustit tuto nástěnku?', areYouSureYouWantToLeaveProject: 'Opravdu chcete opustit projekt?', areYouSureYouWantToMakeThisProjectShared: 'Opravdu chcete tento projekt sdílet?', areYouSureYouWantToRemoveThisManagerFromProject: 'Opravdu chcete tohoto správce z projektu odebrat?', - areYouSureYouWantToRemoveThisMemberFromBoard: 'Opravdu chcete tohoto člena odebrat z tabule?', + areYouSureYouWantToRemoveThisMemberFromBoard: + 'Opravdu chcete tohoto člena odebrat z nástěnky?', assignAsOwner_title: 'Přiřadit jako vlastníka', atLeastOneListMustBePresent: 'Musí být k dispozici alespoň jeden seznam', attachment: 'Příloha', @@ -78,27 +79,27 @@ export default { background: 'Pozadí', baseCustomFields_title: 'Základní vlastní pole', baseGroup: 'Základní skupina', - board: 'Tabule', - boardActions_title: 'Akce tabule', - boardNotFound_title: 'Tabule nenalezena', - boardSubscribed: 'Tabule odebíraná', - boardUser: 'Uživatel tabule', + board: 'Nástěnka', + boardActions_title: 'Akce nástěnky', + boardNotFound_title: 'Nástěnka nenalezena', + boardSubscribed: 'Nástěnka odebíraná', + boardUser: 'Uživatel nástěnky', byCreationTime: 'Podle času vytvoření', byDefault: 'Ve výchozím nastavení', - byDueDate: 'Do data platnosti', - canBeInvitedToWorkInBoards: 'Může být přizván k práci ve tabulích.', + byDueDate: 'Podle data platnosti', + canBeInvitedToWorkInBoards: 'Může být pozván k práci v nástěnkách.', canComment: 'Může komentovat', canCreateOwnProjectsAndBeInvitedToWorkInOthers: - 'Může vytvářet vlastní projekty a být přizván k práci na jiných.', + 'Může vytvářet vlastní projekty a být pozván k práci na jiných.', canEditBoardLayoutAndAssignMembersToCards: - 'Může upravovat rozvržení tabule a přiřazovat členy ke kartám.', + 'Může upravovat rozvržení nástěnky a přiřazovat členy ke kartám.', canManageSystemWideSettingsAndActAsProjectOwner: 'Může spravovat nastavení celého systému a být jako vlastník projektu.', - canOnlyViewBoard: 'Může zobrazit pouze tabuli.', - cardActions_title: 'Akce na kartě', + canOnlyViewBoard: 'Může zobrazit pouze nástěnku.', + cardActions_title: 'Akce karty', cardNotFound_title: 'Karta nenalezena', cardsOnThisListAreAvailableToAllBoardMembers: - 'Karty na tomto seznamu jsou k dispozici všem členům tabule.', + 'Karty na tomto seznamu jsou k dispozici všem členům nástěnky.', cardsOnThisListAreCompleteAndReadyToBeArchived: 'Karty na tomto seznamu jsou kompletní a připravené k archivaci.', cardsOnThisListAreReadyToBeWorkedOn: 'Karty na tomto seznamu jsou připraveny k práci.', @@ -108,7 +109,7 @@ export default { comments: 'Komentáře', contentExceedsLimit: 'Obsah překračuje {{limit}}', copy_inline: 'kopie', - createBoard_title: 'Vytvořit tabuli', + createBoard_title: 'Vytvořit nástěnku', createCustomFieldGroup_title: 'Vytvořit vlastní skupinu polí', createLabel_title: 'Vytvořit štítek', createNewOneOrSelectExistingOne: 'Vytvořit nový nebo vybrat
již existující.', @@ -127,10 +128,10 @@ export default { defaultView_title: 'Výchozí zobrazení', deletedUser_title: 'Smazaný uživatel', deleteAllBoardsToBeAbleToDeleteThisProject: - 'Smazat všechny tabule aby bylo možné tento projekt smazat', + 'Pro smazání tohoto projektu je třeba nejprve smazat všechny nástěnky', deleteAttachment_title: 'Smazat přílohu', deleteBackgroundImage_title: 'Smazat obrázek pozadí', - deleteBoard_title: 'Smazat tabuli', + deleteBoard_title: 'Smazat nástěnku', deleteCard_title: 'Smazat kartu', deleteCardForever_title: 'Smazat kartu navždy', deleteComment_title: 'Smazat komentář', @@ -182,19 +183,19 @@ export default { grid: 'Mřížka', hideFromProjectListAndFavorites: 'Skrýt ze seznamu projektů a oblíbených položek', hours: 'Hodiny', - importBoard_title: 'Importovat tabuli', + importBoard_title: 'Importovat nástěnku', invalidCurrentPassword: 'Neplatné aktuální heslo', kanban: 'Kanban', labels: 'Štítky', language: 'Jazyk', - leaveBoard_title: 'Opustit tabuli', + leaveBoard_title: 'Opustit nástěnku', leaveProject_title: 'Opustit projekt', limitCardTypesToDefaultOne: 'Omezit typy karet na jeden výchozí', list: 'Seznam', lists: 'Seznamy', listActions_title: 'Seznam akcí', makeProjectShared_title: 'Vytvořit sdílený projekt', - managers: 'Vedoucí', + managers: 'Správci', members: 'Členové', memberActions_title: 'Akce člena', minutes: 'Minuty', @@ -207,13 +208,13 @@ export default { newUsername: 'Nové uživatelské jméno', newVersionAvailable: 'Nová verze je k dispozici', noConnectionToServer: 'Není spojení k serveru', - noBoards: 'Žádné tabule', + noBoards: 'Žádné nástěnky', noLists: 'Žádné seznamy', noProjects: 'Žádné projekty', notifications: 'Oznámení', noUnreadNotifications: 'Žádné nepřečtené oznámení.', oldestFirst: 'Nejstarší', - openBoard_title: 'Otevřít tabuli', + openBoard_title: 'Otevřít nástěnku', optional_inline: 'volitelné', organization: 'Společnost', others: 'Jiné', @@ -228,7 +229,7 @@ export default { projectNotFound_title: 'Projekt nenalezen', projectOwner: 'Vlastník projektu', referenceDataAndKnowledgeStorage: 'Uchovávání referenčních údajů a znalostí.', - removeManager_title: 'Odstranit vedoucího', + removeManager_title: 'Odstranit správce', removeMember_title: 'Odstranit člena', role: 'Role', searchCards: 'Hledat karty...', @@ -241,7 +242,7 @@ export default { searchUsers: 'Hledat uživatele...', seconds: 'Vteřin', selectAssignee_title: 'Vybrat přiřazení', - selectBoard: 'Vybrat tabuli', + selectBoard: 'Vybrat nástěnku', selectList: 'Vybrat seznam', selectListToRestoreThisCard: 'Vybrat seznam pro obnovení této karty', selectOrder_title: 'Vybrat řazení', @@ -313,7 +314,7 @@ export default { archiveCards_title: 'Archiv karet', assignAsOwner: 'Přiřadit jako vlastníka', cancel: 'Zrušit', - createBoard: 'Vytvořit tabuli', + createBoard: 'Vytvořit nástěnku', createCustomFieldGroup: 'Vytvořit vlastní skupinu polí', createFile: 'Vytvořit soubor', createLabel: 'Vytvořit štítek', @@ -325,8 +326,8 @@ export default { deleteAttachment: 'Smazat přílohu', deleteAvatar: 'Smazat avatar', deleteBackgroundImage: 'Smazat obrázek pozadí', - deleteBoard: 'Smazat tabuli', - deleteBoard_title: 'Smazat tabuli', + deleteBoard: 'Smazat nástěnku', + deleteBoard_title: 'Smazat nástěnku', deleteCard: 'Smazat kartu', deleteCard_title: 'Smazat kartu', deleteCardForever: 'Smazat kartu navždy', @@ -368,7 +369,7 @@ export default { import: 'Import', join: 'Připojit', leave: 'Opustit', - leaveBoard: 'Opustit tabuli', + leaveBoard: 'Opustit nástěnku', leaveProject: 'Opustit projekt', logOut_title: 'Odhlásit se', makeCover_title: 'Vytvořit obal', @@ -380,12 +381,12 @@ export default { removeAssignee: 'Odstranit přiřazení', removeColor: 'Smazat barvu', removeCover_title: 'Odstranit obal', - removeFromBoard: 'Odstranit z tabule', + removeFromBoard: 'Odstranit z nástěnky', removeFromProject: 'Odstranit z projektu', - removeManager: 'Odstranit vedoucího', + removeManager: 'Odstranit správce', removeMember: 'Odstranit člena', restoreToList: 'Obnovit do {{list}}', - returnToBoard: 'Návrat na tabuli', + returnToBoard: 'Návrat na nástěnku', save: 'Uložit', showActive: 'Zobrazit aktivní', showAllAttachments: 'Zozbrazit všechny přílohy ({{hidden}} skryté)', From ac8361aee3b127693d693b2afc1f847a1234bc1d Mon Sep 17 00:00:00 2001 From: iosabi Date: Thu, 15 May 2025 19:32:37 +0200 Subject: [PATCH 015/121] feat: Support for Docker secrets (#1132) Closes #1001 --- docker-compose-dev.yml | 15 ++++++++----- docker-compose.yml | 33 +++++++++++++++++++++++----- server/.env.sample | 15 ++++++++----- server/start.sh | 49 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 96 insertions(+), 16 deletions(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index e971d974..3beb5685 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -21,22 +21,27 @@ services: # - TOKEN_EXPIRES_IN=365 # In days # related: https://github.com/knex/knex/issues/2354 - # As knex does not pass query parameters from the connection string we - # have to use environment variables in order to pass the desired values, e.g. + # As knex does not pass query parameters from the connection string, + # we have to use environment variables in order to pass the desired values, e.g. # - PGSSLMODE= # Configure knex to accept SSL certificates # - KNEX_REJECT_UNAUTHORIZED_SSL_CERTIFICATE=false - # - DEFAULT_LANGUAGE=en-US # Used for per-board notifications + # Used for per-board notifications + # - DEFAULT_LANGUAGE=en-US - # - DEFAULT_ADMIN_EMAIL=demo@demo.demo # Do not remove if you want to prevent this user from being edited/deleted + # Do not comment out DEFAULT_ADMIN_EMAIL if you want to prevent this user from being edited/deleted + # - DEFAULT_ADMIN_EMAIL=demo@demo.demo # - DEFAULT_ADMIN_PASSWORD=demo # - DEFAULT_ADMIN_NAME=Demo Demo # - DEFAULT_ADMIN_USERNAME=demo # - ACTIVE_USERS_LIMIT= - # - SHOW_DETAILED_AUTH_ERRORS=false # Set to true to show more detailed authentication error messages. It should not be enabled without a rate limiter for security reasons. + + # Set to true to show more detailed authentication error messages. + # It should not be enabled without a rate limiter for security reasons. + # - SHOW_DETAILED_AUTH_ERRORS=false # - S3_ENDPOINT= # - S3_REGION= diff --git a/docker-compose.yml b/docker-compose.yml index 038ee4f1..bd8f8e9c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,17 @@ services: environment: - BASE_URL=http://localhost:3000 - DATABASE_URL=postgresql://postgres@postgres/planka + + # Optionally store the database password in secrets: + # - DATABASE_URL=postgresql://postgres:$${DATABASE_PASSWORD}@postgres/planka + # - DATABASE_PASSWORD__FILE=/run/secrets/database_password + # And add the following to the service: + # secrets: + # - database_password + - SECRET_KEY=notsecretkey + # Optionally store in secrets - then SECRET_KEY should not be set + # - SECRET_KEY__FILE=/run/secrets/secret_key # - LOG_LEVEL=warn @@ -20,33 +30,44 @@ services: # - TOKEN_EXPIRES_IN=365 # In days # related: https://github.com/knex/knex/issues/2354 - # As knex does not pass query parameters from the connection string we - # have to use environment variables in order to pass the desired values, e.g. + # As knex does not pass query parameters from the connection string, + # we have to use environment variables in order to pass the desired values, e.g. # - PGSSLMODE= # Configure knex to accept SSL certificates # - KNEX_REJECT_UNAUTHORIZED_SSL_CERTIFICATE=false - # - DEFAULT_LANGUAGE=en-US # Used for per-board notifications + # Used for per-board notifications + # - DEFAULT_LANGUAGE=en-US - # - DEFAULT_ADMIN_EMAIL=demo@demo.demo # Do not remove if you want to prevent this user from being edited/deleted + # Do not comment out DEFAULT_ADMIN_EMAIL if you want to prevent this user from being edited/deleted + # - DEFAULT_ADMIN_EMAIL=demo@demo.demo # - DEFAULT_ADMIN_PASSWORD=demo + # Optionally store in secrets - then DEFAULT_ADMIN_PASSWORD should not be set + # - DEFAULT_ADMIN_PASSWORD__FILE=/run/secrets/default_admin_password # - DEFAULT_ADMIN_NAME=Demo Demo # - DEFAULT_ADMIN_USERNAME=demo # - ACTIVE_USERS_LIMIT= - # - SHOW_DETAILED_AUTH_ERRORS=false # Set to true to show more detailed authentication error messages. It should not be enabled without a rate limiter for security reasons. + + # Set to true to show more detailed authentication error messages. + # It should not be enabled without a rate limiter for security reasons. + # - SHOW_DETAILED_AUTH_ERRORS=false # - S3_ENDPOINT= # - S3_REGION= # - S3_ACCESS_KEY_ID= # - S3_SECRET_ACCESS_KEY= + # Optionally store in secrets - then S3_SECRET_ACCESS_KEY should not be set + # - S3_SECRET_ACCESS_KEY__FILE=/run/secrets/s3_secret_access_key # - S3_BUCKET= # - S3_FORCE_PATH_STYLE=true # - OIDC_ISSUER= # - OIDC_CLIENT_ID= # - OIDC_CLIENT_SECRET= + # Optionally store in secrets - then OIDC_CLIENT_SECRET should not be set + # - OIDC_CLIENT_SECRET__FILE=/run/secrets/oidc_client_secret # - OIDC_ID_TOKEN_SIGNED_RESPONSE_ALG= # - OIDC_USERINFO_SIGNED_RESPONSE_ALG= # - OIDC_SCOPES=openid email profile @@ -69,6 +90,8 @@ services: # - SMTP_SECURE=true # - SMTP_USER= # - SMTP_PASSWORD= + # Optionally store in secrets - then SMTP_PASSWORD should not be set + # - SMTP_PASSWORD__FILE=/run/secrets/smtp_password # - SMTP_FROM="Demo Demo" # - SMTP_TLS_REJECT_UNAUTHORIZED=false diff --git a/server/.env.sample b/server/.env.sample index 6420a09d..8817bb76 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -13,22 +13,27 @@ SECRET_KEY=notsecretkey # TOKEN_EXPIRES_IN=365 # In days # related: https://github.com/knex/knex/issues/2354 -# As knex does not pass query parameters from the connection string we -# have to use environment variables in order to pass the desired values, e.g. +# As knex does not pass query parameters from the connection string, +# we have to use environment variables in order to pass the desired values, e.g. # PGSSLMODE= # Configure knex to accept SSL certificates # KNEX_REJECT_UNAUTHORIZED_SSL_CERTIFICATE=false -# DEFAULT_LANGUAGE=en-US # Used for per-board notifications +# Used for per-board notifications +# DEFAULT_LANGUAGE=en-US -# DEFAULT_ADMIN_EMAIL=demo@demo.demo # Do not remove if you want to prevent this user from being edited/deleted +# Do not comment out DEFAULT_ADMIN_EMAIL if you want to prevent this user from being edited/deleted +# DEFAULT_ADMIN_EMAIL=demo@demo.demo # DEFAULT_ADMIN_PASSWORD=demo # DEFAULT_ADMIN_NAME=Demo Demo # DEFAULT_ADMIN_USERNAME=demo # ACTIVE_USERS_LIMIT= -# SHOW_DETAILED_AUTH_ERRORS=false # Set to true to show more detailed authentication error messages. It should not be enabled without a rate limiter for security reasons. + +# Set to true to show more detailed authentication error messages. +# It should not be enabled without a rate limiter for security reasons. +# SHOW_DETAILED_AUTH_ERRORS=false # S3_ENDPOINT= # S3_REGION= diff --git a/server/start.sh b/server/start.sh index 440950cc..0f41de93 100755 --- a/server/start.sh +++ b/server/start.sh @@ -1,2 +1,49 @@ #!/bin/bash -export NODE_ENV=production && set -e && node db/init.js && node app.js --prod + +set -eu + +# Load secrets from files if *__FILE variables are provided. +# Only the first line of each file is read (newline excluded). + +# DATABASE_PASSWORD (used to dynamically inject into DATABASE_URL) +if [[ -n "${DATABASE_URL}" ]]; then + if [[ -z "${DATABASE_PASSWORD:-}" && -e "${DATABASE_PASSWORD__FILE:-}" ]]; then + read DATABASE_PASSWORD < "${DATABASE_PASSWORD__FILE}" + export DATABASE_URL="${DATABASE_URL/\$\{DATABASE_PASSWORD\}/${DATABASE_PASSWORD}}" + fi +fi + +# SECRET_KEY +if [[ -z "${SECRET_KEY:-}" && -e "${SECRET_KEY__FILE:-}" ]]; then + read SECRET_KEY < "${SECRET_KEY__FILE}" + export SECRET_KEY +fi + +# DEFAULT_ADMIN_PASSWORD +if [[ -z "${DEFAULT_ADMIN_PASSWORD:-}" && -e "${DEFAULT_ADMIN_PASSWORD__FILE:-}" ]]; then + read DEFAULT_ADMIN_PASSWORD < "${DEFAULT_ADMIN_PASSWORD__FILE}" + export DEFAULT_ADMIN_PASSWORD +fi + +# S3_SECRET_ACCESS_KEY +if [[ -z "${S3_SECRET_ACCESS_KEY:-}" && -e "${S3_SECRET_ACCESS_KEY__FILE:-}" ]]; then + read S3_SECRET_ACCESS_KEY < "${S3_SECRET_ACCESS_KEY__FILE}" + export S3_SECRET_ACCESS_KEY +fi + +# OIDC_CLIENT_SECRET +if [[ -z "${OIDC_CLIENT_SECRET:-}" && -e "${OIDC_CLIENT_SECRET__FILE:-}" ]]; then + read OIDC_CLIENT_SECRET < "${OIDC_CLIENT_SECRET__FILE}" + export OIDC_CLIENT_SECRET +fi + +# SMTP_PASSWORD +if [[ -z "${SMTP_PASSWORD:-}" && -e "${SMTP_PASSWORD__FILE:-}" ]]; then + read SMTP_PASSWORD < "${SMTP_PASSWORD__FILE}" + export SMTP_PASSWORD +fi + +export NODE_ENV=production + +node db/init.js +exec node app.js --prod From f43785c3d05c923bd513190a1b2895b02eae1358 Mon Sep 17 00:00:00 2001 From: Hannes Date: Fri, 16 May 2025 11:18:12 +0200 Subject: [PATCH 016/121] fix: Update German translation (#1134) --- client/src/locales/de-DE/core.js | 153 ++++++++++++++-- client/src/locales/de-DE/login.js | 6 + client/src/locales/de-DE/markdown-editor.json | 165 ++++++++++++++++++ 3 files changed, 313 insertions(+), 11 deletions(-) create mode 100644 client/src/locales/de-DE/markdown-editor.json diff --git a/client/src/locales/de-DE/core.js b/client/src/locales/de-DE/core.js index ac11fedb..022e3ffc 100644 --- a/client/src/locales/de-DE/core.js +++ b/client/src/locales/de-DE/core.js @@ -1,18 +1,20 @@ import dateFns from 'date-fns/locale/de'; import timeAgo from 'javascript-time-ago/locale/de'; +import markdownEditor from './markdown-editor.json'; export default { dateFns, timeAgo, + markdownEditor, format: { date: 'd.MM.yyyy', time: 'p', dateTime: '$t(format:date) $t(format:time)', - longDate: 'd. MMM', - longDateTime: "d. MMMM yy 'um' p", fullDate: 'd. MMM. y', fullDateTime: "d. MMMM. y 'um' p", + longDate: 'd. MMM', + longDateTime: "d. MMMM yy 'um' p", }, translation: { @@ -20,23 +22,44 @@ export default { aboutPlanka: 'Über PLANKA', account: 'Konto', actions: 'Aktionen', + activateUser_title: 'Benutzer aktivieren', active: 'Aktiv', addAttachment_title: 'Anhang hinzufügen', addCustomField_title: 'Datenfeld hinzufügen', addCustomFieldGroup_title: 'Feldgruppe hinzufügen', addManager_title: 'Projektleiter hinzufügen', addMember_title: 'Mitglied hinzufügen', + addTaskList_title: 'Aufgabenliste hinzufügen', addUser_title: 'Benutzer hinzufügen', admin: 'Administrator', administration: 'Verwaltung', all: 'Alle', allChangesWillBeAutomaticallySavedAfterConnectionRestored: 'Alle Änderungen werden automatisch gespeichert, sobald die Verbindung wiederhergestellt wurde.', + alphabetically: 'Alphabetisch', + alwaysDisplayCardCreator: 'Kartenersteller immer anzeigen', + archive: 'Archiv', + archiveCard_title: 'Karte archivieren', + archiveCards_title: 'Karten archivieren', + areYouSureYouWantToActivateThisUser: + 'Sind Sie sicher, dass Sie diesen Benutzer aktivieren möchten?', + areYouSureYouWantToArchiveCards: + 'Sind Sie sicher, dass Sie diese Karten archivieren möchten?', + areYouSureYouWantToArchiveThisCard: + 'Sind Sie sicher, dass Sie diese Karte archivieren möchten?', + areYouSureYouWantToAssignThisProjectManagerAsOwner: + 'Sind Sie sicher, dass Sie diesen Projektleiter als Eigentümer festlegen möchten?', + areYouSureYouWantToDeactivateThisUser: + 'Sind Sie sicher, dass Sie diesen Benutzer deaktivieren möchten?', areYouSureYouWantToDeleteThisAttachment: 'Sind Sie sicher, dass Sie diesen Anhang löschen möchten?', + areYouSureYouWantToDeleteThisBackgroundImage: + 'Sind Sie sicher, dass Sie dieses Hintergrundbild löschen möchten?', areYouSureYouWantToDeleteThisBoard: 'Sind Sie sicher, dass Sie diesen Arbeitsbereich löschen möchten?', areYouSureYouWantToDeleteThisCard: 'Sind Sie sicher, dass Sie diese Karte löschen möchten?', + areYouSureYouWantToDeleteThisCardForever: + 'Sind Sie sicher, dass Sie diese Karte endgültig löschen möchten?', areYouSureYouWantToDeleteThisComment: 'Sind Sie sicher, dass Sie diesen Kommentar löschen möchten?', areYouSureYouWantToDeleteThisCustomField: @@ -45,18 +68,27 @@ export default { 'Sind Sie sicher, dass Sie diese Feldgruppe löschen möchten?', areYouSureYouWantToDeleteThisLabel: 'Sind Sie sicher, dass Sie dieses Label löschen möchten?', areYouSureYouWantToDeleteThisList: 'Sind Sie sicher, dass Sie diese Liste löschen möchten?', + areYouSureYouWantToDeleteThisNotificationService: + 'Sind Sie sicher, dass Sie diesen Benachrichtigungsdienst löschen möchten?', areYouSureYouWantToDeleteThisProject: 'Sind Sie sicher, dass Sie dieses Projekt löschen möchten?', areYouSureYouWantToDeleteThisTask: 'Sind Sie sicher, dass Sie diese Aufgabe löschen möchten?', + areYouSureYouWantToDeleteThisTaskList: + 'Sind Sie sicher, dass Sie diese Aufgabenliste löschen möchten?', areYouSureYouWantToDeleteThisUser: 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?', + areYouSureYouWantToEmptyTrash: 'Sind Sie sicher, dass Sie den Papierkorb leeren möchten?', areYouSureYouWantToLeaveBoard: 'Sind Sie sicher, dass Sie den Arbeitsbereich verlassen möchten?', areYouSureYouWantToLeaveProject: 'Sind Sie sicher, dass Sie das Projekt verlassen möchten?', + areYouSureYouWantToMakeThisProjectShared: + 'Sind Sie sicher, dass Sie dieses Projekt freigeben möchten?', areYouSureYouWantToRemoveThisManagerFromProject: 'Sind Sie sicher, dass Sie diesen Projektleiter aus dem Projekt entfernen möchten?', areYouSureYouWantToRemoveThisMemberFromBoard: 'Sind Sie sicher, dass Sie dieses Mitglied aus dem Arbeitsbereich entfernen möchten?', + assignAsOwner_title: 'Als Eigentümer zuweisen', + atLeastOneListMustBePresent: 'Mindestens eine Liste muss vorhanden sein', attachment: 'Anhang', attachments: 'Anhänge', authentication: 'Authentifizierung', @@ -64,8 +96,13 @@ export default { baseCustomFields_title: 'Feldgruppe', baseGroup: 'Feldgruppe', board: 'Arbeitsbereich', + boardActions_title: 'Arbeitsbereich-Aktionen', boardNotFound_title: 'Arbeitsbereich nicht gefunden', + boardSubscribed: 'Arbeitsbereich abonniert', boardUser: 'Benutzer', + byCreationTime: 'Nach Erstellungszeit', + byDefault: 'Standardmäßig', + byDueDate: 'Nach Fälligkeitsdatum', canBeInvitedToWorkInBoards: 'Kann zu Projekten und Boards eingeladen werden.', canComment: 'Kann kommentieren', canCreateOwnProjectsAndBeInvitedToWorkInOthers: @@ -79,37 +116,57 @@ export default { cardNotFound_title: 'Karte nicht gefunden', cardsOnThisListAreAvailableToAllBoardMembers: 'Cards on this list are available to all Arbeitsbereich members.', + cardsOnThisListAreCompleteAndReadyToBeArchived: + 'Karten in dieser Liste sind abgeschlossen und können archiviert werden.', + cardsOnThisListAreReadyToBeWorkedOn: 'Karten in dieser Liste sind bereit zur Bearbeitung.', + clickHereOrRefreshPageToUpdate: + '<0>Hier klicken oder Seite aktualisieren, um zu aktualisieren.', closed: 'Geschlossen', color: 'Farbe', + comments: 'Kommentare', + contentExceedsLimit: 'Inhalt überschreitet {{limit}}', copy_inline: 'kopieren', createBoard_title: 'Arbeitsbereich erstellen', createCustomFieldGroup_title: 'Feldgruppe erstellen', createLabel_title: 'Label erstellen', - createNewOneOrSelectExistingOne: 'Create a new one or select
an existing one.', + createNewOneOrSelectExistingOne: 'Create a new one or select
an existing one.', createProject_title: 'Projekt erstellen', createTextFile_title: 'Textdatei erstellen', + creator: 'Ersteller', currentPassword: 'Derzeitiges Passwort', customField_title: 'Feldgruppe', - customFields_title: 'Feldgruppen', customFieldGroup_title: 'Feldgruppe', + customFieldGroups_title: 'Benutzerdefinierte Feldgruppen', + customFields_title: 'Feldgruppen', dangerZone_title: 'Gefahrenbereich', date: 'Datum', + deactivateUser_title: 'Benutzer deaktivieren', + defaultCardType_title: 'Standard-Kartentyp', + defaultView_title: 'Standardansicht', + deleteAllBoardsToBeAbleToDeleteThisProject: + 'Löschen Sie alle Arbeitsbereiche, um dieses Projekt löschen zu können', deleteAttachment_title: 'Anhang löschen', + deleteBackgroundImage_title: 'Hintergrundbild löschen', deleteBoard_title: 'Arbeitsbereich löschen', deleteCard_title: 'Karte löschen', + deleteCardForever_title: 'Karte endgültig löschen', deleteComment_title: 'Kommentar löschen', deleteCustomField_title: 'Datenfeld löschen', deleteCustomFieldGroup_title: 'Feldgruppe löschen', + deletedUser_title: 'Gelöschter Benutzer', deleteLabel_title: 'Label löschen', deleteList_title: 'Liste löschen', + deleteNotificationService_title: 'Benachrichtigungsdienst löschen', deleteProject_title: 'Projekt löschen', deleteTask_title: 'Aufgabe löschen', + deleteTaskList_title: 'Aufgabenliste löschen', deleteUser_title: 'Benutzer löschen', description: 'Beschreibung', detectAutomatically: 'Automatisch erkennen', + display: 'Anzeige', dropFileToUpload: 'Datei für Upload ablegen', dueDate_title: 'Fälligkeitsdatum', - editor: 'Verwalter', + dynamicAndUnevenlySpacedLayout: 'Dynamisches und ungleichmäßig verteiltes Layout.', editAttachment_title: 'Anhang bearbeiten', editAvatar_title: 'Profilbild bearbeiten', editColor_title: 'Farbe bearbeiten', @@ -125,7 +182,10 @@ export default { editStopwatch_title: 'Stoppuhr bearbeiten', editType_title: 'Typ ändern', editUsername_title: 'Benutzername ändern', + editor: 'Bearbeiter', + editors: 'Bearbeiter', email: 'E-mail', + emptyTrash_title: 'Papierkorb leeren', enterCardTitle: 'Kartentitel eingeben...', enterDescription: 'Beschreibung eingeben...', enterFilename: 'Dateiname eingeben', @@ -133,43 +193,58 @@ export default { enterTaskDescription: 'Aufgabenbeschreibung eingeben...', filterByLabels_title: 'Nach Label filtern', filterByMembers_title: 'Nach Mitgliedern filtern', + forPersonalProjects: 'Für persönliche Projekte.', + forTeamBasedProjects: 'Für teambasierte Projekte.', fromComputer_title: 'Vom Computer', fromTrello: 'Von Trello', general: 'Allgemein', + gradients: 'Verläufe', + grid: 'Raster', + hideFromProjectListAndFavorites: 'Aus Projektliste und Favoriten ausblenden', hours: 'Stunden', importBoard_title: 'Board importieren', invalidCurrentPassword: 'Das aktuelle Passwort ist falsch', + kanban: 'Kanban', labels: 'Labels', language: 'Sprache', leaveBoard_title: 'Arbeitsbereich verlassen', leaveProject_title: 'Projekt verlassen', + limitCardTypesToDefaultOne: 'Kartentypen auf Standardtyp beschränken', list: 'Liste', - lists: 'Listen', listActions_title: 'Aufgaben auflisten', + lists: 'Listen', + makeProjectShared_title: 'Projekt freigeben', + managerActions_title: 'Projektleiteraktionen', managers: 'Projektleiter', - members: 'Mitglieder', memberActions_title: 'Mitglieder-Aktionen', + members: 'Mitglieder', minutes: 'Minuten', moveCard_title: 'Karte verschieben', + myOwn_title: 'Meine eigenen', name: 'Name', - newestFirst: 'Neueste zuerst', newEmail: 'Neue E-Mail-Adresse', newPassword: 'Neues Passwort', newUsername: 'Neuer Benutzername', - noConnectionToServer: 'Keine Verbindung zum Server', + newVersionAvailable: 'Neue Version verfügbar', + newestFirst: 'Neueste zuerst', noBoards: 'Keine Arbeitsbereiche', + noConnectionToServer: 'Keine Verbindung zum Server', noLists: 'Keine Listen', noProjects: 'Keine Projekte', - notifications: 'Benachrichtigungen', noUnreadNotifications: 'Keine ungelesenen Benachrichtigungen.', + notifications: 'Benachrichtigungen', oldestFirst: 'Älteste zuerst', openBoard_title: 'Arbeitsbereich öffnen', optional_inline: 'Optional', organization: 'Organisation', + others: 'Andere', phone: 'Telefon', + plankaUsesAppriseToSendNotificationsToOver100PopularServices: + 'PLANKA verwendet <1><0>Apprise, um Benachrichtigungen an über 100 beliebte Dienste zu senden.', preferences: 'Voreinstellungen', pressPasteShortcutToAddAttachmentFromClipboard: 'Tipp: Drücken Sie STRG-V (Cmd-V auf Mac), um einen Anhang aus der Zwischenablage hinzuzufügen.', + private: 'Privat', project: 'Projekt', projectNotFound_title: 'Projekt nicht gefunden', projectOwner: 'Projektleitung', @@ -178,28 +253,48 @@ export default { removeMember_title: 'Mitglied entfernen', role: 'Rolle', searchCards: 'Karte suchen...', + searchCustomFieldGroups: 'Benutzerdefinierte Feldgruppen suchen...', searchCustomFields: 'In Feldgruppen suchen...', searchLabels: 'Label suchen...', searchLists: 'Liste suchen...', searchMembers: 'Mitglied suchen...', + searchProjects: 'Projekte suchen...', searchUsers: 'Benutzer suchen...', seconds: 'Sekunden', + selectAssignee_title: 'Zuständigen auswählen', selectBoard: 'Arbeitsbereich auswählen', selectList: 'Liste auswählen', + selectListToRestoreThisCard: 'Liste auswählen, um diese Karte wiederherzustellen', + selectOrder_title: 'Reihenfolge auswählen', selectPermissions_title: 'Berechtigungen auswählen', selectProject: 'Projekt auswählen', selectRole_title: 'Rolle auswählen', selectType_title: 'Typ auswählen', + sequentialDisplayOfCards: 'Sequenzielle Anzeige von Karten.', settings: 'Einstellungen', + shared: 'Geteilt', + sharedWithMe_title: 'Mit mir geteilt', + showOnFrontOfCard: 'Auf der Vorderseite der Karte anzeigen', sortList_title: 'Liste sortieren', stopwatch: 'Stoppuhr', story: 'Wissen', + subscribeToCardWhenCommenting: 'Karte beim Kommentieren abonnieren', subscribeToMyOwnCardsByDefault: 'Standardmäßig meine eigenen Karten abonnieren', taskActions_title: 'Aufgabenaktionen', taskAssignmentAndProjectCompletion: 'Verwaltung von Aufgaben und Projekten.', + taskList_title: 'Aufgabenliste', + taskListActions_title: 'Aufgabenlisten-Aktionen', + team: 'Team', thereIsNoPreviewAvailableForThisAttachment: 'Für diesen Anhang ist keine Vorschau verfügbar.', time: 'Zeit', title: 'Titel', + trash: 'Papierkorb', + trashHasBeenSuccessfullyEmptied: 'Papierkorb wurde erfolgreich geleert.', + turnOffRecentCardHighlighting: 'Hervorhebung neuer Karten ausschalten', + typeNameToConfirm: 'Namen zur Bestätigung eingeben.', + typeTitleToConfirm: 'Titel zur Bestätigung eingeben.', + unsavedChanges: 'Ungespeicherte Änderungen', + uploadedImages: 'Hochgeladene Bilder', userActions_title: 'Benutzeraktionen', userAddedThisCardToList: '<0>{{user}}<1> hat diese Karte hinzugefügt zu {{list}}', userLeftNewCommentToCard: @@ -211,10 +306,15 @@ export default { username: 'Benutzername', users: 'Benutzer', viewer: 'Betrachter', + viewers: 'Betrachter', + visualTaskManagementWithLists: 'Visuelle Aufgabenverwaltung mit Listen.', + withoutBaseGroup: 'Ohne Basisgruppe', writeComment: 'Kommentar verfassen...', }, action: { + activateUser: 'Benutzer aktivieren', + activateUser_title: 'Benutzer aktivieren', addAnotherCard: 'Karte hinzufügen', addAnotherList: 'Liste hinzufügen', addAnotherTask: 'Aufgabe hinzufügen', @@ -227,36 +327,56 @@ export default { addMember: 'Mitglied hinzufügen', addMoreDetailedDescription: 'Eine detaillierte Beschreibung hinzufügen', addTask: 'Aufgabe hinzufügen', + addTaskList: 'Aufgabenliste hinzufügen', addToCard: 'Zu Karte hinzufügen', addUser: 'Benutzer hinzufügen', + archive: 'Archivieren', + archiveCard: 'Karte archivieren', + archiveCard_title: 'Karte archivieren', + archiveCards: 'Karten archivieren', + archiveCards_title: 'Karten archivieren', + assignAsOwner: 'Als Eigentümer zuweisen', + cancel: 'Abbrechen', createBoard: 'Arbeitsbereich erstellen', createCustomFieldGroup: 'Feldgruppe erstellen', createFile: 'Datei erstellen', createLabel: 'Label erstellen', createNewLabel: 'Neues Label erstellen', createProject: 'Projekt erstellen', + deactivateUser: 'Benutzer deaktivieren', + deactivateUser_title: 'Benutzer deaktivieren', delete: 'Löschen', deleteAttachment: 'Anhang löschen', deleteAvatar: 'Avatar löschen', + deleteBackgroundImage: 'Hintergrundbild löschen', deleteBoard: 'Arbeitsbereich löschen', + deleteBoard_title: 'Arbeitsbereich löschen', deleteCard: 'Karte löschen', deleteCard_title: 'Karte löschen', + deleteCardForever: 'Karte endgültig löschen', deleteComment: 'Kommentar löschen', deleteCustomField: 'Datenfeld löschen', deleteCustomFieldGroup: 'Feldgruppe löschen', + deleteForever_title: 'Endgültig löschen', deleteGroup: 'Gruppe löschen', deleteLabel: 'Label löschen', deleteList: 'Liste löschen', deleteList_title: 'Liste löschen', + deleteNotificationService: 'Benachrichtigungsdienst löschen', deleteProject: 'Projekt löschen', deleteProject_title: 'Projekt löschen', deleteTask: 'Aufgabe löschen', deleteTask_title: 'Aufgabe löschen', + deleteTaskList: 'Aufgabenliste löschen', deleteUser: 'Benutzer löschen', + deleteUser_title: 'Benutzer löschen', + dismissAll: 'Alle verwerfen', + duplicate: 'Duplizieren', + duplicateCard_title: 'Karte duplizieren', edit: 'Bearbeiten', editColor_title: 'Farbe bearbeiten', - editDueDate_title: 'Fälligkeitsdatum bearbeiten', editDescription_title: 'Beschreibung ändern', + editDueDate_title: 'Fälligkeitsdatum bearbeiten', editEmail_title: 'E-Mail-Adresse bearbeiten', editGroup: 'Gruppe bearbeiten', editInformation_title: 'Informationen bearbeiten', @@ -267,23 +387,34 @@ export default { editTitle_title: 'Titel bearbeiten', editType_title: 'Typ ändern ', editUsername_title: 'Benutzername ändern', + emptyTrash: 'Papierkorb leeren', + emptyTrash_title: 'Papierkorb leeren', import: 'Import', + join: 'Beitreten', + leave: 'Verlassen', leaveBoard: 'Arbeitsbereich verlassen', leaveProject: 'Projekt verlassen', logOut_title: 'Ausloggen', makeCover_title: 'Als Vorschau festlegen', + makeProjectShared: 'Projekt freigeben', + makeProjectShared_title: 'Projekt freigeben', move: 'Verschieben', moveCard_title: 'Karte bewegen', remove: 'Löschen', + removeAssignee: 'Zuständigen entfernen', removeColor: 'Farbe löschen', removeCover_title: 'Vorschau löschen', removeFromBoard: 'Vom Arbeitsbereich entfernen', removeFromProject: 'Vom Projekt entfernen', removeManager: 'Projektleiter entfernen', removeMember: 'Mitglied entfernen', + restoreToList: 'Wiederherstellen in {{list}}', + returnToBoard: 'Zurück zum Arbeitsbereich', save: 'Speichern', + showActive: 'Aktive anzeigen', showAllAttachments: 'Alle Anhänge anzeigen ({{hidden}} versteckt)', showCardsWithThisUser: 'Karten mit diesem Benutzer zeigen', + showDeactivated: 'Deaktivierte anzeigen', showFewerAttachments: 'Weniger Anhänge anzeigen', sortList_title: 'Liste sortieren', start: 'Start', diff --git a/client/src/locales/de-DE/login.js b/client/src/locales/de-DE/login.js index bf35cc7a..e357d0b5 100644 --- a/client/src/locales/de-DE/login.js +++ b/client/src/locales/de-DE/login.js @@ -1,21 +1,27 @@ export default { translation: { common: { + activeUsersLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht', emailAlreadyInUse: 'E-mail Adresse wird bereits benutzt', emailOrUsername: 'E-Mail-Adresse oder Benutzername', + invalidCredentials: 'Ungültige Anmeldeinformationen', invalidEmailOrUsername: 'Ungültige E-Mail-Adresse oder Benutzername', invalidPassword: 'Ungültiges Passwort', logIn_title: 'Anmelden', noInternetConnection: 'Keine Internetverbindung', + or: 'Oder', pageNotFound_title: 'Seite nicht gefunden', password: 'Passwort', + poweredByPlanka: 'Powered by PLANKA', serverConnectionFailed: 'Serververbindung fehlgeschlagen', unknownError: 'Unbekannter Fehler, bitte später erneut versuchen', usernameAlreadyInUse: 'Benutzername wird bereits verwendet', + useSingleSignOn: 'Einmalige Anmeldung (SSO) verwenden', }, action: { logIn: 'Einloggen', + logInWithSso: 'Einloggen mit SSO', }, }, }; diff --git a/client/src/locales/de-DE/markdown-editor.json b/client/src/locales/de-DE/markdown-editor.json new file mode 100644 index 00000000..e979d30d --- /dev/null +++ b/client/src/locales/de-DE/markdown-editor.json @@ -0,0 +1,165 @@ +{ + "action-previews": { + "text": "Dies ist ein Text ohne Titel.\nSowohl der Titel als auch der Text\nkönnen fett, kursiv, farbig,\ndurchgestrichen und unterstrichen hervorgehoben werden.", + "text-with-head": "Dies ist ein Text mit einem Titel.\nSowohl der Titel als auch der Text\nkönnen fett, kursiv, farbig,\ndurchgestrichen und unterstrichen hervorgehoben werden.", + "heading": "Titel" + }, + "bundle": { + "error-title": "Fehler im Markdown-Editor", + "settings_wysiwyg": "Visueller Editor (WYSIWYG)", + "settings_markup": "Markdown-Auszeichnung", + "markup_placeholder": "Markdown-Auszeichnung eingeben..." + }, + "codeblock": { + "remove": "Entfernen", + "empty_option": "Keine Übereinstimmungen gefunden" + }, + "common": { + "delete": "Löschen", + "edit": "Bearbeiten", + "toolbar_action_disabled": "Inkompatibles Markup-Element" + }, + "forms": { + "common_action_cancel": "Abbrechen", + "common_action_submit": "Absenden", + "common_action_upload": "Auswählen", + "common_tab_attach": "Vom Gerät hinzufügen", + "common_tab_link": "Per Link hinzufügen", + "common_link": "Link", + "common_sizes": "Größe, px", + "image_name": "Titel", + "image_link_href": "Bildlink", + "image_link_href_help": "Adresse, zu der der Bildlink führt.", + "image_alt": "Alternativtext", + "image_alt_help": "Der Alternativtext wird angezeigt, wenn das Bild nicht geladen werden kann.", + "image_upload_help": "JPEG-, GIF- oder PNG-Bild mit maximal 1 MB.", + "image_upload_failed": "Bild konnte nicht hinzugefügt werden", + "image_size_width": "Breite", + "image_size_height": "Höhe", + "link_url_help": "Adresse, zu der der Link führt.", + "link_text": "Linktext", + "link_text_help": "Text, der als Link angezeigt wird.", + "link_open_help": "Link in neuem Tab öffnen" + }, + "md-hints": { + "header_title": "Überschrift", + "header_hint": "# Dein Text", + "italic_title": "Kursiv", + "italic_hint": "_Dein Text_", + "bold_title": "Fett", + "bold_hint": "**Dein Text**", + "strikethrough_title": "Durchgestrichen", + "strikethrough_hint": "~~Dein Text~~", + "blockquote_title": "Blockzitat", + "blockquote_hint": "> Dein Text", + "code_title": "Code", + "code_hint": "```Dein Text```", + "link_title": "Link", + "link_hint": "[Dein Text](URL)", + "image_title": "Bild", + "image_hint": "![Dein Text](URL)", + "list_title": "Listenelement", + "list_hint": "- Dein Text", + "numbered-list_title": "Nummerierte Liste", + "numbered-list_hint": "1. Dein Text", + "documentation": "Dokumentation", + "documentation_link": " https://diplodoc.com/docs/en/syntax/" + }, + "menubar": { + "bold": "Fett", + "code": "Code", + "code_inline": "Inline-Code", + "codeblock": "Codeblock", + "colorify": "Textfarbe", + "colorify__color_blue": "Blau", + "colorify__color_default": "Standard", + "colorify__color_gray": "Grau", + "colorify__color_green": "Grün", + "colorify__color_orange": "Orange", + "colorify__color_red": "Rot", + "colorify__color_violet": "Violett", + "colorify__color_yellow": "Gelb", + "colorify__group_text": "Text", + "cut": "Ausschneiden", + "emoji": "Emoji", + "emoji__hint": "Emojis können im WYSIWYG-Editor hinzugefügt oder manuell mit Markup eingefügt werden", + "heading": "Überschrift", + "heading1": "Überschrift 1", + "heading2": "Überschrift 2", + "heading3": "Überschrift 3", + "heading4": "Überschrift 4", + "heading5": "Überschrift 5", + "heading6": "Überschrift 6", + "hrule": "Trennlinie", + "image": "Bild", + "italic": "Kursiv", + "link": "Link", + "list": "Liste", + "list__action_lift": "Element anheben", + "list__action_sink": "Element einrücken", + "list_action_disabled": "Widerspricht der Logik der Liste", + "mark": "Markiert", + "mono": "Monospace", + "more_action": "Weitere Aktionen", + "note": "Hinweis", + "olist": "Geordnete Liste", + "quote": "Zitat", + "redo": "Wiederherstellen", + "strike": "Durchgestrichen", + "table": "Tabelle", + "text": "Text", + "ulist": "Aufzählungsliste", + "underline": "Unterstrichen", + "undo": "Rückgängig" + }, + "placeholder": { + "doc_empty": "Tippe / für Slashbefehle...", + "checkbox": "Aufgabenbeschreibung eingeben...", + "deflist_term": "Begriff", + "deflist_desc": "Definitionsbeschreibung", + "heading": "Überschrift", + "cut_title": "Titel", + "cut_content": "Inhalt, der beim Klicken angezeigt wird", + "note_title": "Titel", + "note_content": "Hinweisinhalt", + "table_cell": "Zelleninhalt", + "select_filter": "Sprachen durchsuchen..." + }, + "search": { + "label_case-sensitive": "Groß-/Kleinschreibung beachten", + "label_whole-word": "Ganzes Wort", + "title": "Im Code suchen" + }, + "suggest": { + "empty-msg": "Nicht gefunden" + }, + "widgets": { + "image": "Bild hinzufügen", + "link": "Link hinzufügen" + }, + "yfm-note": { + "info": "Hinweis", + "tip": "Tipp", + "warning": "Warnung", + "alert": "Alarm", + "remove": "Entfernen" + }, + "yfm-table": { + "column.add.before": "Spalte davor einfügen", + "column.add.after": "Spalte danach einfügen", + "column.remove": "Spalte entfernen", + "row.add.before": "Zeile davor einfügen", + "row.add.after": "Zeile danach einfügen", + "row.remove": "Zeile entfernen", + "table.remove": "Tabelle entfernen", + "table.menu.cell.align.left": "Zelleninhalt linksbündig ausrichten", + "table.menu.cell.align.right": "Zelleninhalt rechtsbündig ausrichten", + "table.menu.cell.align.center": "Zelleninhalt zentrieren", + "table.menu.row.add": "Zeile danach einfügen", + "table.menu.row.remove": "Zeile entfernen", + "table.menu.column.add": "Spalte danach einfügen", + "table.menu.column.remove": "Spalte entfernen", + "table.menu.convert.yfm": "In YFM-Tabelle umwandeln", + "table.menu.table.remove": "Tabelle entfernen" + } +} From f6568ce41b0e759254bf67419d7bfab2880a7be0 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 17 May 2025 01:50:40 +0200 Subject: [PATCH 017/121] feat: Add notification when user is added to card --- .../components/activities/Activities/Item.jsx | 30 +++++++ .../notifications/NotificationsStep/Item.jsx | 18 ++++ client/src/constants/Enums.js | 2 + client/src/locales/en-GB/core.js | 3 + client/src/locales/en-US/core.js | 3 + .../controllers/card-memberships/create.js | 10 ++- server/api/helpers/actions/create-one.js | 87 ++++++++++++------- .../helpers/card-memberships/create-one.js | 20 ++++- .../api/helpers/notifications/create-one.js | 27 ++++++ server/api/models/Action.js | 1 + server/api/models/Notification.js | 1 + server/config/locales/en-GB.json | 2 + server/config/locales/en-US.json | 2 + server/config/locales/ru-RU.json | 2 + 14 files changed, 169 insertions(+), 39 deletions(-) diff --git a/client/src/components/activities/Activities/Item.jsx b/client/src/components/activities/Activities/Item.jsx index 7768f415..181e5970 100755 --- a/client/src/components/activities/Activities/Item.jsx +++ b/client/src/components/activities/Activities/Item.jsx @@ -84,6 +84,36 @@ const Item = React.memo(({ id }) => { break; } + case ActivityTypes.ADD_MEMBER_TO_CARD: + contentNode = + user.id === activity.data.user.id ? ( + + {userName} + {' joined this card'} + + ) : ( + + {userName} + + {' added '} + {activity.data.user.name} + {' to this card'} + + + ); + + break; default: contentNode = null; } diff --git a/client/src/components/notifications/NotificationsStep/Item.jsx b/client/src/components/notifications/NotificationsStep/Item.jsx index 7679fddc..69c65b5b 100644 --- a/client/src/components/notifications/NotificationsStep/Item.jsx +++ b/client/src/components/notifications/NotificationsStep/Item.jsx @@ -103,6 +103,24 @@ const Item = React.memo(({ id, onClose }) => { break; } + case NotificationTypes.ADD_MEMBER_TO_CARD: + contentNode = ( + + {creatorUserName} + {` added you to `} + + {cardName} + + + ); + + break; default: contentNode = null; } diff --git a/client/src/constants/Enums.js b/client/src/constants/Enums.js index 219d10b0..0cfcf20a 100755 --- a/client/src/constants/Enums.js +++ b/client/src/constants/Enums.js @@ -90,11 +90,13 @@ export const AttachmentTypes = { export const ActivityTypes = { CREATE_CARD: 'createCard', MOVE_CARD: 'moveCard', + ADD_MEMBER_TO_CARD: 'addMemberToCard', }; export const NotificationTypes = { MOVE_CARD: 'moveCard', COMMENT_CARD: 'commentCard', + ADD_MEMBER_TO_CARD: 'addMemberToCard', }; export const NotificationServiceFormats = { diff --git a/client/src/locales/en-GB/core.js b/client/src/locales/en-GB/core.js index f5c256d8..d19b63a2 100644 --- a/client/src/locales/en-GB/core.js +++ b/client/src/locales/en-GB/core.js @@ -287,6 +287,9 @@ export default { uploadedImages: 'Uploaded images', userActions_title: 'User Actions', userAddedThisCardToList: '<0>{{user}}<1> added this card to {{list}}', + userAddedUserToThisCard: '<0>{{actorUser}}<1> added {{addedUser}} to this card', + userAddedYouToCard: '{{user}} added you to <2>{{card}}', + userJoinedThisCard: `<0>{{user}}<1> joined this card`, userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}', userMovedCardFromListToList: '{{user}} moved <2>{{card}} from {{fromList}} to {{toList}}', userMovedThisCardFromListToList: diff --git a/client/src/locales/en-US/core.js b/client/src/locales/en-US/core.js index 0b0345e8..468eb945 100644 --- a/client/src/locales/en-US/core.js +++ b/client/src/locales/en-US/core.js @@ -282,6 +282,9 @@ export default { uploadedImages: 'Uploaded images', userActions_title: 'User Actions', userAddedThisCardToList: '<0>{{user}}<1> added this card to {{list}}', + userAddedUserToThisCard: '<0>{{actorUser}}<1> added {{addedUser}} to this card', + userAddedYouToCard: '{{user}} added you to <2>{{card}}', + userJoinedThisCard: `<0>{{user}}<1> joined this card`, userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}', userMovedCardFromListToList: '{{user}} moved <2>{{card}} from {{fromList}} to {{toList}}', userMovedThisCardFromListToList: diff --git a/server/api/controllers/card-memberships/create.js b/server/api/controllers/card-memberships/create.js index 5d3aa4c7..c5750764 100755 --- a/server/api/controllers/card-memberships/create.js +++ b/server/api/controllers/card-memberships/create.js @@ -67,7 +67,13 @@ module.exports = { throw Errors.NOT_ENOUGH_RIGHTS; } - const isBoardMember = await sails.helpers.users.isBoardMember(inputs.userId, board.id); + const user = await User.qm.getOneById(inputs.userId); + + if (!user) { + throw Errors.USER_NOT_FOUND; + } + + const isBoardMember = await sails.helpers.users.isBoardMember(user.id, board.id); if (!isBoardMember) { throw Errors.USER_NOT_FOUND; @@ -80,7 +86,7 @@ module.exports = { list, values: { card, - userId: inputs.userId, + user, }, actorUser: currentUser, request: this.req, diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js index 8aa73fd3..ca23d358 100644 --- a/server/api/helpers/actions/create-one.js +++ b/server/api/helpers/actions/create-one.js @@ -143,55 +143,76 @@ module.exports = { }); if (action.type !== Action.Types.CREATE_CARD) { - const cardSubscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds( - action.cardId, - action.userId, - ); - - const boardSubscriptionUserIds = await sails.helpers.boards.getSubscriptionUserIds( - inputs.board.id, - action.userId, - ); - - const notifiableUserIds = _.union(cardSubscriptionUserIds, boardSubscriptionUserIds); - - await Promise.all( - notifiableUserIds.map((userId) => - sails.helpers.notifications.createOne.with({ + if (action.type === Action.Types.ADD_MEMBER_TO_CARD) { + if (values.user !== action.data.user.id) { + await sails.helpers.notifications.createOne.with({ values: { - userId, action, type: action.type, data: { ...action.data, card: _.pick(values.card, ['name']), }, + userId: action.data.user.id, creatorUser: values.user, card: values.card, }, project: inputs.project, board: inputs.board, list: inputs.list, - }), - ), - ); - } + }); + } + } else { + const cardSubscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds( + action.cardId, + action.userId, + ); - const notificationServices = await NotificationService.qm.getByBoardId(inputs.board.id); + const boardSubscriptionUserIds = await sails.helpers.boards.getSubscriptionUserIds( + inputs.board.id, + action.userId, + ); - if (notificationServices.length > 0) { - const services = notificationServices.map((notificationService) => - _.pick(notificationService, ['url', 'format']), - ); + const notifiableUserIds = _.union(cardSubscriptionUserIds, boardSubscriptionUserIds); - buildAndSendNotifications( - services, - inputs.board, - values.card, - action, - values.user, - sails.helpers.utils.makeTranslator(), - ); + await Promise.all( + notifiableUserIds.map((userId) => + sails.helpers.notifications.createOne.with({ + values: { + userId, + action, + type: action.type, + data: { + ...action.data, + card: _.pick(values.card, ['name']), + }, + creatorUser: values.user, + card: values.card, + }, + project: inputs.project, + board: inputs.board, + list: inputs.list, + }), + ), + ); + + const notificationServices = await NotificationService.qm.getByBoardId(inputs.board.id); + + if (notificationServices.length > 0) { + const services = notificationServices.map((notificationService) => + _.pick(notificationService, ['url', 'format']), + ); + + buildAndSendNotifications( + services, + inputs.board, + values.card, + action, + values.user, + sails.helpers.utils.makeTranslator(), + ); + } + } } return action; diff --git a/server/api/helpers/card-memberships/create-one.js b/server/api/helpers/card-memberships/create-one.js index bb41285e..b66fd2fb 100644 --- a/server/api/helpers/card-memberships/create-one.js +++ b/server/api/helpers/card-memberships/create-one.js @@ -37,15 +37,12 @@ module.exports = { async fn(inputs) { const { values } = inputs; - if (values.user) { - values.userId = values.user.id; - } - let cardMembership; try { cardMembership = await CardMembership.qm.createOne({ ...values, cardId: values.card.id, + userId: values.user.id, }); } catch (error) { if (error.code === 'E_UNIQUE') { @@ -69,6 +66,7 @@ module.exports = { buildData: () => ({ item: cardMembership, included: { + users: [values.user], projects: [inputs.project], boards: [inputs.board], lists: [inputs.list], @@ -107,6 +105,20 @@ module.exports = { // TODO: send webhooks } + await sails.helpers.actions.createOne.with({ + values: { + type: Action.Types.ADD_MEMBER_TO_CARD, + data: { + user: _.pick(values.user, ['id', 'name']), + }, + user: inputs.actorUser, + card: values.card, + }, + project: inputs.project, + board: inputs.board, + list: inputs.list, + }); + return cardMembership; }, }; diff --git a/server/api/helpers/notifications/create-one.js b/server/api/helpers/notifications/create-one.js index 63ff59f1..990e6a41 100644 --- a/server/api/helpers/notifications/create-one.js +++ b/server/api/helpers/notifications/create-one.js @@ -12,6 +12,8 @@ const buildTitle = (notification, t) => { return t('Card Moved'); case Notification.Types.COMMENT_CARD: return t('New Comment'); + case Notification.Types.ADD_MEMBER_TO_CARD: + return t('You Were Added to Card'); default: return null; } @@ -77,6 +79,22 @@ const buildBodyByFormat = (board, card, notification, actorUser, t) => { )}:\n\n${escapeHtml(commentText)}`, }; } + case Notification.Types.ADD_MEMBER_TO_CARD: + return { + text: t('%s added you to %s on %s', actorUser.name, card.name, board.name), + markdown: t( + '%s added you to %s on %s', + escapeMarkdown(actorUser.name), + markdownCardLink, + escapeMarkdown(board.name), + ), + html: t( + '%s added you to %s on %s', + escapeHtml(actorUser.name), + htmlCardLink, + escapeHtml(board.name), + ), + }; default: return null; } @@ -120,6 +138,15 @@ const buildAndSendEmail = async (board, card, notification, actorUser, notifiabl boardLink, )}

${escapeHtml(notification.data.text)}

`; + break; + case Notification.Types.ADD_MEMBER_TO_CARD: + html = `

${t( + '%s added you to %s on %s', + escapeHtml(actorUser.name), + cardLink, + boardLink, + )}

`; + break; default: return; diff --git a/server/api/models/Action.js b/server/api/models/Action.js index 59921b45..6fd8711f 100755 --- a/server/api/models/Action.js +++ b/server/api/models/Action.js @@ -13,6 +13,7 @@ const Types = { CREATE_CARD: 'createCard', MOVE_CARD: 'moveCard', + ADD_MEMBER_TO_CARD: 'addMemberToCard', }; module.exports = { diff --git a/server/api/models/Notification.js b/server/api/models/Notification.js index c970d7dd..2fdfde03 100755 --- a/server/api/models/Notification.js +++ b/server/api/models/Notification.js @@ -13,6 +13,7 @@ const Types = { MOVE_CARD: 'moveCard', COMMENT_CARD: 'commentCard', + ADD_MEMBER_TO_CARD: 'addMemberToCard', }; module.exports = { diff --git a/server/config/locales/en-GB.json b/server/config/locales/en-GB.json index 30d4f65b..9e9c1322 100644 --- a/server/config/locales/en-GB.json +++ b/server/config/locales/en-GB.json @@ -6,6 +6,8 @@ "This is a test text message!": "This is a test text message!", "This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!", "This is a test html message": "This is a test html message", + "You Were Added to Card": "Your Were Added to Card", + "%s added you to %s on %s": "%s added you to %s on %s", "%s created %s in %s on %s": "%s created %s in %s on %s", "%s left a new comment to %s on %s": "%s left a new comment to %s on %s", "%s moved %s from %s to %s on %s": "%s moved %s from %s to %s on %s" diff --git a/server/config/locales/en-US.json b/server/config/locales/en-US.json index c5190d91..f9b9b376 100644 --- a/server/config/locales/en-US.json +++ b/server/config/locales/en-US.json @@ -6,6 +6,8 @@ "This is a test text message!": "This is a test text message!", "This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!", "This is a test html message": "This is a test html message", + "You Were Added to Card": "Your Were Added to Card", + "%s added you to %s on %s": "%s added you to %s on %s", "%s created %s in %s on %s": "%s created %s in %s on %s", "%s left a new comment to %s on %s": "%s left a new comment to %s on %s", "%s moved %s from %s to %s on %s": "%s moved %s from %s to %s on %s" diff --git a/server/config/locales/ru-RU.json b/server/config/locales/ru-RU.json index bc6bebd2..6f300160 100644 --- a/server/config/locales/ru-RU.json +++ b/server/config/locales/ru-RU.json @@ -6,6 +6,8 @@ "This is a test text message!": "Это тестовое сообщение!", "This is a *test* **markdown** `message`!": "Это *тестовое* **markdown** `сообщение`!", "This is a test html message": "Это тестовое html сообщение", + "You Were Added to Card": "Вы были добавлены к карточке", + "%s added you to %s on %s": "%s добавил(а) вас к %s на %s", "%s created %s in %s on %s": "%s создал(а) %s в %s на %s", "%s left a new comment to %s on %s": "%s оставил(а) новый комментарий к %s на %s", "%s moved %s from %s to %s on %s": "%s переместил(а) %s из %s в %s на %s" From eeb52d19bbab20405f58f2bfb8a106096369b73e Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 17 May 2025 15:40:43 +0200 Subject: [PATCH 018/121] feat: Enhance card emphasis in colored and closed lists Closes #428, closes #506 --- client/src/components/cards/Card/Card.jsx | 40 +++++++++---------- .../components/cards/Card/Card.module.scss | 5 +++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/client/src/components/cards/Card/Card.jsx b/client/src/components/cards/Card/Card.jsx index c05e9112..dc78ef09 100755 --- a/client/src/components/cards/Card/Card.jsx +++ b/client/src/components/cards/Card/Card.jsx @@ -3,16 +3,17 @@ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md */ +import upperFirst from 'lodash/upperFirst'; +import camelCase from 'lodash/camelCase'; import React, { useCallback, useMemo, useState } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { shallowEqual, useDispatch, useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { Button, Icon } from 'semantic-ui-react'; import { push } from '../../../lib/redux-router'; import { usePopup } from '../../../lib/popup'; import selectors from '../../../selectors'; -import { isListArchiveOrTrash } from '../../../utils/record-helpers'; import Paths from '../../../constants/Paths'; import { BoardMembershipRoles, CardTypes, ListTypes } from '../../../constants/Enums'; import ProjectContent from './ProjectContent'; @@ -22,6 +23,7 @@ import EditName from './EditName'; import ActionsStep from './ActionsStep'; import styles from './Card.module.scss'; +import globalStyles from '../../../styles.module.scss'; const Card = React.memo(({ id, isInline }) => { const selectCardById = useMemo(() => selectors.makeSelectCardById(), []); @@ -29,6 +31,7 @@ const Card = React.memo(({ id, isInline }) => { const selectListById = useMemo(() => selectors.makeSelectListById(), []); const card = useSelector((state) => selectCardById(state, id)); + const list = useSelector((state) => selectListById(state, card.listId)); const isHighlightedAsRecent = useSelector((state) => { const { turnOffRecentCardHighlighting } = selectors.selectCurrentUser(state); @@ -40,24 +43,10 @@ const Card = React.memo(({ id, isInline }) => { return selectIsCardWithIdRecent(state, id); }); - const { isDisabled, canUseActions } = useSelector((state) => { - const list = selectListById(state, card.listId); - + const canUseActions = useSelector((state) => { const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); - const isEditor = !!boardMembership && boardMembership.role === BoardMembershipRoles.EDITOR; - - if (isListArchiveOrTrash(list)) { - return { - isDisabled: false, - canUseActions: isEditor, - }; - } - - return { - isDisabled: list.type === ListTypes.CLOSED && !isEditor, - canUseActions: isEditor, - }; - }, shallowEqual); + return !!boardMembership && boardMembership.role === BoardMembershipRoles.EDITOR; + }); const dispatch = useDispatch(); const [isEditNameOpened, setIsEditNameOpened] = useState(false); @@ -101,11 +90,20 @@ const Card = React.memo(({ id, isInline }) => { } } + const colorLineNode = list.color && ( +
+ ); + return (
{ jsx-a11y/no-static-element-interactions */}
+ {colorLineNode}
{canUseActions && ( @@ -128,6 +127,7 @@ const Card = React.memo(({ id, isInline }) => { ) : ( + {colorLineNode} )}
diff --git a/client/src/components/cards/Card/Card.module.scss b/client/src/components/cards/Card/Card.module.scss index 99dcee12..4e0c4681 100644 --- a/client/src/components/cards/Card/Card.module.scss +++ b/client/src/components/cards/Card/Card.module.scss @@ -28,6 +28,11 @@ } } + .colorLine { + border-radius: 0 0 3px 3px; + height: 4px; + } + .content { cursor: pointer; From 3aedbff5d0679f59b0042faef1a46f3706efb566 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 17 May 2025 22:24:37 +0200 Subject: [PATCH 019/121] feat: Log action when user is removed from card --- .../components/activities/Activities/Item.jsx | 30 ++++++++++++++++ client/src/constants/Enums.js | 1 + client/src/locales/en-GB/core.js | 3 ++ client/src/locales/en-US/core.js | 3 ++ .../controllers/card-memberships/create.js | 2 +- .../controllers/card-memberships/delete.js | 3 ++ server/api/helpers/actions/create-one.js | 34 ++++++++++--------- .../helpers/card-memberships/delete-one.js | 19 +++++++++++ server/api/models/Action.js | 8 +++++ 9 files changed, 86 insertions(+), 17 deletions(-) diff --git a/client/src/components/activities/Activities/Item.jsx b/client/src/components/activities/Activities/Item.jsx index 181e5970..e1901076 100755 --- a/client/src/components/activities/Activities/Item.jsx +++ b/client/src/components/activities/Activities/Item.jsx @@ -113,6 +113,36 @@ const Item = React.memo(({ id }) => { ); + break; + case ActivityTypes.REMOVE_MEMBER_FROM_CARD: + contentNode = + user.id === activity.data.user.id ? ( + + {userName} + {' left this card'} + + ) : ( + + {userName} + + {' removed '} + {activity.data.user.name} + {' from this card'} + + + ); + break; default: contentNode = null; diff --git a/client/src/constants/Enums.js b/client/src/constants/Enums.js index 0cfcf20a..02f591cf 100755 --- a/client/src/constants/Enums.js +++ b/client/src/constants/Enums.js @@ -91,6 +91,7 @@ export const ActivityTypes = { CREATE_CARD: 'createCard', MOVE_CARD: 'moveCard', ADD_MEMBER_TO_CARD: 'addMemberToCard', + REMOVE_MEMBER_FROM_CARD: 'removeMemberFromCard', }; export const NotificationTypes = { diff --git a/client/src/locales/en-GB/core.js b/client/src/locales/en-GB/core.js index d19b63a2..688eebf2 100644 --- a/client/src/locales/en-GB/core.js +++ b/client/src/locales/en-GB/core.js @@ -291,9 +291,12 @@ export default { userAddedYouToCard: '{{user}} added you to <2>{{card}}', userJoinedThisCard: `<0>{{user}}<1> joined this card`, userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}', + userLeftThisCard: '<0>{{user}}<1> left this card', userMovedCardFromListToList: '{{user}} moved <2>{{card}} from {{fromList}} to {{toList}}', userMovedThisCardFromListToList: '<0>{{user}}<1> moved this card from {{fromList}} to {{toList}}', + userRemovedUserFromThisCard: + '<0>{{actorUser}}<1> removed {{removedUser}} from this card', username: 'Username', users: 'Users', viewer: 'Viewer', diff --git a/client/src/locales/en-US/core.js b/client/src/locales/en-US/core.js index 468eb945..50487bd3 100644 --- a/client/src/locales/en-US/core.js +++ b/client/src/locales/en-US/core.js @@ -286,9 +286,12 @@ export default { userAddedYouToCard: '{{user}} added you to <2>{{card}}', userJoinedThisCard: `<0>{{user}}<1> joined this card`, userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}', + userLeftThisCard: '<0>{{user}}<1> left this card', userMovedCardFromListToList: '{{user}} moved <2>{{card}} from {{fromList}} to {{toList}}', userMovedThisCardFromListToList: '<0>{{user}}<1> moved this card from {{fromList}} to {{toList}}', + userRemovedUserFromThisCard: + '<0>{{actorUser}}<1> removed {{removedUser}} from this card', username: 'Username', users: 'Users', viewer: 'Viewer', diff --git a/server/api/controllers/card-memberships/create.js b/server/api/controllers/card-memberships/create.js index c5750764..e0199150 100755 --- a/server/api/controllers/card-memberships/create.js +++ b/server/api/controllers/card-memberships/create.js @@ -76,7 +76,7 @@ module.exports = { const isBoardMember = await sails.helpers.users.isBoardMember(user.id, board.id); if (!isBoardMember) { - throw Errors.USER_NOT_FOUND; + throw Errors.USER_NOT_FOUND; // Forbidden } const cardMembership = await sails.helpers.cardMemberships.createOne diff --git a/server/api/controllers/card-memberships/delete.js b/server/api/controllers/card-memberships/delete.js index 73857573..ec70c435 100755 --- a/server/api/controllers/card-memberships/delete.js +++ b/server/api/controllers/card-memberships/delete.js @@ -70,7 +70,10 @@ module.exports = { throw Errors.USER_NOT_CARD_MEMBER; } + const user = await User.qm.getOneById(cardMembership.userId); + cardMembership = await sails.helpers.cardMemberships.deleteOne.with({ + user, project, board, list, diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js index ca23d358..ed35b5e7 100644 --- a/server/api/helpers/actions/create-one.js +++ b/server/api/helpers/actions/create-one.js @@ -142,8 +142,8 @@ module.exports = { user: values.user, }); - if (action.type !== Action.Types.CREATE_CARD) { - if (action.type === Action.Types.ADD_MEMBER_TO_CARD) { + if (Action.INTERNAL_NOTIFIABLE_TYPES.includes(action.type)) { + if (Action.PERSONAL_NOTIFIABLE_TYPES.includes(action.type)) { if (values.user !== action.data.user.id) { await sails.helpers.notifications.createOne.with({ values: { @@ -195,23 +195,25 @@ module.exports = { }), ), ); + } + } - const notificationServices = await NotificationService.qm.getByBoardId(inputs.board.id); + if (Action.EXTERNAL_NOTIFIABLE_TYPES.includes(action.type)) { + const notificationServices = await NotificationService.qm.getByBoardId(inputs.board.id); - if (notificationServices.length > 0) { - const services = notificationServices.map((notificationService) => - _.pick(notificationService, ['url', 'format']), - ); + if (notificationServices.length > 0) { + const services = notificationServices.map((notificationService) => + _.pick(notificationService, ['url', 'format']), + ); - buildAndSendNotifications( - services, - inputs.board, - values.card, - action, - values.user, - sails.helpers.utils.makeTranslator(), - ); - } + buildAndSendNotifications( + services, + inputs.board, + values.card, + action, + values.user, + sails.helpers.utils.makeTranslator(), + ); } } diff --git a/server/api/helpers/card-memberships/delete-one.js b/server/api/helpers/card-memberships/delete-one.js index f9ed0470..659bb90a 100644 --- a/server/api/helpers/card-memberships/delete-one.js +++ b/server/api/helpers/card-memberships/delete-one.js @@ -9,6 +9,10 @@ module.exports = { type: 'ref', required: true, }, + user: { + type: 'ref', + required: true, + }, project: { type: 'ref', required: true, @@ -52,6 +56,7 @@ module.exports = { buildData: () => ({ item: cardMembership, included: { + users: [inputs.user], projects: [inputs.project], boards: [inputs.board], lists: [inputs.list], @@ -75,6 +80,20 @@ module.exports = { }, }); } + + await sails.helpers.actions.createOne.with({ + values: { + type: Action.Types.REMOVE_MEMBER_FROM_CARD, + data: { + user: _.pick(inputs.user, ['id', 'name']), + }, + user: inputs.actorUser, + card: inputs.card, + }, + project: inputs.project, + board: inputs.board, + list: inputs.list, + }); } return cardMembership; diff --git a/server/api/models/Action.js b/server/api/models/Action.js index 6fd8711f..888d34f1 100755 --- a/server/api/models/Action.js +++ b/server/api/models/Action.js @@ -14,10 +14,18 @@ const Types = { CREATE_CARD: 'createCard', MOVE_CARD: 'moveCard', ADD_MEMBER_TO_CARD: 'addMemberToCard', + REMOVE_MEMBER_FROM_CARD: 'removeMemberFromCard', }; +const INTERNAL_NOTIFIABLE_TYPES = [Types.MOVE_CARD, Types.ADD_MEMBER_TO_CARD]; +const EXTERNAL_NOTIFIABLE_TYPES = [Types.CREATE_CARD, Types.MOVE_CARD]; +const PERSONAL_NOTIFIABLE_TYPES = [Types.ADD_MEMBER_TO_CARD]; + module.exports = { Types, + INTERNAL_NOTIFIABLE_TYPES, + EXTERNAL_NOTIFIABLE_TYPES, + PERSONAL_NOTIFIABLE_TYPES, attributes: { // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ From 652c5e9475f792d62ce794ad47e80070d75aeef5 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Mon, 19 May 2025 17:27:18 +0200 Subject: [PATCH 020/121] fix: Use batch inserts to avoid query size limits --- server/db/upgrade.js | 551 +++++++++++++++++++++++-------------------- 1 file changed, 300 insertions(+), 251 deletions(-) diff --git a/server/db/upgrade.js b/server/db/upgrade.js index 16ea33cd..d3ca37ed 100644 --- a/server/db/upgrade.js +++ b/server/db/upgrade.js @@ -97,50 +97,53 @@ const upgradeDatabase = async () => { const whereInUserIds = ['0', ...userIds]; if (users.length > 0) { - await trx('user_account').insert( - users.map((user) => ({ - ..._.pick(user, [ - 'id', - 'email', - 'password', - 'name', - 'username', - 'phone', - 'organization', - 'language', - 'subscribe_to_own_cards', - 'created_at', - 'updated_at', - 'password_changed_at', - ]), - role: user.is_admin ? User.Roles.ADMIN : User.Roles.BOARD_USER, - avatar: user.avatar && { - ...user.avatar, - sizeInBytes: 0, - }, - subscribe_to_card_when_commenting: true, - turn_off_recent_card_highlighting: false, - enable_favorites_by_default: false, - default_editor_mode: User.EditorModes.WYSIWYG, - default_home_view: User.HomeViews.GROUPED_PROJECTS, - default_projects_order: User.ProjectOrders.BY_DEFAULT, - is_sso_user: user.is_sso, - is_deactivated: false, - })), - ); + await knex + .batchInsert( + 'user_account', + users.map((user) => ({ + ..._.pick(user, [ + 'id', + 'email', + 'password', + 'name', + 'username', + 'phone', + 'organization', + 'language', + 'subscribe_to_own_cards', + 'created_at', + 'updated_at', + 'password_changed_at', + ]), + role: user.is_admin ? User.Roles.ADMIN : User.Roles.BOARD_USER, + avatar: user.avatar && { + ...user.avatar, + sizeInBytes: 0, + }, + subscribe_to_card_when_commenting: true, + turn_off_recent_card_highlighting: false, + enable_favorites_by_default: false, + default_editor_mode: User.EditorModes.WYSIWYG, + default_home_view: User.HomeViews.GROUPED_PROJECTS, + default_projects_order: User.ProjectOrders.BY_DEFAULT, + is_sso_user: user.is_sso, + is_deactivated: false, + })), + ) + .transacting(trx); const identityProviderUsers = await trx('identity_provider_user') .withSchema('v1') .whereIn('user_id', whereInUserIds); if (identityProviderUsers.length > 0) { - await trx('identity_provider_user').insert(identityProviderUsers); + await knex.batchInsert('identity_provider_user', identityProviderUsers).transacting(trx); } const sessions = await trx('session').withSchema('v1').whereIn('user_id', whereInUserIds); if (sessions.length > 0) { - await trx('session').insert(sessions); + await knex.batchInsert('session', sessions).transacting(trx); } } @@ -154,47 +157,53 @@ const upgradeDatabase = async () => { if (projectsWithBackgroundImage.length > 0) { const createdAt = new Date().toISOString(); - const backgroundImages = await trx('background_image').insert( - projectsWithBackgroundImage.map((project) => ({ - ...project.background_image, - project_id: project.id, - size_in_bytes: 0, - created_at: createdAt, - })), - ['id', 'project_id'], - ); + const backgroundImages = await knex + .batchInsert( + 'background_image', + projectsWithBackgroundImage.map((project) => ({ + ...project.background_image, + project_id: project.id, + size_in_bytes: 0, + created_at: createdAt, + })), + ) + .returning(['id', 'project_id']) + .transacting(trx); backgroundImages.forEach((backgroundImage) => { backgroundImageIdByProjectId[backgroundImage.project_id] = backgroundImage.id; }); } - await trx('project').insert( - projects.map((project) => { - const data = { - ..._.pick(project, ['id', 'name', 'created_at', 'updated_at']), - is_hidden: false, - }; + await knex + .batchInsert( + 'project', + projects.map((project) => { + const data = { + ..._.pick(project, ['id', 'name', 'created_at', 'updated_at']), + is_hidden: false, + }; - if (project.background) { - data.background_type = project.background.type; + if (project.background) { + data.background_type = project.background.type; - switch (project.background.type) { - case Project.BackgroundTypes.GRADIENT: - data.background_gradient = project.background.name; + switch (project.background.type) { + case Project.BackgroundTypes.GRADIENT: + data.background_gradient = project.background.name; - break; - case Project.BackgroundTypes.IMAGE: - data.background_image_id = backgroundImageIdByProjectId[project.id]; + break; + case Project.BackgroundTypes.IMAGE: + data.background_image_id = backgroundImageIdByProjectId[project.id]; - break; - default: + break; + default: + } } - } - return data; - }), - ); + return data; + }), + ) + .transacting(trx); } const projectManagers = await trx('project_manager') @@ -202,7 +211,7 @@ const upgradeDatabase = async () => { .whereIn('project_id', whereInProjectIds); if (projectManagers.length > 0) { - await trx('project_manager').insert(projectManagers); + await knex.batchInsert('project_manager', projectManagers).transacting(trx); } const boards = await trx('board').withSchema('v1').whereIn('project_id', whereInProjectIds); @@ -218,27 +227,33 @@ const upgradeDatabase = async () => { const whereInBoardIds = ['0', ...Object.keys(projectIdByBoardId)]; if (boards.length > 0) { - await trx('board').insert( - boards.map((board) => ({ - ..._.pick(board, ['id', 'project_id', 'position', 'name', 'created_at', 'updated_at']), - default_view: Board.Views.KANBAN, - default_card_type: Card.Types.PROJECT, - limit_card_types_to_default_one: false, - always_display_card_creator: false, - })), - ); + await knex + .batchInsert( + 'board', + boards.map((board) => ({ + ..._.pick(board, ['id', 'project_id', 'position', 'name', 'created_at', 'updated_at']), + default_view: Board.Views.KANBAN, + default_card_type: Card.Types.PROJECT, + limit_card_types_to_default_one: false, + always_display_card_creator: false, + })), + ) + .transacting(trx); const createdAt = new Date().toISOString(); - await trx('list').insert( - boards.flatMap((board) => - [List.Types.ARCHIVE, List.Types.TRASH].map((type) => ({ - type, - board_id: board.id, - created_at: createdAt, - })), - ), - ); + await knex + .batchInsert( + 'list', + boards.flatMap((board) => + [List.Types.ARCHIVE, List.Types.TRASH].map((type) => ({ + type, + board_id: board.id, + created_at: createdAt, + })), + ), + ) + .transacting(trx); } const boardMemberships = await trx('board_membership') @@ -246,46 +261,52 @@ const upgradeDatabase = async () => { .whereIn('board_id', whereInBoardIds); if (boardMemberships.length > 0) { - await trx('board_membership').insert( - boardMemberships.map((boardMembership) => ({ - ..._.pick(boardMembership, [ - 'id', - 'board_id', - 'user_id', - 'role', - 'can_comment', - 'created_at', - 'updated_at', - ]), - project_id: projectIdByBoardId[boardMembership.board_id], - })), - ); + await knex + .batchInsert( + 'board_membership', + boardMemberships.map((boardMembership) => ({ + ..._.pick(boardMembership, [ + 'id', + 'board_id', + 'user_id', + 'role', + 'can_comment', + 'created_at', + 'updated_at', + ]), + project_id: projectIdByBoardId[boardMembership.board_id], + })), + ) + .transacting(trx); } const labels = await trx('label').withSchema('v1').whereIn('board_id', whereInBoardIds); if (labels.length > 0) { - await trx('label').insert(labels); + await knex.batchInsert('label', labels).transacting(trx); } const lists = await trx('list').withSchema('v1').whereIn('board_id', whereInBoardIds); const whereInListIds = ['0', ...lists.map(({ id }) => id)]; if (lists.length > 0) { - await trx('list').insert( - lists.map((list) => ({ - ..._.pick(list, [ - 'id', - 'board_id', - 'position', - 'name', - 'color', - 'created_at', - 'updated_at', - ]), - type: List.Types.ACTIVE, - })), - ); + await knex + .batchInsert( + 'list', + lists.map((list) => ({ + ..._.pick(list, [ + 'id', + 'board_id', + 'position', + 'name', + 'color', + 'created_at', + 'updated_at', + ]), + type: List.Types.ACTIVE, + })), + ) + .transacting(trx); } const cards = await trx('card') @@ -297,26 +318,29 @@ const upgradeDatabase = async () => { const whereInCardIds = ['0', ...Object.keys(cardById)]; if (cards.length > 0) { - await trx('card').insert( - cards.map((card) => ({ - ..._.pick(card, [ - 'id', - 'board_id', - 'list_id', - 'cover_attachment_id', - 'position', - 'name', - 'description', - 'due_date', - 'stopwatch', - 'created_at', - 'updated_at', - ]), - creator_user_id: userIdsSet.has(card.creator_user_id) ? card.creator_user_id : null, - type: Card.Types.PROJECT, - list_changed_at: card.created_at, - })), - ); + await knex + .batchInsert( + 'card', + cards.map((card) => ({ + ..._.pick(card, [ + 'id', + 'board_id', + 'list_id', + 'cover_attachment_id', + 'position', + 'name', + 'description', + 'due_date', + 'stopwatch', + 'created_at', + 'updated_at', + ]), + creator_user_id: userIdsSet.has(card.creator_user_id) ? card.creator_user_id : null, + type: Card.Types.PROJECT, + list_changed_at: card.created_at, + })), + ) + .transacting(trx); } const cardSubscriptions = await trx('card_subscription') @@ -324,7 +348,7 @@ const upgradeDatabase = async () => { .whereIn('card_id', whereInCardIds); if (cardSubscriptions.length > 0) { - await trx('card_subscription').insert(cardSubscriptions); + await knex.batchInsert('card_subscription', cardSubscriptions).transacting(trx); } const cardMemberships = await trx('card_membership') @@ -332,13 +356,13 @@ const upgradeDatabase = async () => { .whereIn('card_id', whereInCardIds); if (cardMemberships.length > 0) { - await trx('card_membership').insert(cardMemberships); + await knex.batchInsert('card_membership', cardMemberships).transacting(trx); } const cardLabels = await trx('card_label').withSchema('v1').whereIn('card_id', whereInCardIds); if (cardLabels.length > 0) { - await trx('card_label').insert(cardLabels); + await knex.batchInsert('card_label', cardLabels).transacting(trx); } const tasks = await trx('task').withSchema('v1').whereIn('card_id', whereInCardIds); @@ -349,47 +373,63 @@ const upgradeDatabase = async () => { if (taskCardIds.length > 0) { const createdAt = new Date().toISOString(); - const taskLists = await trx('task_list').insert( - taskCardIds.map((cardId) => ({ - card_id: cardId, - position: POSITION_GAP, - name: 'Task List', - show_on_front_of_card: true, - created_at: createdAt, - })), - ['id', 'card_id'], - ); - - await trx('task').insert( - taskLists.flatMap((taskList) => - tasksByCardId[taskList.card_id].map((task) => ({ - ..._.pick(task, ['id', 'position', 'name', 'is_completed', 'created_at', 'updated_at']), - task_list_id: taskList.id, + const taskLists = await knex + .batchInsert( + 'task_list', + taskCardIds.map((cardId) => ({ + card_id: cardId, + position: POSITION_GAP, + name: 'Task List', + show_on_front_of_card: true, + created_at: createdAt, })), - ), - ); + ) + .returning(['id', 'card_id']) + .transacting(trx); + + await knex + .batchInsert( + 'task', + taskLists.flatMap((taskList) => + tasksByCardId[taskList.card_id].map((task) => ({ + ..._.pick(task, [ + 'id', + 'position', + 'name', + 'is_completed', + 'created_at', + 'updated_at', + ]), + task_list_id: taskList.id, + })), + ), + ) + .transacting(trx); } const attachments = await trx('attachment').withSchema('v1').whereIn('card_id', whereInCardIds); if (attachments.length > 0) { - await trx('attachment').insert( - attachments.map((attachment) => ({ - ..._.pick(attachment, ['id', 'card_id', 'name', 'created_at', 'updated_at']), - creator_user_id: userIdsSet.has(attachment.creator_user_id) - ? attachment.creator_user_id - : null, - type: Attachment.Types.FILE, - data: { - fileReferenceId: attachment.dirname, - filename: attachment.filename, - mimeType: mime.getType(attachment.filename), - sizeInBytes: 0, - encoding: null, - image: attachment.image, - }, - })), - ); + await knex + .batchInsert( + 'attachment', + attachments.map((attachment) => ({ + ..._.pick(attachment, ['id', 'card_id', 'name', 'created_at', 'updated_at']), + creator_user_id: userIdsSet.has(attachment.creator_user_id) + ? attachment.creator_user_id + : null, + type: Attachment.Types.FILE, + data: { + fileReferenceId: attachment.dirname, + filename: attachment.filename, + mimeType: mime.getType(attachment.filename), + sizeInBytes: 0, + encoding: null, + image: attachment.image, + }, + })), + ) + .transacting(trx); } const actions = await trx('action').withSchema('v1').whereIn('card_id', whereInCardIds); @@ -409,52 +449,58 @@ const upgradeDatabase = async () => { }); if (commentActions.length > 0) { - await trx('comment').insert( - commentActions.map((action) => ({ - ..._.pick(action, ['id', 'card_id', 'created_at', 'updated_at']), - user_id: userIdsSet.has(action.user_id) ? action.user_id : null, - text: action.data.text, - })), - ); + await knex + .batchInsert( + 'comment', + commentActions.map((action) => ({ + ..._.pick(action, ['id', 'card_id', 'created_at', 'updated_at']), + user_id: userIdsSet.has(action.user_id) ? action.user_id : null, + text: action.data.text, + })), + ) + .transacting(trx); } if (otherActions.length > 0) { - await trx('action').insert( - otherActions.map((action) => { - const data = { - ..._.pick(action, ['id', 'card_id', 'type', 'created_at', 'updated_at']), - user_id: userIdsSet.has(action.user_id) ? action.user_id : null, - }; + await knex + .batchInsert( + 'action', + otherActions.map((action) => { + const data = { + ..._.pick(action, ['id', 'card_id', 'type', 'created_at', 'updated_at']), + user_id: userIdsSet.has(action.user_id) ? action.user_id : null, + }; - switch (action.type) { - case Action.Types.CREATE_CARD: - data.data = { - list: { - ...action.data.list, - type: List.Types.ACTIVE, - }, - }; + switch (action.type) { + case Action.Types.CREATE_CARD: + data.data = { + list: { + ...action.data.list, + type: List.Types.ACTIVE, + }, + }; - break; - case Action.Types.MOVE_CARD: - data.data = { - fromList: { - ...action.data.fromList, - type: List.Types.ACTIVE, - }, - toList: { - ...action.data.toList, - type: List.Types.ACTIVE, - }, - }; + break; + case Action.Types.MOVE_CARD: + data.data = { + fromList: { + ...action.data.fromList, + type: List.Types.ACTIVE, + }, + toList: { + ...action.data.toList, + type: List.Types.ACTIVE, + }, + }; - break; - default: - } + break; + default: + } - return data; - }), - ); + return data; + }), + ) + .transacting(trx); } const notifications = await trx('notification') @@ -464,55 +510,58 @@ const upgradeDatabase = async () => { .whereIn('card_id', whereInCardIds); if (notifications.length > 0) { - await trx('notification').insert( - notifications.map((notification) => { - const card = cardById[notification.card_id]; - const action = actionById[notification.action_id]; + await knex + .batchInsert( + 'notification', + notifications.map((notification) => { + const card = cardById[notification.card_id]; + const action = actionById[notification.action_id]; - const data = { - ..._.pick(notification, [ - 'id', - 'user_id', - 'card_id', - 'is_read', - 'created_at', - 'updated_at', - ]), - creator_user_id: userIdsSet.has(notification.creator_user_id) - ? notification.creator_user_id - : null, - board_id: card.board_id, - type: action.type, - }; + const data = { + ..._.pick(notification, [ + 'id', + 'user_id', + 'card_id', + 'is_read', + 'created_at', + 'updated_at', + ]), + creator_user_id: userIdsSet.has(notification.creator_user_id) + ? notification.creator_user_id + : null, + board_id: card.board_id, + type: action.type, + }; - if (action.type === PrevActionTypes.COMMENT_CARD) { - Object.assign(data, { - comment_id: action.id, - data: { - card: _.pick(card, ['name']), - text: action.data.text, - }, - }); - } else { - Object.assign(data, { - action_id: action.id, - data: { - fromList: { - ...action.data.fromList, - type: List.Types.ACTIVE, + if (action.type === PrevActionTypes.COMMENT_CARD) { + Object.assign(data, { + comment_id: action.id, + data: { + card: _.pick(card, ['name']), + text: action.data.text, }, - toList: { - ...action.data.toList, - type: List.Types.ACTIVE, + }); + } else { + Object.assign(data, { + action_id: action.id, + data: { + fromList: { + ...action.data.fromList, + type: List.Types.ACTIVE, + }, + toList: { + ...action.data.toList, + type: List.Types.ACTIVE, + }, + card: _.pick(card, ['name']), }, - card: _.pick(card, ['name']), - }, - }); - } + }); + } - return data; - }), - ); + return data; + }), + ) + .transacting(trx); } await trx.schema.dropSchema('v1', true); From 3b8bec5743eff01ba4476a366e6833894c6126f2 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Mon, 19 May 2025 18:03:08 +0200 Subject: [PATCH 021/121] docs: Update docker pulls counter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 032d3b2d..0b07a568 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Project mastering driven by fun** -![Version](https://img.shields.io/github/package-json/v/plankanban/planka?style=flat-square) [![Docker Pulls](https://img.shields.io/badge/docker_pulls-5M%2B-%23066da5?style=flat-square&color=red)](https://github.com/plankanban/planka/pkgs/container/planka) [![Contributors](https://img.shields.io/github/contributors/plankanban/planka?style=flat-square&color=blue)](https://github.com/plankanban/planka/graphs/contributors) [![Chat](https://img.shields.io/discord/1041440072953765979?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/WqqYNd7Jvt) +![Version](https://img.shields.io/github/package-json/v/plankanban/planka?style=flat-square) [![Docker Pulls](https://img.shields.io/badge/docker_pulls-6M%2B-%23066da5?style=flat-square&color=red)](https://github.com/plankanban/planka/pkgs/container/planka) [![Contributors](https://img.shields.io/github/contributors/plankanban/planka?style=flat-square&color=blue)](https://github.com/plankanban/planka/graphs/contributors) [![Chat](https://img.shields.io/discord/1041440072953765979?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/WqqYNd7Jvt) ![Demo](https://raw.githubusercontent.com/plankanban/planka/master/assets/demo.gif) From 5d53f44fe8b897f0cd85351df3353b1ce2610a6c Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Tue, 20 May 2025 00:06:51 +0200 Subject: [PATCH 022/121] fix: Add clearfix and missing id property --- client/src/components/cards/Card/ProjectContent.module.scss | 6 ++++++ server/api/helpers/actions/create-one.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/components/cards/Card/ProjectContent.module.scss b/client/src/components/cards/Card/ProjectContent.module.scss index 48853615..72503ee2 100644 --- a/client/src/components/cards/Card/ProjectContent.module.scss +++ b/client/src/components/cards/Card/ProjectContent.module.scss @@ -101,6 +101,12 @@ .wrapper { padding: 6px 8px 0; + + &:after { + clear: both; + content: ""; + display: table; + } } :global(.card):hover { diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js index ed35b5e7..ba1e6494 100644 --- a/server/api/helpers/actions/create-one.js +++ b/server/api/helpers/actions/create-one.js @@ -144,7 +144,7 @@ module.exports = { if (Action.INTERNAL_NOTIFIABLE_TYPES.includes(action.type)) { if (Action.PERSONAL_NOTIFIABLE_TYPES.includes(action.type)) { - if (values.user !== action.data.user.id) { + if (values.user.id !== action.data.user.id) { await sails.helpers.notifications.createOne.with({ values: { action, From d5fd2fd33bfb8f73ec127a9856577b7d5f940705 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Tue, 20 May 2025 21:17:51 +0200 Subject: [PATCH 023/121] feat: Log actions when task completion status changes --- .../components/activities/Activities/Item.jsx | 38 +++++++++++++++++++ client/src/constants/Enums.js | 2 + client/src/locales/en-GB/core.js | 3 ++ client/src/locales/en-US/core.js | 3 ++ server/api/helpers/tasks/update-one.js | 16 ++++++++ server/api/models/Action.js | 2 + 6 files changed, 64 insertions(+) diff --git a/client/src/components/activities/Activities/Item.jsx b/client/src/components/activities/Activities/Item.jsx index e1901076..e4d34acb 100755 --- a/client/src/components/activities/Activities/Item.jsx +++ b/client/src/components/activities/Activities/Item.jsx @@ -143,6 +143,44 @@ const Item = React.memo(({ id }) => { ); + break; + case ActivityTypes.COMPLETE_TASK: + contentNode = ( + + {userName} + + {' completed '} + {activity.data.task.name} + {' on this card'} + + + ); + + break; + case ActivityTypes.UNCOMPLETE_TASK: + contentNode = ( + + {userName} + + {' marked '} + {activity.data.task.name} + {' incomplete on this card'} + + + ); + break; default: contentNode = null; diff --git a/client/src/constants/Enums.js b/client/src/constants/Enums.js index 02f591cf..9da896a2 100755 --- a/client/src/constants/Enums.js +++ b/client/src/constants/Enums.js @@ -92,6 +92,8 @@ export const ActivityTypes = { MOVE_CARD: 'moveCard', ADD_MEMBER_TO_CARD: 'addMemberToCard', REMOVE_MEMBER_FROM_CARD: 'removeMemberFromCard', + COMPLETE_TASK: 'completeTask', + UNCOMPLETE_TASK: 'uncompleteTask', }; export const NotificationTypes = { diff --git a/client/src/locales/en-GB/core.js b/client/src/locales/en-GB/core.js index 688eebf2..2cb913e3 100644 --- a/client/src/locales/en-GB/core.js +++ b/client/src/locales/en-GB/core.js @@ -289,9 +289,12 @@ export default { userAddedThisCardToList: '<0>{{user}}<1> added this card to {{list}}', userAddedUserToThisCard: '<0>{{actorUser}}<1> added {{addedUser}} to this card', userAddedYouToCard: '{{user}} added you to <2>{{card}}', + userCompletedTaskOnThisCard: '<0>{{user}}<1> completed {{task}} on this card', userJoinedThisCard: `<0>{{user}}<1> joined this card`, userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}', userLeftThisCard: '<0>{{user}}<1> left this card', + userMarkedTaskIncompleteOnThisCard: + '<0>{{user}}<1> marked {{task}} incomplete on this card', userMovedCardFromListToList: '{{user}} moved <2>{{card}} from {{fromList}} to {{toList}}', userMovedThisCardFromListToList: '<0>{{user}}<1> moved this card from {{fromList}} to {{toList}}', diff --git a/client/src/locales/en-US/core.js b/client/src/locales/en-US/core.js index 50487bd3..28cae078 100644 --- a/client/src/locales/en-US/core.js +++ b/client/src/locales/en-US/core.js @@ -284,9 +284,12 @@ export default { userAddedThisCardToList: '<0>{{user}}<1> added this card to {{list}}', userAddedUserToThisCard: '<0>{{actorUser}}<1> added {{addedUser}} to this card', userAddedYouToCard: '{{user}} added you to <2>{{card}}', + userCompletedTaskOnThisCard: '<0>{{user}}<1> completed {{task}} on this card', userJoinedThisCard: `<0>{{user}}<1> joined this card`, userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}', userLeftThisCard: '<0>{{user}}<1> left this card', + userMarkedTaskIncompleteOnThisCard: + '<0>{{user}}<1> marked {{task}} incomplete on this card', userMovedCardFromListToList: '{{user}} moved <2>{{card}} from {{fromList}} to {{toList}}', userMovedThisCardFromListToList: '<0>{{user}}<1> moved this card from {{fromList}} to {{toList}}', diff --git a/server/api/helpers/tasks/update-one.js b/server/api/helpers/tasks/update-one.js index 84cd13e4..6261398f 100644 --- a/server/api/helpers/tasks/update-one.js +++ b/server/api/helpers/tasks/update-one.js @@ -132,6 +132,22 @@ module.exports = { }), user: inputs.actorUser, }); + + if (inputs.record.isCompleted !== task.isCompleted) { + await sails.helpers.actions.createOne.with({ + values: { + type: task.isCompleted ? Action.Types.COMPLETE_TASK : Action.Types.UNCOMPLETE_TASK, + data: { + task: _.pick(task, ['id', 'name']), + }, + user: inputs.actorUser, + card: inputs.card, + }, + project: inputs.project, + board: inputs.board, + list: inputs.list, + }); + } } return task; diff --git a/server/api/models/Action.js b/server/api/models/Action.js index 888d34f1..955bf812 100755 --- a/server/api/models/Action.js +++ b/server/api/models/Action.js @@ -15,6 +15,8 @@ const Types = { MOVE_CARD: 'moveCard', ADD_MEMBER_TO_CARD: 'addMemberToCard', REMOVE_MEMBER_FROM_CARD: 'removeMemberFromCard', + COMPLETE_TASK: 'completeTask', + UNCOMPLETE_TASK: 'uncompleteTask', }; const INTERNAL_NOTIFIABLE_TYPES = [Types.MOVE_CARD, Types.ADD_MEMBER_TO_CARD]; From c05dcf45f2c9cd5fcbff39daa76f1b94b002952f Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Wed, 21 May 2025 13:03:25 +0200 Subject: [PATCH 024/121] feat: Enhance notifications popup appearance --- client/src/api/notifications.js | 3 +++ .../activities/Activities/Item.module.scss | 2 -- .../notifications/NotificationsStep/Item.jsx | 14 ++++++++++---- .../NotificationsStep/Item.module.scss | 13 ++++++++++++- client/src/locales/ar-YE/core.js | 5 +++-- client/src/locales/bg-BG/core.js | 5 +++-- client/src/locales/cs-CZ/core.js | 11 +++++++---- client/src/locales/da-DK/core.js | 5 +++-- client/src/locales/de-DE/core.js | 4 ++-- client/src/locales/en-GB/core.js | 8 +++++--- client/src/locales/en-US/core.js | 8 +++++--- client/src/locales/es-ES/core.js | 5 +++-- client/src/locales/fa-IR/core.js | 5 +++-- client/src/locales/fr-FR/core.js | 8 ++++---- client/src/locales/hu-HU/core.js | 4 ++-- client/src/locales/id-ID/core.js | 4 ++-- client/src/locales/it-IT/core.js | 4 ++-- client/src/locales/ja-JP/core.js | 6 +++--- client/src/locales/ko-KR/core.js | 5 +++-- client/src/locales/nl-NL/core.js | 4 ++-- client/src/locales/pl-PL/core.js | 5 +++-- client/src/locales/pt-BR/core.js | 5 +++-- client/src/locales/ro-RO/core.js | 4 ++-- client/src/locales/ru-RU/core.js | 5 +++-- client/src/locales/sk-SK/core.js | 6 ++++-- client/src/locales/sr-Cyrl-CS/core.js | 5 +++-- client/src/locales/sr-Latn-CS/core.js | 5 +++-- client/src/locales/sv-SE/core.js | 5 +++-- client/src/locales/tr-TR/core.js | 4 ++-- client/src/locales/uk-UA/core.js | 4 ++-- client/src/locales/uz-UZ/core.js | 5 +++-- client/src/locales/zh-CN/core.js | 4 ++-- client/src/locales/zh-TW/core.js | 4 ++-- 33 files changed, 112 insertions(+), 72 deletions(-) diff --git a/client/src/api/notifications.js b/client/src/api/notifications.js index b0456229..6d36332a 100755 --- a/client/src/api/notifications.js +++ b/client/src/api/notifications.js @@ -16,6 +16,9 @@ export const transformNotification = (notification) => ({ activityId: notification.actionId, } : notification), + ...(notification.createdAt && { + createdAt: new Date(notification.createdAt), + }), }); /* Actions */ diff --git a/client/src/components/activities/Activities/Item.module.scss b/client/src/components/activities/Activities/Item.module.scss index 37c92a31..7245597b 100644 --- a/client/src/components/activities/Activities/Item.module.scss +++ b/client/src/components/activities/Activities/Item.module.scss @@ -6,7 +6,6 @@ :global(#app) { .author { color: #17394d; - display: inline-block; font-weight: bold; line-height: 20px; } @@ -21,7 +20,6 @@ .date { color: #6b808c; - display: inline-block; font-size: 12px; line-height: 20px; } diff --git a/client/src/components/notifications/NotificationsStep/Item.jsx b/client/src/components/notifications/NotificationsStep/Item.jsx index 69c65b5b..ac424ab2 100644 --- a/client/src/components/notifications/NotificationsStep/Item.jsx +++ b/client/src/components/notifications/NotificationsStep/Item.jsx @@ -16,6 +16,7 @@ import entryActions from '../../../entry-actions'; import Paths from '../../../constants/Paths'; import { StaticUserIds } from '../../../constants/StaticUsers'; import { NotificationTypes } from '../../../constants/Enums'; +import TimeAgo from '../../common/TimeAgo'; import UserAvatar from '../../users/UserAvatar'; import styles from './Item.module.scss'; @@ -67,7 +68,7 @@ const Item = React.memo(({ id, onClose }) => { toList: toListName, }} > - {creatorUserName} + {creatorUserName} {' moved '} {cardName} @@ -93,7 +94,7 @@ const Item = React.memo(({ id, onClose }) => { card: cardName, }} > - {creatorUserName} + {creatorUserName} {` left a new comment «${commentText}» to `} {cardName} @@ -112,7 +113,7 @@ const Item = React.memo(({ id, onClose }) => { card: cardName, }} > - {creatorUserName} + {creatorUserName} {` added you to `} {cardName} @@ -128,7 +129,12 @@ const Item = React.memo(({ id, onClose }) => { return (
- {contentNode} + +
{contentNode}
+ + + +