1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-18 12:49:43 +02:00

Merge branch 'master' into feat/turkish-translation

This commit is contained in:
Maksim Eltyshev 2025-07-07 12:02:29 +02:00 committed by GitHub
commit 07909cf3e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
159 changed files with 6391 additions and 1228 deletions

View file

@ -15,7 +15,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '22'
cache: 'npm'
- name: Update npm

View file

@ -24,7 +24,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '22'
cache: 'npm'
- name: Set up PostgreSQL

View file

@ -16,7 +16,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '22'
cache: 'npm'
- name: Cache Node.js modules

View file

@ -1,4 +1,4 @@
FROM node:18-alpine AS server-dependencies
FROM node:22-alpine AS server-dependencies
RUN apk -U upgrade \
&& apk add build-base python3 --no-cache
@ -10,7 +10,7 @@ COPY server/package.json server/package-lock.json server/requirements.txt ./
RUN npm install npm --global \
&& npm install --omit=dev
FROM node:lts AS client
FROM node:22 AS client
WORKDIR /app
@ -21,7 +21,7 @@ RUN npm install npm --global \
RUN DISABLE_ESLINT_PLUGIN=true npm run build
FROM node:18-alpine
FROM node:22-alpine
RUN apk -U upgrade \
&& apk add bash python3 --no-cache \

View file

@ -1,4 +1,4 @@
FROM node:lts-alpine
FROM node:22-alpine
RUN apk -U upgrade \
&& apk add bash build-base python3 xdg-utils --no-cache \

View file

@ -213,3 +213,20 @@ oidc:
## key: key-inside-the-secret
##
extraEnv: []
## Example extraEnv for configure SMTP
## extraEnv:
## - name: SMTP_HOST
## value: "your_smtp_server"
## - name: SMTP_PORT
## value: "587"
## - name: SMTP_USER
## value: "your_email@example.com"
## - name: SMTP_PASSWORD
## value: "your_password"
## - name: SMTP_FROM
## value: "your_email@example.com"
## - name: SMTP_NAME
## value: "your_name_or_login"
## - name: SMTP_SECURE
## value: "false"

2714
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -82,10 +82,10 @@
"@diplodoc/cut-extension": "^0.7.4",
"@diplodoc/transform": "^4.57.7",
"@gravity-ui/components": "^4.4.0",
"@gravity-ui/markdown-editor": "^15.13.2",
"@gravity-ui/uikit": "^7.13.0",
"@gravity-ui/markdown-editor": "^15.14.1",
"@gravity-ui/uikit": "^7.16.2",
"@juggle/resize-observer": "^3.4.0",
"@vitejs/plugin-react": "^4.5.1",
"@vitejs/plugin-react": "^4.6.0",
"browserslist-to-esbuild": "^2.1.1",
"classnames": "^2.5.1",
"date-fns": "^2.30.0",
@ -96,7 +96,7 @@
"highlightjs-apex": "^1.5.0",
"highlightjs-blade": "^0.1.0",
"highlightjs-cobol": "^0.3.3",
"highlightjs-cshtml-razor": "^2.1.1",
"highlightjs-cshtml-razor": "^2.2.0",
"highlightjs-gf": "^1.0.1",
"highlightjs-jolie": "^0.1.8",
"highlightjs-lean": "^1.2.0",
@ -115,7 +115,7 @@
"hightlightjs-papyrus": "^0.0.4",
"history": "^5.3.0",
"i18next": "^25.2.1",
"i18next-browser-languagedetector": "^8.1.0",
"i18next-browser-languagedetector": "^8.2.0",
"initials": "^3.1.2",
"javascript-time-ago": "^2.5.11",
"js-cookie": "^3.0.5",
@ -137,7 +137,7 @@
"react-dropzone": "^14.3.8",
"react-frame-component": "^5.2.7",
"react-hot-toast": "^2.5.2",
"react-i18next": "^15.5.2",
"react-i18next": "^15.5.3",
"react-input-mask": "^2.0.4",
"react-intersection-observer": "^9.16.0",
"react-mentions": "^4.4.10",
@ -152,7 +152,7 @@
"redux-saga": "^1.3.0",
"reselect": "^4.1.8",
"sails.io.js": "^1.2.1",
"sass-embedded": "^1.89.1",
"sass-embedded": "^1.89.2",
"semantic-ui-react": "^2.1.5",
"socket.io-client": "^2.5.0",
"validator": "^13.15.15",
@ -163,23 +163,23 @@
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/eslint-parser": "^7.27.1",
"@babel/eslint-parser": "^7.27.5",
"@babel/preset-env": "^7.27.2",
"@cucumber/cucumber": "^11.3.0",
"@cucumber/pretty-formatter": "^1.0.1",
"@playwright/test": "^1.52.0",
"@playwright/test": "^1.53.1",
"babel-jest": "^29.7.0",
"babel-preset-airbnb": "^5.0.0",
"eslint": "^8.57.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-prettier": "^5.5.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^4.6.2",
"jest": "^29.7.0",
"playwright": "^1.52.0",
"playwright": "^1.53.1",
"prettier": "3.3.3"
}
}

View file

@ -8,6 +8,7 @@ import ActionTypes from '../constants/ActionTypes';
const initializeCore = (
user,
board,
webhooks,
users,
projects,
projectManagers,
@ -33,6 +34,7 @@ const initializeCore = (
payload: {
user,
board,
webhooks,
users,
projects,
projectManagers,

View file

@ -8,6 +8,7 @@ import socket from './socket';
import login from './login';
import core from './core';
import modals from './modals';
import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@ -35,6 +36,7 @@ export default {
...login,
...core,
...modals,
...webhooks,
...users,
...projects,
...projectManagers,

View file

@ -14,6 +14,7 @@ const handleSocketReconnect = (
config,
user,
board,
webhooks,
users,
projects,
projectManagers,
@ -40,6 +41,7 @@ const handleSocketReconnect = (
config,
user,
board,
webhooks,
users,
projects,
projectManagers,

View file

@ -67,6 +67,7 @@ const handleUserUpdate = (
boardIds,
config,
board,
webhooks,
users,
projects,
projectManagers,
@ -95,6 +96,7 @@ const handleUserUpdate = (
boardIds,
config,
board,
webhooks,
users,
projects,
projectManagers,

View file

@ -0,0 +1,104 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import ActionTypes from '../constants/ActionTypes';
const createWebhook = (webhook) => ({
type: ActionTypes.WEBHOOK_CREATE,
payload: {
webhook,
},
});
createWebhook.success = (localId, webhook) => ({
type: ActionTypes.WEBHOOK_CREATE__SUCCESS,
payload: {
localId,
webhook,
},
});
createWebhook.failure = (localId, error) => ({
type: ActionTypes.WEBHOOK_CREATE__FAILURE,
payload: {
localId,
error,
},
});
const handleWebhookCreate = (webhook) => ({
type: ActionTypes.WEBHOOK_CREATE_HANDLE,
payload: {
webhook,
},
});
const updateWebhook = (id, data) => ({
type: ActionTypes.WEBHOOK_UPDATE,
payload: {
id,
data,
},
});
updateWebhook.success = (webhook) => ({
type: ActionTypes.WEBHOOK_UPDATE__SUCCESS,
payload: {
webhook,
},
});
updateWebhook.failure = (id, error) => ({
type: ActionTypes.WEBHOOK_UPDATE__FAILURE,
payload: {
id,
error,
},
});
const handleWebhookUpdate = (webhook) => ({
type: ActionTypes.WEBHOOK_UPDATE_HANDLE,
payload: {
webhook,
},
});
const deleteWebhook = (id) => ({
type: ActionTypes.WEBHOOK_DELETE,
payload: {
id,
},
});
deleteWebhook.success = (webhook) => ({
type: ActionTypes.WEBHOOK_DELETE__SUCCESS,
payload: {
webhook,
},
});
deleteWebhook.failure = (id, error) => ({
type: ActionTypes.WEBHOOK_DELETE__FAILURE,
payload: {
id,
error,
},
});
const handleWebhookDelete = (webhook) => ({
type: ActionTypes.WEBHOOK_DELETE_HANDLE,
payload: {
webhook,
},
});
export default {
createWebhook,
handleWebhookCreate,
updateWebhook,
handleWebhookUpdate,
deleteWebhook,
handleWebhookDelete,
};

View file

@ -7,6 +7,7 @@ import http from './http';
import socket from './socket';
import config from './config';
import accessTokens from './access-tokens';
import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@ -35,6 +36,7 @@ export { http, socket };
export default {
...config,
...accessTokens,
...webhooks,
...users,
...projects,
...projectManagers,

23
client/src/api/webhooks.js Executable file
View file

@ -0,0 +1,23 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import socket from './socket';
/* Actions */
const getWebhooks = (headers) => socket.get('/webhooks', undefined, headers);
const createWebhook = (data, headers) => socket.post('/webhooks', data, headers);
const updateWebhook = (id, data, headers) => socket.patch(`/webhooks/${id}`, data, headers);
const deleteWebhook = (id, headers) => socket.delete(`/webhooks/${id}`, undefined, headers);
export default {
getWebhooks,
createWebhook,
updateWebhook,
deleteWebhook,
};

View file

@ -16,6 +16,7 @@ import Encodings from '../../../constants/Encodings';
import { AttachmentTypes } from '../../../constants/Enums';
import ItemContent from './ItemContent';
import ContentViewer from './ContentViewer';
import PdfViewer from './PdfViewer';
import CsvViewer from './CsvViewer';
import styles from './Item.module.scss';
@ -40,10 +41,8 @@ const Item = React.memo(({ id, isVisible }) => {
switch (attachment.data.mimeType) {
case 'application/pdf':
content = (
// eslint-disable-next-line jsx-a11y/alt-text
<object
data={attachment.data.url}
type={attachment.data.mimeType}
<PdfViewer
src={attachment.data.url}
className={classNames(styles.content, styles.contentViewer)}
/>
);
@ -60,15 +59,6 @@ const Item = React.memo(({ id, isVisible }) => {
<audio controls src={attachment.data.url} className={styles.content} />
);
break;
case 'video/mp4':
case 'video/ogg':
case 'video/webm':
content = (
// eslint-disable-next-line jsx-a11y/media-has-caption
<video controls src={attachment.data.url} className={styles.content} />
);
break;
case 'text/csv':
content = (
@ -78,6 +68,15 @@ const Item = React.memo(({ id, isVisible }) => {
/>
);
break;
case 'video/mp4':
case 'video/ogg':
case 'video/webm':
content = (
// eslint-disable-next-line jsx-a11y/media-has-caption
<video controls src={attachment.data.url} className={styles.content} />
);
break;
default:
if (attachment.data.encoding === Encodings.UTF8) {

View file

@ -0,0 +1,26 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import styles from './PdfViewer.module.scss';
const PdfViewer = React.memo(({ src, className }) => (
// eslint-disable-next-line jsx-a11y/iframe-has-title
<iframe src={src} type="application/pdf" className={classNames(styles.wrapper, className)} />
));
PdfViewer.propTypes = {
src: PropTypes.string.isRequired,
className: PropTypes.string,
};
PdfViewer.defaultProps = {
className: undefined,
};
export default PdfViewer;

View file

@ -0,0 +1,10 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
:global(#app) {
.wrapper {
border: 0;
}
}

View file

@ -12,6 +12,7 @@ import { Modal, Tab } from 'semantic-ui-react';
import entryActions from '../../../entry-actions';
import { useClosableModal } from '../../../hooks';
import UsersPane from './UsersPane';
import WebhooksPane from './WebhooksPane';
import styles from './AdministrationModal.module.scss';
@ -37,6 +38,12 @@ const AdministrationModal = React.memo(() => {
}),
render: () => <UsersPane />,
},
{
menuItem: t('common.webhooks', {
context: 'title',
}),
render: () => <WebhooksPane />,
},
];
const isUsersPaneActive = activeTabIndex === 0;

View file

@ -117,7 +117,7 @@ const AddStep = React.memo(({ onClose }) => {
);
const handleMessageDismiss = useCallback(() => {
dispatch(entryActions.clearUserPasswordUpdateError());
dispatch(entryActions.clearUserCreateError());
}, [dispatch]);
const handleSelectRoleClick = useCallback(() => {

View file

@ -0,0 +1,35 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Tab } from 'semantic-ui-react';
import selectors from '../../../selectors';
import entryActions from '../../../entry-actions';
import Webhooks from '../../webhooks/Webhooks';
import styles from './WebhooksPane.module.scss';
const WebhooksPane = React.memo(() => {
const webhookIds = useSelector(selectors.selectWebhookIds);
const dispatch = useDispatch();
const handleCreate = useCallback(
(data) => {
dispatch(entryActions.createWebhook(data));
},
[dispatch],
);
return (
<Tab.Pane attached={false} className={styles.wrapper}>
<Webhooks ids={webhookIds} onCreate={handleCreate} />
</Tab.Pane>
);
});
export default WebhooksPane;

View file

@ -0,0 +1,11 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
:global(#app) {
.wrapper {
border: none;
box-shadow: none;
}
}

View file

@ -28,21 +28,26 @@ const ConfirmationStep = React.memo(
const [nameFieldRef, handleNameFieldRef] = useNestedRef('inputRef');
const handleSubmit = useCallback(() => {
if (typeValue) {
const cleanData = {
...data,
typeValue: data.typeValue.trim(),
};
const handleSubmit = useCallback(
(event) => {
event.stopPropagation();
if (cleanData.typeValue.toLowerCase() !== typeValue.toLowerCase()) {
nameFieldRef.current.select();
return;
if (typeValue) {
const cleanData = {
...data,
typeValue: data.typeValue.trim(),
};
if (cleanData.typeValue.toLowerCase() !== typeValue.toLowerCase()) {
nameFieldRef.current.select();
return;
}
}
}
onConfirm();
}, [typeValue, onConfirm, data, nameFieldRef]);
onConfirm();
},
[typeValue, onConfirm, data, nameFieldRef],
);
useEffect(() => {
if (typeValue) {

View file

@ -125,7 +125,7 @@ const Item = React.memo(({ id }) => {
dispatch(entryActions.deleteNotificationService(id));
}, [id, dispatch]);
const handleUpdateSubmit = useCallback(() => {
const handleSubmit = useCallback(() => {
urlFieldRef.current.blur();
}, [urlFieldRef]);
@ -153,7 +153,7 @@ const Item = React.memo(({ id }) => {
const ConfirmationPopup = usePopupInClosableContext(ConfirmationStep);
return (
<Form className={styles.wrapper} onSubmit={handleUpdateSubmit}>
<Form className={styles.wrapper} onSubmit={handleSubmit}>
<Input
ref={handleUrlFieldRef}
name="url"

View file

@ -62,6 +62,7 @@
overflow-wrap: break-word;
padding: 8px 0;
vertical-align: top;
white-space: pre-wrap;
width: 100%;
}

View file

@ -0,0 +1,152 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React, { useCallback, useImperativeHandle } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { Dropdown, Input } from 'semantic-ui-react';
import { useNestedRef } from '../../../hooks';
import WEBHOOK_EVENTS from '../../../constants/WebhookEvents';
import styles from './Editor.module.scss';
const Editor = React.forwardRef(({ data, isReadOnly, onFieldChange }, ref) => {
const [t] = useTranslation();
const [nameFieldRef, handleNameFieldRef] = useNestedRef('inputRef');
const [urlFieldRef, handleUrlFieldRef] = useNestedRef('inputRef');
const focusNameField = useCallback(() => {
nameFieldRef.current.focus({
preventScroll: true,
});
}, [nameFieldRef]);
const selectNameField = useCallback(() => {
nameFieldRef.current.select();
}, [nameFieldRef]);
const selectUrlField = useCallback(() => {
urlFieldRef.current.select();
}, [urlFieldRef]);
useImperativeHandle(
ref,
() => ({
focusNameField,
selectNameField,
selectUrlField,
}),
[focusNameField, selectNameField, selectUrlField],
);
return (
<>
<div className={styles.text}>{t('common.title')}</div>
<Input
fluid
ref={handleNameFieldRef}
name="name"
value={data.name}
maxLength={128}
readOnly={isReadOnly}
className={styles.field}
onChange={onFieldChange}
/>
<div className={styles.text}>{t('common.url')}</div>
<Input
fluid
ref={handleUrlFieldRef}
name="url"
value={data.url}
maxLength={2048}
readOnly={isReadOnly}
className={styles.field}
onChange={onFieldChange}
/>
<div className={styles.text}>
{t('common.accessToken')} (
{t('common.optional', {
context: 'inline',
})}
)
</div>
<Input
fluid
name="accessToken"
value={data.accessToken}
maxLength={512}
readOnly={isReadOnly}
className={styles.field}
onChange={onFieldChange}
/>
{data.excludedEvents.length === 0 && (
<>
<div className={styles.text}>
{t('common.events')} (
{t('common.optional', {
context: 'inline',
})}
)
</div>
<Dropdown
selection
multiple
fluid
name="events"
options={WEBHOOK_EVENTS.map((event) => ({
text: event,
value: event,
}))}
value={data.events}
placeholder="All"
readOnly={isReadOnly}
className={styles.field}
onChange={onFieldChange}
/>
</>
)}
{data.events.length === 0 && (
<>
<div className={styles.text}>
{t('common.excludedEvents')} (
{t('common.optional', {
context: 'inline',
})}
)
</div>
<Dropdown
selection
multiple
fluid
name="excludedEvents"
options={WEBHOOK_EVENTS.map((event) => ({
text: event,
value: event,
}))}
value={data.excludedEvents}
placeholder="None"
readOnly={isReadOnly}
className={styles.field}
onChange={onFieldChange}
/>
</>
)}
</>
);
});
Editor.propTypes = {
data: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
isReadOnly: PropTypes.bool,
onFieldChange: PropTypes.func.isRequired,
};
Editor.defaultProps = {
isReadOnly: false,
};
export default React.memo(Editor);

View file

@ -0,0 +1,17 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
:global(#app) {
.field {
margin-bottom: 8px;
}
.text {
color: #444444;
font-size: 12px;
font-weight: bold;
padding-bottom: 6px;
}
}

View file

@ -0,0 +1,137 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { dequal } from 'dequal';
import React, { useCallback, useMemo, useRef } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { Accordion, Button, Form, Icon } from 'semantic-ui-react';
import selectors from '../../../selectors';
import entryActions from '../../../entry-actions';
import { useForm, usePopupInClosableContext } from '../../../hooks';
import { isUrl } from '../../../utils/validator';
import Editor from './Editor';
import ConfirmationStep from '../../common/ConfirmationStep';
import styles from './Item.module.scss';
import { useToggle } from '../../../lib/hooks';
const Item = React.memo(({ id }) => {
const selectWebhookById = useMemo(() => selectors.makeSelectWebhookById(), []);
const webhook = useSelector((state) => selectWebhookById(state, id));
const dispatch = useDispatch();
const [t] = useTranslation();
const [isOpened, toggleOpened] = useToggle();
const defaultData = useMemo(
() => ({
name: webhook.name,
url: webhook.url,
accessToken: webhook.accessToken,
events: webhook.events,
excludedEvents: webhook.excludedEvents,
}),
[webhook],
);
const [data, handleFieldChange] = useForm(() => ({
name: '',
url: '',
...defaultData,
accessToken: defaultData.accessToken || '',
events: defaultData.events || [],
excludedEvents: defaultData.excludedEvents || [],
}));
const cleanData = useMemo(
() => ({
...data,
name: data.name.trim(),
url: data.url.trim(),
accessToken: data.accessToken.trim() || null,
events: data.events.length === 0 ? null : data.events,
excludedEvents: data.excludedEvents.length === 0 ? null : data.excludedEvents,
}),
[data],
);
const editorRef = useRef(null);
const handleDeleteConfirm = useCallback(() => {
dispatch(entryActions.deleteWebhook(id));
}, [id, dispatch]);
const handleSubmit = useCallback(() => {
if (!cleanData.name) {
editorRef.current.selectNameField();
return;
}
if (!cleanData.url || !isUrl(cleanData.url)) {
editorRef.current.selectUrlField();
return;
}
dispatch(entryActions.updateWebhook(id, cleanData));
}, [id, dispatch, cleanData]);
const handleOpenClick = useCallback(() => {
toggleOpened();
}, [toggleOpened]);
const ConfirmationPopup = usePopupInClosableContext(ConfirmationStep);
return (
<>
<Accordion.Title active={isOpened} className={styles.title} onClick={handleOpenClick}>
<Icon name="dropdown" />
{defaultData.name}
</Accordion.Title>
<Accordion.Content active={isOpened}>
<div>
<Form onSubmit={handleSubmit}>
<Editor
ref={editorRef}
data={data}
isReadOnly={!webhook.isPersisted}
onFieldChange={handleFieldChange}
/>
<div className={styles.controls}>
<Button
positive
disabled={dequal(cleanData, defaultData)}
content={t('action.save')}
/>
<ConfirmationPopup
title="common.deleteWebhook"
content="common.areYouSureYouWantToDeleteThisWebhook"
buttonContent="action.deleteWebhook"
onConfirm={handleDeleteConfirm}
>
<Button
type="button"
disabled={!webhook.isPersisted}
className={styles.deleteButton}
>
{t('action.delete')}
</Button>
</ConfirmationPopup>
</div>
</Form>
</div>
</Accordion.Content>
</>
);
});
Item.propTypes = {
id: PropTypes.string.isRequired,
};
export default Item;

View file

@ -0,0 +1,22 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
:global(#app) {
.controls {
display: flex;
justify-content: space-between;
}
.deleteButton {
box-shadow: 0 1px 0 #cbcccc;
margin-right: 0;
}
.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}

View file

@ -0,0 +1,96 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React, { useCallback, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { Accordion, Button, Form, Segment } from 'semantic-ui-react';
import { useDidUpdate, useToggle } from '../../../lib/hooks';
import { useForm } from '../../../hooks';
import { isUrl } from '../../../utils/validator';
import Item from './Item';
import Editor from './Editor';
const DEFAULT_DATA = {
name: '',
url: '',
accessToken: '',
events: [],
excludedEvents: [],
};
const Webhooks = React.memo(({ ids, onCreate }) => {
const [t] = useTranslation();
const [data, handleFieldChange, setData] = useForm(DEFAULT_DATA);
const [focusNameFieldState, focusNameField] = useToggle();
const editorRef = useRef(null);
const handleCreateSubmit = useCallback(() => {
const cleanData = {
...data,
name: data.name.trim(),
url: data.url.trim(),
accessToken: data.accessToken.trim() || null,
events: data.events.length === 0 ? null : data.events,
excludedEvents: data.excludedEvents.length === 0 ? null : data.excludedEvents,
};
if (!cleanData.name) {
editorRef.current.selectNameField();
return;
}
if (!cleanData.url || !isUrl(cleanData.url)) {
editorRef.current.selectUrlField();
return;
}
onCreate(cleanData);
setData(DEFAULT_DATA);
focusNameField();
}, [onCreate, data, setData, focusNameField]);
useEffect(() => {
if (editorRef.current) {
editorRef.current.focusNameField();
}
}, []);
useDidUpdate(() => {
if (editorRef.current) {
editorRef.current.focusNameField();
}
}, [focusNameFieldState]);
return (
<>
{ids.length > 0 && (
<Accordion styled fluid>
{ids.map((id) => (
<Item key={id} id={id} />
))}
</Accordion>
)}
{ids.length < 10 && (
<Segment>
<Form onSubmit={handleCreateSubmit}>
<Editor ref={editorRef} data={data} onFieldChange={handleFieldChange} />
<Button positive>{t('action.addWebhook')}</Button>
</Form>
</Segment>
)}
</>
);
});
Webhooks.propTypes = {
ids: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
onCreate: PropTypes.func.isRequired,
};
export default Webhooks;

View file

@ -0,0 +1,8 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import Webhooks from './Webhooks';
export default Webhooks;

View file

@ -42,6 +42,21 @@ export default {
MODAL_OPEN: 'MODAL_OPEN',
MODAL_CLOSE: 'MODAL_CLOSE',
/* Webhooks */
WEBHOOK_CREATE: 'WEBHOOK_CREATE',
WEBHOOK_CREATE__SUCCESS: 'WEBHOOK_CREATE__SUCCESS',
WEBHOOK_CREATE__FAILURE: 'WEBHOOK_CREATE__FAILURE',
WEBHOOK_CREATE_HANDLE: 'WEBHOOK_CREATE_HANDLE',
WEBHOOK_UPDATE: 'WEBHOOK_UPDATE',
WEBHOOK_UPDATE__SUCCESS: 'WEBHOOK_UPDATE__SUCCESS',
WEBHOOK_UPDATE__FAILURE: 'WEBHOOK_UPDATE__FAILURE',
WEBHOOK_UPDATE_HANDLE: 'WEBHOOK_UPDATE_HANDLE',
WEBHOOK_DELETE: 'WEBHOOK_DELETE',
WEBHOOK_DELETE__SUCCESS: 'WEBHOOK_DELETE__SUCCESS',
WEBHOOK_DELETE__FAILURE: 'WEBHOOK_DELETE__FAILURE',
WEBHOOK_DELETE_HANDLE: 'WEBHOOK_DELETE_HANDLE',
/* Users */
USER_CREATE: 'USER_CREATE',

View file

@ -31,6 +31,15 @@ export default {
MODAL_OPEN: `${PREFIX}/MODAL_OPEN`,
MODAL_CLOSE: `${PREFIX}/MODAL_CLOSE`,
/* Webhooks */
WEBHOOK_CREATE: `${PREFIX}/WEBHOOK_CREATE`,
WEBHOOK_CREATE_HANDLE: `${PREFIX}/WEBHOOK_CREATE_HANDLE`,
WEBHOOK_UPDATE: `${PREFIX}/WEBHOOK_UPDATE`,
WEBHOOK_UPDATE_HANDLE: `${PREFIX}/WEBHOOK_UPDATE_HANDLE`,
WEBHOOK_DELETE: `${PREFIX}/WEBHOOK_DELETE`,
WEBHOOK_DELETE_HANDLE: `${PREFIX}/WEBHOOK_DELETE_HANDLE`,
/* Users */
USER_CREATE: `${PREFIX}/USER_CREATE`,

View file

@ -0,0 +1,91 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
export default [
'actionCreate',
'attachmentCreate',
'attachmentUpdate',
'attachmentDelete',
'backgroundImageCreate',
'backgroundImageDelete',
'baseCustomFieldGroupCreate',
'baseCustomFieldGroupUpdate',
'baseCustomFieldGroupDelete',
'boardCreate',
'boardUpdate',
'boardDelete',
'boardMembershipCreate',
'boardMembershipUpdate',
'boardMembershipDelete',
'cardCreate',
'cardUpdate',
'cardDelete',
'cardLabelCreate',
'cardLabelDelete',
'cardMembershipCreate',
'cardMembershipDelete',
'commentCreate',
'commentUpdate',
'commentDelete',
'customFieldCreate',
'customFieldUpdate',
'customFieldDelete',
'customFieldGroupCreate',
'customFieldGroupUpdate',
'customFieldGroupDelete',
'customFieldValueUpdate',
'customFieldValueDelete',
'labelCreate',
'labelUpdate',
'labelDelete',
'listCreate',
'listUpdate',
'listClear',
'listDelete',
'notificationCreate',
'notificationUpdate',
'notificationServiceCreate',
'notificationServiceUpdate',
'notificationServiceDelete',
'projectCreate',
'projectUpdate',
'projectDelete',
'projectManagerCreate',
'projectManagerDelete',
'taskCreate',
'taskUpdate',
'taskDelete',
'taskListCreate',
'taskListUpdate',
'taskListDelete',
'userCreate',
'userUpdate',
'userDelete',
'webhookCreate',
'webhookUpdate',
'webhookDelete',
];

View file

@ -7,6 +7,7 @@ import socket from './socket';
import login from './login';
import core from './core';
import modals from './modals';
import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@ -33,6 +34,7 @@ export default {
...login,
...core,
...modals,
...webhooks,
...users,
...projects,
...projectManagers,

View file

@ -0,0 +1,58 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import EntryActionTypes from '../constants/EntryActionTypes';
const createWebhook = (data) => ({
type: EntryActionTypes.WEBHOOK_CREATE,
payload: {
data,
},
});
const handleWebhookCreate = (webhook) => ({
type: EntryActionTypes.WEBHOOK_CREATE_HANDLE,
payload: {
webhook,
},
});
const updateWebhook = (id, data) => ({
type: EntryActionTypes.WEBHOOK_UPDATE,
payload: {
id,
data,
},
});
const handleWebhookUpdate = (webhook) => ({
type: EntryActionTypes.WEBHOOK_UPDATE_HANDLE,
payload: {
webhook,
},
});
const deleteWebhook = (id) => ({
type: EntryActionTypes.WEBHOOK_DELETE,
payload: {
id,
},
});
const handleWebhookDelete = (webhook) => ({
type: EntryActionTypes.WEBHOOK_DELETE_HANDLE,
payload: {
webhook,
},
});
export default {
createWebhook,
handleWebhookCreate,
updateWebhook,
handleWebhookUpdate,
deleteWebhook,
handleWebhookDelete,
};

View file

@ -21,6 +21,7 @@ export default {
translation: {
common: {
aboutPlanka: 'About PLANKA',
accessToken: 'Access token',
account: 'Account',
actions: 'Actions',
activateUser_title: 'Activate User',
@ -69,6 +70,7 @@ export default {
areYouSureYouWantToDeleteThisTask: 'Are you sure you want to delete this task?',
areYouSureYouWantToDeleteThisTaskList: 'Are you sure you want to delete this task list?',
areYouSureYouWantToDeleteThisUser: 'Are you sure you want to delete this user?',
areYouSureYouWantToDeleteThisWebhook: 'Are you sure you want to delete this webhook?',
areYouSureYouWantToEmptyTrash: 'Are you sure you want to empty the trash?',
areYouSureYouWantToLeaveBoard: 'Are you sure you want to leave the board?',
areYouSureYouWantToLeaveProject: 'Are you sure you want to leave the project?',
@ -151,6 +153,7 @@ export default {
deleteTaskList_title: 'Delete Task List',
deleteTask_title: 'Delete Task',
deleteUser_title: 'Delete User',
deleteWebhook_title: 'Delete Webhook',
deletedUser_title: 'Deleted User',
description: 'Description',
detectAutomatically: 'Detect automatically',
@ -182,6 +185,8 @@ export default {
enterFilename: 'Enter filename',
enterListTitle: 'Enter list title...',
enterTaskDescription: 'Enter task description...',
events: 'Events',
excludedEvents: 'Excluded events',
filterByLabels_title: 'Filter By Labels',
filterByMembers_title: 'Filter By Members',
forPersonalProjects: 'For personal projects.',
@ -286,6 +291,7 @@ export default {
typeTitleToConfirm: 'Type the title to confirm.',
unsavedChanges: 'Unsaved changes',
uploadedImages: 'Uploaded images',
url: 'URL',
userActions_title: 'User Actions',
userAddedCardToList: '<0>{{user}}</0> added <2>{{card}}</2> to {{list}}',
userAddedThisCardToList: '<0>{{user}}</0> added this card to {{list}}',
@ -316,6 +322,7 @@ export default {
viewer: 'Viewer',
viewers: 'Viewers',
visualTaskManagementWithLists: 'Visual task management with lists.',
webhooks: 'Webhooks',
withoutBaseGroup: 'Without base group',
writeComment: 'Write a comment...',
},
@ -338,6 +345,7 @@ export default {
addTaskList: 'Add task list',
addToCard: 'Add to card',
addUser: 'Add user',
addWebhook: 'Add webhook',
archive: 'Archive',
archiveCard: 'Archive card',
archiveCard_title: 'Archive Card',
@ -378,6 +386,7 @@ export default {
deleteTask_title: 'Delete Task',
deleteUser: 'Delete user',
deleteUser_title: 'Delete User',
deleteWebhook: 'Delete webhook',
dismissAll: 'Dismiss all',
duplicate: 'Duplicate',
duplicateCard_title: 'Duplicate Card',

View file

@ -16,6 +16,7 @@ export default {
translation: {
common: {
aboutPlanka: 'About PLANKA',
accessToken: 'Access token',
account: 'Account',
actions: 'Actions',
activateUser_title: 'Activate User',
@ -64,6 +65,7 @@ export default {
areYouSureYouWantToDeleteThisTask: 'Are you sure you want to delete this task?',
areYouSureYouWantToDeleteThisTaskList: 'Are you sure you want to delete this task list?',
areYouSureYouWantToDeleteThisUser: 'Are you sure you want to delete this user?',
areYouSureYouWantToDeleteThisWebhook: 'Are you sure you want to delete this webhook?',
areYouSureYouWantToEmptyTrash: 'Are you sure you want to empty the trash?',
areYouSureYouWantToLeaveBoard: 'Are you sure you want to leave the board?',
areYouSureYouWantToLeaveProject: 'Are you sure you want to leave the project?',
@ -146,6 +148,7 @@ export default {
deleteTaskList_title: 'Delete Task List',
deleteTask_title: 'Delete Task',
deleteUser_title: 'Delete User',
deleteWebhook_title: 'Delete Webhook',
deletedUser_title: 'Deleted User',
description: 'Description',
detectAutomatically: 'Detect automatically',
@ -177,6 +180,8 @@ export default {
enterFilename: 'Enter filename',
enterListTitle: 'Enter list title...',
enterTaskDescription: 'Enter task description...',
events: 'Events',
excludedEvents: 'Excluded events',
filterByLabels_title: 'Filter By Labels',
filterByMembers_title: 'Filter By Members',
forPersonalProjects: 'For personal projects.',
@ -281,6 +286,7 @@ export default {
typeTitleToConfirm: 'Type the title to confirm.',
unsavedChanges: 'Unsaved changes',
uploadedImages: 'Uploaded images',
url: 'URL',
userActions_title: 'User Actions',
userAddedCardToList: '<0>{{user}}</0> added <2>{{card}}</2> to {{list}}',
userAddedThisCardToList: '<0>{{user}}</0> added this card to {{list}}',
@ -311,6 +317,7 @@ export default {
viewer: 'Viewer',
viewers: 'Viewers',
visualTaskManagementWithLists: 'Visual task management with lists.',
webhooks: 'Webhooks',
withoutBaseGroup: 'Without base group',
writeComment: 'Write a comment...',
},
@ -333,6 +340,7 @@ export default {
addTaskList: 'Add task list',
addToCard: 'Add to card',
addUser: 'Add user',
addWebhook: 'Add webhook',
archive: 'Archive',
archiveCard: 'Archive card',
archiveCard_title: 'Archive Card',
@ -373,6 +381,7 @@ export default {
deleteTask_title: 'Delete Task',
deleteUser: 'Delete user',
deleteUser_title: 'Delete User',
deleteWebhook: 'Delete webhook',
dismissAll: 'Dismiss all',
duplicate: 'Duplicate',
duplicateCard_title: 'Duplicate Card',

View file

@ -0,0 +1,437 @@
import dateFns from 'date-fns/locale/et';
import timeAgo from 'javascript-time-ago/locale/et';
import markdownEditor from './markdown-editor.json';
export default {
dateFns,
timeAgo,
markdownEditor,
format: {
date: 'M/d/yyyy',
time: 'p',
dateTime: '$t(format:date) $t(format:time)',
longDate: 'MMM d',
longDateTime: "MMMM d 'at' p",
fullDate: 'MMM d, y',
fullDateTime: "MMMM d, y 'at' p",
},
translation: {
common: {
aboutPlanka: 'Planka kohta',
account: 'Konto',
actions: 'Tegevused',
activateUser_title: 'Aktiveeri kasutaja',
active: 'Aktiivne',
addAttachment_title: 'Lisa manus',
addCustomFieldGroup_title: 'Lisa kohandatud väljade grupp',
addCustomField_title: 'Lisa kohandatud väli',
addManager_title: 'Lisa haldur',
addMember_title: 'Lisa liige',
addTaskList_title: 'Lisa ülesannete nimekiri',
addUser_title: 'Lisa kasutaja',
admin: 'Administraator',
administration: 'Administreerimine',
all: 'Kõik',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Kõik muudatused salvestatakse automaatselt pärast ühenduse taastamist.',
alphabetically: 'Tähestiku järgi',
alwaysDisplayCardCreator: 'Näita alati kaardi loojat',
archive: 'Arhiveeri',
archiveCard_title: 'Arhiveeri kaart',
archiveCards_title: 'Arhiveeri kaardid',
areYouSureYouWantToActivateThisUser: 'Oled kindel, et soovid seda kasutajat aktiveerida?',
areYouSureYouWantToArchiveCards: 'Oled kindel, et soovid kaarte arhiveerida?',
areYouSureYouWantToArchiveThisCard: 'Oled kindel, et soovid seda kaarti arhiveerida?',
areYouSureYouWantToAssignThisProjectManagerAsOwner:
'Oled kindel, et soovid seda projektihaldurit omanikuks määrata?',
areYouSureYouWantToDeactivateThisUser: 'Oled kindel, et soovid seda kasutajat deaktiveerida?',
areYouSureYouWantToDeleteThisAttachment: 'Oled kindel, et soovid seda manusi kustutada?',
areYouSureYouWantToDeleteThisBackgroundImage:
'Oled kindel, et soovid seda taustapilla kustutada?',
areYouSureYouWantToDeleteThisBoard: 'Oled kindel, et soovid seda tahveli kustutada?',
areYouSureYouWantToDeleteThisCard: 'Oled kindel, et soovid seda kaarti kustutada?',
areYouSureYouWantToDeleteThisCardForever:
'Oled kindel, et soovid seda kaarti jäädavalt kustutada?',
areYouSureYouWantToDeleteThisComment: 'Oled kindel, et soovid seda kommentaari kustutada?',
areYouSureYouWantToDeleteThisCustomField:
'Oled kindel, et soovid seda kohandatud väli kustutada?',
areYouSureYouWantToDeleteThisCustomFieldGroup:
'Oled kindel, et soovid seda kohandatud väljade gruppi kustutada?',
areYouSureYouWantToDeleteThisLabel: 'Oled kindel, et soovid seda silti kustutada?',
areYouSureYouWantToDeleteThisList:
'Oled kindel, et soovid seda nimekirja kustutada? Kõik kaardid liigutatakse prügikasti.',
areYouSureYouWantToDeleteThisNotificationService:
'Oled kindel, et soovid seda teavitusteenuse kustutada?',
areYouSureYouWantToDeleteThisProject: 'Oled kindel, et soovid seda projekti kustutada?',
areYouSureYouWantToDeleteThisTask: 'Oled kindel, et soovid seda ülesannet kustutada?',
areYouSureYouWantToDeleteThisTaskList:
'Oled kindel, et soovid seda ülesannete nimekirja kustutada?',
areYouSureYouWantToDeleteThisUser: 'Oled kindel, et soovid seda kasutaja kustutada?',
areYouSureYouWantToEmptyTrash: 'Oled kindel, et soovid prügikasti tühjendada?',
areYouSureYouWantToLeaveBoard: 'Oled kindel, et soovid lahku tahvlilt?',
areYouSureYouWantToLeaveProject: 'Oled kindel, et soovid lahku projektist?',
areYouSureYouWantToMakeThisProjectShared:
'Oled kindel, et soovid seda projekti jagatavaks määrata?',
areYouSureYouWantToRemoveThisManagerFromProject:
'Oled kindel, et soovid seda haldurit projektist eemaldada?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Oled kindel, et soovid seda liiget tahvlilt eemaldada?',
assignAsOwner_title: 'Määra omanikuks',
atLeastOneListMustBePresent: 'Vähemalt üks nimekiri peab olemas olema',
attachment: 'Manus',
attachments: 'Manused',
authentication: 'Autentimine',
background: 'Taust',
baseCustomFields_title: 'Põhiväljad',
baseGroup: 'Põhiklass',
board: 'Tahvel',
boardActions_title: 'Tahvelitegevused',
boardNotFound_title: 'Tahvel ei leitud',
boardSubscribed: 'Tahvel tellitud',
boardUser: 'Tahvelkasutaja',
byCreationTime: 'Kõrvaliku järgi',
byDefault: 'Vaikimisi',
byDueDate: 'Kõrvaliku järgi',
canBeInvitedToWorkInBoards: 'Saab kutsuda tööle tahvlid.',
canComment: 'Saab kommenteerida',
canCreateOwnProjectsAndBeInvitedToWorkInOthers:
'Saab luua oma projekte ja kutsuda tööle teised.',
canEditBoardLayoutAndAssignMembersToCards:
'Saab tahveli kujundust ja liikmeid kaarte määrama.',
canManageSystemWideSettingsAndActAsProjectOwner:
'Saab hallata süsteemi üldseadeid ja mõjutada projekti omanikut.',
canOnlyViewBoard: 'Saab vaid tahveli vaadata.',
cardActions_title: 'Kaardi tegevused',
cardNotFound_title: 'Kaart ei leitud',
cardsOnThisListAreAvailableToAllBoardMembers:
'Kaardid sellel nimekirjal on saadaval kõigile tahvelkasutajatele.',
cardsOnThisListAreCompleteAndReadyToBeArchived:
'Kaardid sellel nimekirjal on täidetud ja valmis arhiveerimiseks.',
cardsOnThisListAreReadyToBeWorkedOn: 'Kaardid sellel nimekirjal on valmis tööle.',
clickHereOrRefreshPageToUpdate: '<0>Klõpsa siia</0> või uuendage lehte.',
closed: 'Suletud',
color: 'Värv',
comments: 'Kommentaarid',
contentExceedsLimit: 'Sisu ületab {{limit}}',
contentOfThisAttachmentIsTooBigToDisplay: 'Sisu seda manusi ei õnnestu kuvada.',
copy_inline: 'kopeeri',
createBoard_title: 'Loo tahvel',
createCustomFieldGroup_title: 'Loo kohandatud väljade grupp',
createLabel_title: 'Loo silt',
createNewOneOrSelectExistingOne: 'Loo uus või vali<br />olemasolev.',
createProject_title: 'Loo projekt',
createTextFile_title: 'Loo tekstifail',
creator: 'Looja',
currentPassword: 'Praegune parool',
customFieldGroup_title: 'Kohandatud väljade grupp',
customFieldGroups_title: 'Kohandatud väljade grupid',
customField_title: 'Kohandatud väli',
customFields_title: 'Kohandatud väljad',
dangerZone_title: 'Ohtliku ala',
date: 'Kuupäev',
deactivateUser_title: 'Deaktiveeri kasutaja',
defaultCardType_title: 'Vaikimisi kaardi tüüp',
defaultView_title: 'Vaikimisi vaade',
deleteAllBoardsToBeAbleToDeleteThisProject:
'Kustuta kõik tahvlid, et seda projekti kustutada',
deleteAttachment_title: 'Kustuta manus',
deleteBackgroundImage_title: 'Kustuta taustapilt',
deleteBoard_title: 'Kustuta tahvel',
deleteCardForever_title: 'Kustuta kaart jäädavalt',
deleteCard_title: 'Kustuta kaart',
deleteComment_title: 'Kustuta kommentaar',
deleteCustomFieldGroup_title: 'Kustuta kohandatud väljade grupp',
deleteCustomField_title: 'Kustuta kohandatud väli',
deleteLabel_title: 'Kustuta silt',
deleteList_title: 'Kustuta nimekiri',
deleteNotificationService_title: 'Kustuta teavitusteenus',
deleteProject_title: 'Kustuta projekt',
deleteTaskList_title: 'Kustuta ülesannete nimekiri',
deleteTask_title: 'Kustuta ülesanne',
deleteUser_title: 'Kustuta kasutaja',
deletedUser_title: 'Kustutatud kasutaja',
description: 'Kirjeldus',
detectAutomatically: 'Tuletage automaatselt',
display: 'Kuva',
dropFileToUpload: 'Lase faili üleslaadida',
dueDate_title: 'Tähtaeg',
dynamicAndUnevenlySpacedLayout: 'Dünaamiline ja eirastega kujundus.',
editAttachment_title: 'Muuda manus',
editAvatar_title: 'Muuda avatar',
editColor_title: 'Muuda värvi',
editCustomFieldGroup_title: 'Muuda kohandatud väljade gruppi',
editCustomField_title: 'Muuda kohandatud väli',
editDueDate_title: 'Muuda tähtaega',
editEmail_title: 'Muuda e-posti',
editInformation_title: 'Muuda infot',
editLabel_title: 'Muuda silt',
editPassword_title: 'Muuda parooli',
editPermissions_title: 'Muuda õigusi',
editRole_title: 'Muuda rolli',
editStopwatch_title: 'Muuda stopperit',
editType_title: 'Muuda tüüpi',
editUsername_title: 'Muuda kasutajanime',
editor: 'Redaktor',
editors: 'Redaktorid',
email: 'E-post',
emptyTrash_title: 'Tühjenda prügikast',
enterCardTitle: 'Sisestage kaardi pealkiri...',
enterDescription: 'Sisestage kirjeldus...',
enterFilename: 'Sisestage failinimi',
enterListTitle: 'Sisestage nimekiri pealkiri...',
enterTaskDescription: 'Sisestage ülesande kirjeldus...',
filterByLabels_title: 'Filtreeri siltide järgi',
filterByMembers_title: 'Filtreeri liikmete järgi',
forPersonalProjects: 'Inimlikuks projektideks.',
forTeamBasedProjects: 'Töögrupi põhised projektid.',
fromComputer_title: 'Arvutist',
fromTrello: 'Trellost',
general: 'Üldine',
gradients: 'Gradiendid',
grid: 'Grill',
hideFromProjectListAndFavorites: 'Peida projektiloendist ja lemmikutest',
hours: 'Tunnid',
importBoard_title: 'Impordi tahvel',
invalidCurrentPassword: 'Vale praegune parool',
kanban: 'Kanban',
labels: 'Sildid',
language: 'Keel',
leaveBoard_title: 'Lahku tahvlilt',
leaveProject_title: 'Lahku projektist',
limitCardTypesToDefaultOne: 'Piirata kaardi tüüpe vaikimisi üheks',
list: 'Nimekiri',
listActions_title: 'Nimekiri tegevused',
lists: 'Nimekirjad',
makeProjectShared_title: 'Muuda projekt jagatavaks',
managers: 'Haldurid',
memberActions_title: 'Liikme tegevused',
members: 'Liikmed',
minutes: 'Minutid',
moveCard_title: 'Liiguta kaart',
myOwn_title: 'Minu omanik',
name: 'Nimi',
newEmail: 'Uus e-post',
newPassword: 'Uus parool',
newUsername: 'Uus kasutajanimi',
newVersionAvailable: 'Uus versioon saadaval',
newestFirst: 'Kõige uuem',
noBoards: 'Tahvleid pole',
noConnectionToServer: 'Ühendust serveriga ei leitud',
noLists: 'Nimekirju pole',
noProjects: 'Projekte pole',
noUnreadNotifications: 'Lugemata teavitused.',
notifications: 'Teavitused',
oldestFirst: 'Kõige vanem',
openBoard_title: 'Ava tahvel',
optional_inline: 'valikuline',
organization: 'Organisatsioon',
others: 'Teised',
phone: 'Telefon',
plankaUsesAppriseToSendNotificationsToOver100PopularServices:
'PLANKA kasutab <1><0>Apprise</0></1> teavitusteenuse, et teavitada üle 100 populaarset teenust.',
preferences: 'Eelistused',
pressPasteShortcutToAddAttachmentFromClipboard:
"Näpunäide: vajutage Ctrl-V (Cmd-V Mac'il) manuse lisamiseks kleebist.",
private: 'Privaatne',
project: 'Projekt',
projectNotFound_title: 'Projekt ei leitud',
projectOwner: 'Projekti omanik',
referenceDataAndKnowledgeStorage: 'Viideandmete ja teadmise salvestamiseks.',
removeManager_title: 'Eemalda haldur',
removeMember_title: 'Eemalda liige',
role: 'Roll',
searchCards: 'Kaartide otsimine...',
searchCustomFieldGroups: 'Kohandatud väljade gruppide otsimine...',
searchCustomFields: 'Kohandatud väljade otsimine...',
searchLabels: 'Siltide otsimine...',
searchLists: 'Nimekiri otsimine...',
searchMembers: 'Liikmete otsimine...',
searchProjects: 'Projektide otsimine...',
searchUsers: 'Kasutajate otsimine...',
seconds: 'Sekundid',
selectAssignee_title: 'Vali vastutaja',
selectBoard: 'Vali tahvel',
selectList: 'Vali nimekiri',
selectListToRestoreThisCard: 'Vali nimekiri, et seda kaart taastada',
selectOrder_title: 'Vali järjekord',
selectPermissions_title: 'Vali õigused',
selectProject: 'Vali projekt',
selectRole_title: 'Vali roll',
selectType_title: 'Vali tüüp',
sequentialDisplayOfCards: 'Järjestikune kaardi kuvamine.',
settings: 'Seaded',
shared: 'Jagatud',
sharedWithMe_title: 'Jagatud minuga',
showOnFrontOfCard: 'Kuva kaardi ees',
sortList_title: 'Nimekiri sorteerimine',
stopwatch: 'Stopper',
story: 'Kirjeldus',
subscribeToCardWhenCommenting: 'Telli kaart, kui kommenteerida',
subscribeToMyOwnCardsByDefault: 'Telli oma kaardid vaikimisi',
taskActions_title: 'Ülesande tegevused',
taskAssignmentAndProjectCompletion: 'Ülesande määramine ja projekti lõpetamine.',
taskListActions_title: 'Ülesannete nimekiri tegevused',
taskList_title: 'Ülesanne nimekiri',
team: 'Töögrupp',
thereIsNoPreviewAvailableForThisAttachment: 'Selle manusi eelvaadet pole saadaval.',
time: 'Aeg',
title: 'Pealkiri',
trash: 'Prügikast',
trashHasBeenSuccessfullyEmptied: 'Prügikast on edukalt tühjendatud.',
turnOffRecentCardHighlighting: 'Lülita välja hiljuti kuvatud kaardi üleminek',
typeNameToConfirm: 'Sisestage nimi, et kinnitada.',
typeTitleToConfirm: 'Sisestage pealkiri, et kinnitada.',
unsavedChanges: 'Muudetud andmed',
uploadedImages: 'Laaditud pildid',
userActions_title: 'Kasutaja tegevused',
userAddedCardToList: '<0>{{user}}</0> lisas <2>{{card}}</2> nimekirjaan {{list}}',
userAddedThisCardToList: '<0>{{user}}</0> lisas selle kaardi nimekirjaan {{list}}',
userAddedUserToCard: '<0>{{actorUser}}</0> lisas {{addedUser}} kaardile <4>{{card}}</4>',
userAddedUserToThisCard: '<0>{{actorUser}}</0> lisas {{addedUser}} selle kaardi',
userAddedYouToCard: '<0>{{user}}</0> lisas sind kaardile <2>{{card}}</2>',
userCompletedTaskOnCard: '<0>{{user}}</0> täideti {{task}} kaardil <4>{{card}}</4>',
userCompletedTaskOnThisCard: '<0>{{user}}</0> täideti {{task}} selle kaardil',
userJoinedCard: '<0>{{user}}</0> liitus <2>{{card}}</2>',
userJoinedThisCard: '<0>{{user}}</0> liitus selle kaardiga',
userLeftCard: '<0>{{user}}</0> lahkus <2>{{card}}</2>',
userLeftNewCommentToCard:
'<0>{{user}}</0> jäi uus kommentaar «{{comment}}» kaardile <2>{{card}}</2>',
userLeftThisCard: '<0>{{user}}</0> lahkus selle kaardist',
userMarkedTaskIncompleteOnCard:
'<0>{{user}}</0> märgis {{task}} täitmata kaardil <4>{{card}}</4>',
userMarkedTaskIncompleteOnThisCard: '<0>{{user}}</0> märgis {{task}} täitmata selle kaardil',
userMentionedYouInCommentOnCard:
'<0>{{user}}</0> mainis sind kommentaaris «{{comment}}» kaardil <2>{{card}}</2>',
userMovedCardFromListToList:
'<0>{{user}}</0> liigutas <2>{{card}}</2> nimekirjast {{fromList}} nimekirjaan {{toList}}',
userMovedThisCardFromListToList:
'<0>{{user}}</0> liigutas selle kaardi nimekirjast {{fromList}} nimekirjaan {{toList}}',
userRemovedUserFromCard:
'<0>{{actorUser}}</0> eemaldas {{removedUser}} kaardilt <4>{{card}}</4>',
userRemovedUserFromThisCard: '<0>{{actorUser}}</0> eemaldas {{removedUser}} selle kaardist',
username: 'Kasutajanimi',
users: 'Kasutajad',
viewer: 'Vaataja',
viewers: 'Vaatajad',
visualTaskManagementWithLists: 'Visual tööülesande haldamine nimekirjade abil.',
withoutBaseGroup: 'Ilma põhiklassita',
writeComment: 'Kirjuta kommentaar...',
},
action: {
activateUser: 'Aktiveeri kasutaja',
activateUser_title: 'Aktiveeri kasutaja',
addAnotherCard: 'Lisa veel kaart',
addAnotherList: 'Lisa veel nimekiri',
addAnotherTask: 'Lisa veel ülesanne',
addCard: 'Lisa kaart',
addCard_title: 'Lisa kaart',
addComment: 'Lisa kommentaar',
addCustomField: 'Lisa kohandatud väli',
addCustomFieldGroup: 'Lisa kohandatud väljade grupp',
addList: 'Lisa nimekiri',
addMember: 'Lisa liige',
addMoreDetailedDescription: 'Lisa üksikasjalikum kirjeldus',
addTask: 'Lisa ülesanne',
addTaskList: 'Lisa ülesannete nimekiri',
addToCard: 'Lisa kaardile',
addUser: 'Lisa kasutaja',
archive: 'Arhiveeri',
archiveCard: 'Arhiveeri kaart',
archiveCard_title: 'Arhiveeri kaart',
archiveCards: 'Arhiveeri kaardid',
archiveCards_title: 'Arhiveeri kaardid',
assignAsOwner: 'Määra omanikuks',
cancel: 'Tühista',
createBoard: 'Loo tahvel',
createCustomFieldGroup: 'Loo kohandatud väljade grupp',
createFile: 'Loo fail',
createLabel: 'Loo silt',
createNewLabel: 'Loo uus silt',
createProject: 'Loo projekt',
deactivateUser: 'Deaktiveeri kasutaja',
deactivateUser_title: 'Deaktiveeri kasutaja',
delete: 'Kustuta',
deleteAttachment: 'Kustuta manus',
deleteAvatar: 'Kustuta avatar',
deleteBackgroundImage: 'Kustuta taustapilt',
deleteBoard: 'Kustuta tahvel',
deleteBoard_title: 'Kustuta tahvel',
deleteCard: 'Kustuta kaart',
deleteCardForever: 'Kustuta kaart jäädavalt',
deleteCard_title: 'Kustuta kaart',
deleteComment: 'Kustuta kommentaar',
deleteCustomField: 'Kustuta kohandatud väli',
deleteCustomFieldGroup: 'Kustuta kohandatud väljade grupp',
deleteForever_title: 'Kustuta jäädavalt',
deleteGroup: 'Kustuta grupp',
deleteLabel: 'Kustuta silt',
deleteList: 'Kustuta nimekiri',
deleteList_title: 'Kustuta nimekiri',
deleteNotificationService: 'Kustuta teavitusteenus',
deleteProject: 'Kustuta projekt',
deleteProject_title: 'Kustuta projekt',
deleteTask: 'Kustuta ülesanne',
deleteTaskList: 'Kustuta ülesannete nimekiri',
deleteTask_title: 'Kustuta ülesanne',
deleteUser: 'Kustuta kasutaja',
deleteUser_title: 'Kustuta kasutaja',
dismissAll: 'Eemalda kõik',
duplicate: 'Dubleeri',
duplicateCard_title: 'Duplikaardi loomine',
edit: 'Muuda',
editColor_title: 'Muuda värvi',
editDescription_title: 'Muuda kirjeldust',
editDueDate_title: 'Muuda tähtaega',
editEmail_title: 'Muuda e-posti',
editGroup: 'Muuda gruppi',
editInformation_title: 'Muuda infot',
editPassword_title: 'Muuda parooli',
editPermissions: 'Muuda õigusi',
editRole_title: 'Muuda rolli',
editStopwatch_title: 'Muuda stopperit',
editTitle_title: 'Muuda pealkirja',
editType_title: 'Muuda tüüpi',
editUsername_title: 'Muuda kasutajanime',
emptyTrash: 'Tühjenda prügikast',
emptyTrash_title: 'Tühjenda prügikast',
import: 'Impordi',
join: 'Liitu',
leave: 'Lahku',
leaveBoard: 'Lahku tahvlilt',
leaveProject: 'Lahku projektist',
logOut_title: 'Logi välja',
makeCover_title: 'Määra kaaneks',
makeProjectShared: 'Muuda projekt jagatavaks',
makeProjectShared_title: 'Muuda projekt jagatavaks',
move: 'Liiguta',
moveCard_title: 'Liiguta kaart',
remove: 'Eemalda',
removeAssignee: 'Eemalda vastutaja',
removeColor: 'Eemalda värv',
removeCover_title: 'Eemalda kaas',
removeFromBoard: 'Eemalda tahvlilt',
removeFromProject: 'Eemalda projektist',
removeManager: 'Eemalda haldur',
removeMember: 'Eemalda liige',
restoreToList: 'Taasta nimekirja {{list}}',
returnToBoard: 'Tagasi tahvlile',
save: 'Salvesta',
showActive: 'Näita aktiivseid',
showAllAttachments: 'Näita kõiki manuseid ({{hidden}} peidetud)',
showCardsWithThisUser: 'Näita selle kasutajaga kaarte',
showDeactivated: 'Näita deaktiveerituid',
showFewerAttachments: 'Näita vähem manuseid',
sortList_title: 'Sorteeri nimekiri',
start: 'Alusta',
stop: 'Peata',
subscribe: 'Telli',
unsubscribe: 'Tühista tellimus',
uploadNewAvatar: 'Laadi üles uus avatar',
uploadNewImage: 'Laadi üles uus pilt',
},
},
};

View file

@ -0,0 +1,8 @@
import login from './login';
export default {
language: 'et-EE',
country: 'ee',
name: 'Eesti',
embeddedLocale: login,
};

View file

@ -0,0 +1,27 @@
export default {
translation: {
common: {
activeUsersLimitReached: 'Aktiivsete kasutajate limiit on täis',
emailAlreadyInUse: 'E-post on juba kasutusel',
emailOrUsername: 'E-post või kasutajanimi',
invalidCredentials: 'Vale kasutajanimi või parool',
invalidEmailOrUsername: 'Vale e-post või kasutajanimi',
invalidPassword: 'Vale parool',
logIn_title: 'Logi sisse',
noInternetConnection: 'Internetiühendus puudub',
or: 'Või',
pageNotFound_title: 'Lehte ei leitud',
password: 'Parool',
poweredByPlanka: 'Töötab <1>PLANKA</1> platvormil',
serverConnectionFailed: 'Serveriühendus ebaõnnestus',
unknownError: 'Tundmatu viga, proovi hiljem uuesti',
useSingleSignOn: 'Kasuta ühekordset sisselogimist',
usernameAlreadyInUse: 'Kasutajanimi on juba kasutusel',
},
action: {
logIn: 'Logi sisse',
logInWithSso: 'Logi sisse SSO-ga',
},
},
};

View file

@ -0,0 +1,165 @@
{
"action-previews": {
"text": "See on tekst ilma pealkirjata.\nNii pealkirja kui ka teksti\nsaab esile tõsta paksus, kaldkirjas, värvilisena,\nläbikriipsutatuna ja allajoonituna.",
"text-with-head": "See on tekst koos pealkirjaga.\nNii pealkirja kui ka teksti\nsaab esile tõsta paksus, kaldkirjas, värvilisena,\nläbikriipsutatuna ja allajoonituna.",
"heading": "Pealkiri"
},
"bundle": {
"error-title": "Viga markdown-redaktoris",
"settings_wysiwyg": "Visuaalne redaktor (wysiwyg)",
"settings_markup": "Markdown märgistus",
"markup_placeholder": "Sisesta markdown märgistus..."
},
"codeblock": {
"remove": "Eemalda",
"empty_option": "Vastavusi ei leitud"
},
"common": {
"delete": "Kustuta",
"edit": "Muuda",
"toolbar_action_disabled": "Ühildumatu märgistus"
},
"forms": {
"common_action_cancel": "Tühista",
"common_action_submit": "Saada",
"common_action_upload": "Vali",
"common_tab_attach": "Lisa seadmest",
"common_tab_link": "Lisa lingi kaudu",
"common_link": "Link",
"common_sizes": "Suurus, px",
"image_name": "Pealkiri",
"image_link_href": "Pildi link",
"image_link_href_help": "Aadress, kuhu pildi link viib.",
"image_alt": "Alternatiivtekst",
"image_alt_help": "Alternatiivtekst kuvatakse, kui pilti ei saa laadida.",
"image_upload_help": "JPEG, GIF või PNG pilt kuni 1 MB.",
"image_upload_failed": "Pildi lisamine ebaõnnestus",
"image_size_width": "Laius",
"image_size_height": "Kõrgus",
"link_url_help": "Aadress, kuhu link viib.",
"link_text": "Lingitekst",
"link_text_help": "Tekst, mida kuvatakse lingina.",
"link_open_help": "Ava link uues vahekaardis"
},
"md-hints": {
"header_title": "Pealkiri",
"header_hint": "# Sinu tekst",
"italic_title": "Kaldkiri",
"italic_hint": "_Sinu tekst_",
"bold_title": "Paks",
"bold_hint": "**Sinu tekst**",
"strikethrough_title": "Läbikriipsutus",
"strikethrough_hint": "~~Sinu tekst~~",
"blockquote_title": "Tsitaat",
"blockquote_hint": "> Sinu tekst",
"code_title": "Kood",
"code_hint": "```Sinu tekst```",
"link_title": "Link",
"link_hint": "[Sinu tekst](url)",
"image_title": "Pilt",
"image_hint": "![Sinu tekst](url)",
"list_title": "Loendi element",
"list_hint": "- Sinu tekst",
"numbered-list_title": "Nummerdatud loend",
"numbered-list_hint": "1. Sinu tekst",
"documentation": "Dokumentatsioon",
"documentation_link": "https://diplodoc.com/docs/et/syntax/"
},
"menubar": {
"bold": "Paks",
"code": "Kood",
"code_inline": "Reakood",
"codeblock": "Koodiplokk",
"colorify": "Teksti värv",
"colorify__color_blue": "Sinine",
"colorify__color_default": "Vaikimisi",
"colorify__color_gray": "Hall",
"colorify__color_green": "Roheline",
"colorify__color_orange": "Oranž",
"colorify__color_red": "Punane",
"colorify__color_violet": "Violetne",
"colorify__color_yellow": "Kollane",
"colorify__group_text": "Tekst",
"cut": "Lõika",
"emoji": "Emotikon",
"emoji__hint": "Emotikoone saab lisada WYSIWYG-is või käsitsi märgistusega",
"heading": "Pealkiri",
"heading1": "Pealkiri 1",
"heading2": "Pealkiri 2",
"heading3": "Pealkiri 3",
"heading4": "Pealkiri 4",
"heading5": "Pealkiri 5",
"heading6": "Pealkiri 6",
"hrule": "Eraldaja",
"image": "Pilt",
"italic": "Kaldkiri",
"link": "Link",
"list": "Loend",
"list__action_lift": "Tõsta üles",
"list__action_sink": "Langeta alla",
"list_action_disabled": "Loogikaga vastuolus",
"mark": "Märgitud",
"mono": "Monospace",
"more_action": "Rohkem toiminguid",
"note": "Märkus",
"olist": "Järjestatud loend",
"quote": "Tsitaat",
"redo": "Tee uuesti",
"strike": "Läbikriipsutus",
"table": "Tabel",
"text": "Tekst",
"ulist": "Punktloend",
"underline": "Allajoonitud",
"undo": "Võta tagasi"
},
"placeholder": {
"doc_empty": "Kirjuta /, et kasutada käsklusi...",
"checkbox": "Sisesta ülesande kirjeldus...",
"deflist_term": "Mõiste",
"deflist_desc": "Mõiste kirjeldus",
"heading": "Pealkiri",
"cut_title": "Pealkiri",
"cut_content": "Sisu, mida kuvatakse klõpsamisel",
"note_title": "Pealkiri",
"note_content": "Märkuse sisu",
"table_cell": "Lahtri sisu",
"select_filter": "Otsi keeli..."
},
"search": {
"label_case-sensitive": "Tõstutundlik",
"label_whole-word": "Terve sõna",
"title": "Otsi koodist"
},
"suggest": {
"empty-msg": "Ei leitud"
},
"widgets": {
"image": "Lisa pilt",
"link": "Lisa link"
},
"yfm-note": {
"info": "Märkus",
"tip": "Nipp",
"warning": "Hoiatus",
"alert": "Häire",
"remove": "Eemalda"
},
"yfm-table": {
"column.add.before": "Lisa veerg enne",
"column.add.after": "Lisa veerg pärast",
"column.remove": "Eemalda veerg",
"row.add.before": "Lisa rida enne",
"row.add.after": "Lisa rida pärast",
"row.remove": "Eemalda rida",
"table.remove": "Eemalda tabel",
"table.menu.cell.align.left": "Joonda lahtri sisu vasakule",
"table.menu.cell.align.right": "Joonda lahtri sisu paremale",
"table.menu.cell.align.center": "Joonda lahtri sisu keskele",
"table.menu.row.add": "Lisa rida pärast",
"table.menu.row.remove": "Eemalda rida",
"table.menu.column.add": "Lisa veerg pärast",
"table.menu.column.remove": "Eemalda veerg",
"table.menu.convert.yfm": "Konverteeri YFM-tabeliks",
"table.menu.table.remove": "Eemalda tabel"
}
}

View file

@ -21,103 +21,210 @@ export default {
translation: {
common: {
aboutPlanka: 'À propos de PLANKA',
accessToken: "Jeton d'accès",
account: 'Compte',
actions: 'Actions',
activateUser_title: "Activer l'utilisateur",
active: 'Actif',
addAttachment_title: 'Ajouter une pièce jointe',
addManager_title: 'Ajouter un manager',
addCustomFieldGroup_title: 'Ajouter un groupe de champs personnalisés',
addCustomField_title: 'Ajouter un champ personnalisé',
addManager_title: 'Ajouter un responsable',
addMember_title: 'Ajouter un membre',
addTaskList_title: 'Ajouter une liste de tâches',
addUser_title: 'Ajouter un utilisateur',
admin: 'Administrateur',
administration: 'Administration',
all: 'Tout',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Toutes les modifications seront automatiquement enregistrées<br />une fois la connexion rétablie.',
alphabetically: 'Alphabétique',
alwaysDisplayCardCreator: 'Toujours afficher le créateur de la carte',
archive: 'Archiver',
archiveCard_title: 'Archiver la carte',
archiveCards_title: 'Cartes archivées',
areYouSureYouWantToActivateThisUser: 'Etes-vous sûr de vouloir activer cet utilisateur ?',
areYouSureYouWantToArchiveCards: 'Etes-vous sûr de vouloir archiver les cartes ?',
areYouSureYouWantToArchiveThisCard: 'Etes-vous sûr de vouloir archiver cette carte ?',
areYouSureYouWantToAssignThisProjectManagerAsOwner:
'Êtes-vous sûr de vouloir attribuer ce responsable de projet comme propriétaire ?',
areYouSureYouWantToDeactivateThisUser:
'Etes-vous sûr de vouloir désactiver cet utilisateur ?',
areYouSureYouWantToDeleteThisAttachment:
'Êtes-vous sûr de vouloir supprimer cette pièce jointe ?',
areYouSureYouWantToDeleteThisBackgroundImage:
'Etes-vous sûr de vouloir supprimer cette image darrière-plan ?',
areYouSureYouWantToDeleteThisBoard: 'Êtes-vous sûr de vouloir supprimer ce tableau ?',
areYouSureYouWantToDeleteThisCard: 'Êtes-vous sûr de vouloir supprimer cette carte ?',
areYouSureYouWantToDeleteThisCardForever:
'Êtes-vous sûr de vouloir supprimer cette carte définitivement ?',
areYouSureYouWantToDeleteThisComment: 'Êtes-vous sûr de vouloir supprimer ce commentaire ?',
areYouSureYouWantToDeleteThisCustomField:
'Êtes-vous sûr de vouloir supprimer ce champ personnalisé ?',
areYouSureYouWantToDeleteThisCustomFieldGroup:
'Êtes-vous sûr de vouloir supprimer ce groupe de champs personnalisés ?',
areYouSureYouWantToDeleteThisLabel: 'Êtes-vous sûr de vouloir supprimer cette étiquette ?',
areYouSureYouWantToDeleteThisList: 'Êtes-vous sûr de vouloir supprimer cette liste ?',
areYouSureYouWantToDeleteThisNotificationService:
'Êtes-vous sûr de vouloir supprimer ce service de notification ?',
areYouSureYouWantToDeleteThisProject: 'Êtes-vous sûr de vouloir supprimer ce projet ?',
areYouSureYouWantToDeleteThisTask: 'Êtes-vous sûr de vouloir supprimer cette tâche ?',
areYouSureYouWantToDeleteThisTaskList:
'Êtes-vous sûr de vouloir supprimer cette liste de tâches ?',
areYouSureYouWantToDeleteThisUser: 'Êtes-vous sûr de vouloir supprimer cet utilisateur ?',
areYouSureYouWantToDeleteThisWebhook: 'Etes-vous sûr de vouloir supprimer ce webhook ?',
areYouSureYouWantToEmptyTrash: 'Etes-vous sûr de vouloir vider la corbeille ?',
areYouSureYouWantToLeaveBoard: 'Etes-vous sûr de vouloir quitter ce tableau ?',
areYouSureYouWantToLeaveProject: 'Êtes-vous sûr de vouloir quitter ce projet ?',
areYouSureYouWantToMakeThisProjectShared:
"Etes-vous sûr de vouloir transformer ce projet en projet d'équipe ?",
areYouSureYouWantToRemoveThisManagerFromProject:
'Êtes-vous sûr de vouloir supprimer ce manager du projet ?',
'Êtes-vous sûr de vouloir supprimer ce responsable du projet ?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Êtes-vous sûr de vouloir supprimer ce membre du tableau ?',
assignAsOwner_title: 'Assigner comme propriétaire',
atLeastOneListMustBePresent: 'Au moins une liste doit être présente',
attachment: 'Pièce jointe',
attachments: 'Pièces jointes',
authentication: 'Authentification',
background: 'Arrière-plan',
baseCustomFields_title: 'Champs personnalisés de base',
baseGroup: 'Groupe de base',
board: 'Tableau',
boardActions_title: 'Actions du tableau',
boardNotFound_title: 'Carte non trouvée',
boardSubscribed: 'Abonné au tableau',
boardUser: 'Utilisateur de tableau',
byCreationTime: 'Par date de création',
byDefault: 'Par défaut',
byDueDate: 'Par date déchéance',
canBeInvitedToWorkInBoards: 'Peut être invité à travailler dans des tableaux.',
canComment: 'Peut commenter',
canCreateOwnProjectsAndBeInvitedToWorkInOthers:
'Peut créer ses propres projets et être invité à travailler dans dautres.',
canEditBoardLayoutAndAssignMembersToCards:
'Peut modifier la disposition du tableau et attribuer des membres aux cartes.',
canManageSystemWideSettingsAndActAsProjectOwner:
'Peut gérer les paramètres globaux du système et agir en tant que propriétaire de projet.',
canOnlyViewBoard: 'Peut uniquement voir le tableau.',
cardActions_title: 'Actions sur la carte',
cardNotFound_title: 'Carte non trouvée',
cardsOnThisListAreAvailableToAllBoardMembers:
'Les cartes de cette liste sont disponibles pour tous les membres du tableau.',
cardsOnThisListAreCompleteAndReadyToBeArchived:
'Les cartes de cette liste sont terminées et prêtes à être archivées.',
cardsOnThisListAreReadyToBeWorkedOn: 'Les cartes de cette liste sont prêtes à être traitées.',
clickHereOrRefreshPageToUpdate:
'<0>Cliquez ici</0> ou rafraîchissez la page pour mettre à jour.',
closed: 'Fermé',
color: 'Couleur',
comments: 'Commentaires',
contentExceedsLimit: 'Le contenu dépasse la limite {{limit}}',
contentOfThisAttachmentIsTooBigToDisplay:
'Le contenu de cette pièce jointe est trop volumineux pour être affiché.',
copy_inline: 'copie',
createBoard_title: 'Créer un tableau',
createCustomFieldGroup_title: 'Créer un groupe de champs personnalisés',
createLabel_title: 'Créer une étiquette',
createNewOneOrSelectExistingOne: 'Créez-en un nouveau ou sélectionnez<br />un existant.',
createProject_title: 'Créer un projet',
createTextFile_title: 'Créer un fichier texte',
creator: 'Créateur',
currentPassword: 'Mot de passe actuel',
customFieldGroup_title: 'Groupe de champs personnalisés',
customFieldGroups_title: 'Groupes de champs personnalisés',
customField_title: 'Champ personnalisé',
customFields_title: 'Champs personnalisés',
dangerZone_title: 'Zone dangereuse',
date: 'Date',
deactivateUser_title: 'Désactiver lutilisateur',
defaultCardType_title: 'Type de carte par défaut',
defaultView_title: 'Vue par défaut',
deleteAllBoardsToBeAbleToDeleteThisProject:
'Supprimer tous les tableaux pour pouvoir supprimer ce projet.',
deleteAttachment_title: 'Supprimer la pièce jointe',
deleteBackgroundImage_title: 'Supprimer limage darrière-plan',
deleteBoard_title: 'Supprimer le tableau',
deleteCardForever_title: 'Supprimer la carte définitivement',
deleteCard_title: 'Supprimer la carte',
deleteComment_title: 'Supprimer le commentaire',
deleteCustomFieldGroup_title: 'Supprimer le groupe de champs personnalisés',
deleteCustomField_title: 'Supprimer le champ personnalisé',
deleteLabel_title: "Supprimer l'étiquette",
deleteList_title: 'Supprimer la liste',
deleteNotificationService_title: 'Supprimer le service de notification',
deleteProject_title: 'Supprimer le projet',
deleteTaskList_title: 'Supprimer la liste de tâches',
deleteTask_title: 'Supprimer la tâche',
deleteUser_title: "Supprimer l'utilisateur",
deleteWebhook_title: 'Supprimer le webhook',
deletedUser_title: 'Utilisateur supprimé',
description: 'Description',
detectAutomatically: 'Détecter automatiquement',
display: 'Affichage',
dropFileToUpload: 'Déposer le fichier à télécharger',
dueDate_title: "Date d'échéance",
dynamicAndUnevenlySpacedLayout: 'Mise en page dynamique et inégalement espacée.',
editAttachment_title: 'Modifier la pièce jointe',
editAvatar_title: "Modifier l'avatar",
editColor_title: 'Modifier la couleur',
editCustomFieldGroup_title: 'Modifier le groupe de champs personnalisés',
editCustomField_title: 'Modifier le champ personnalisé',
editDueDate_title: "Modifier la date d'échéance",
editEmail_title: "Modifier l'e-mail",
editInformation_title: 'Modifier les informations',
editLabel_title: "Modifier l'étiquette",
editPassword_title: 'Modifier le mot de passe',
editPermissions_title: 'Modifier les permissions',
editRole_title: 'Modifier le rôle',
editStopwatch_title: 'Modifier la minuterie',
editType_title: 'Modifier le type',
editUsername_title: "Modifier le nom d'utilisateur",
editor: 'Éditeur',
editors: 'Éditeurs',
email: 'E-mail',
emptyTrash_title: 'Vider la corbeille',
enterCardTitle: 'Saisir le titre de la carte...',
enterDescription: 'Saisir la description...',
enterFilename: 'Saisir le nom du fichier',
enterListTitle: 'Saisie le titre de la liste...',
enterTaskDescription: 'Saisir la description de la tâche...',
events: 'Événements',
excludedEvents: 'Événements exclus',
filterByLabels_title: 'Filtrer par étiquettes',
filterByMembers_title: 'Filtrer par membres',
forPersonalProjects: 'Pour les projets personnels',
forTeamBasedProjects: 'Pour les projets basés sur une équipe',
fromComputer_title: "Depuis l'ordinateur",
fromTrello: 'Depuis Trello',
general: 'Général',
gradients: 'Dégradés',
grid: 'Grid',
hideFromProjectListAndFavorites: 'Masquer de la liste des projets et des favoris',
hours: 'Heures',
importBoard_title: 'Importer un tableau',
invalidCurrentPassword: 'Mot de passe actuel invalide',
kanban: 'Kanban',
labels: 'Étiquettes',
language: 'Langue',
leaveBoard_title: 'Quitter le tableau',
leaveProject_title: 'Quitter le projet',
limitCardTypesToDefaultOne: 'Restreindre les types de cartes au type par défaut',
list: 'Lister',
listActions_title: 'Liste des actions',
managers: 'Managers',
lists: 'Listes',
makeProjectShared_title: 'Transformer le projet en projet partagé',
managers: 'Responsables',
memberActions_title: 'Actions des membres',
members: 'Membres',
minutes: 'Minutes',
moveCard_title: 'Déplacer la carte',
myOwn_title: 'Mes projets privés',
name: 'Nom',
newEmail: 'Nouvel e-mail',
newPassword: 'Nouveau mot de passe',
newUsername: "Nouveau nom d'utilisateur",
newVersionAvailable: 'Une nouvelle version est disponible',
newestFirst: 'Le plus récent en premier',
noBoards: 'Pas de tableau',
noConnectionToServer: 'Pas de connexion au serveur',
@ -129,79 +236,162 @@ export default {
openBoard_title: 'Ouvrir le tableau',
optional_inline: 'optionnel',
organization: 'Organisation',
others: 'Autres',
phone: 'Téléphone',
plankaUsesAppriseToSendNotificationsToOver100PopularServices:
'PLANKA utilise <1><0>Apprise</0></1> pour envoyer des notifications vers plus de 100 services populaires.',
preferences: 'Préférences',
pressPasteShortcutToAddAttachmentFromClipboard:
'Conseil: appuyer sur Ctrl-V (Cmd-V sur Mac) pour ajouter une pièce jointe depuis le presse-papiers',
private: 'Privé',
project: 'Projet',
projectNotFound_title: 'Projet introuvable',
removeManager_title: 'Supprimer le manager',
projectOwner: 'Propriétaire de projet',
referenceDataAndKnowledgeStorage: 'Stockage de données de référence et de connaissances.',
removeManager_title: 'Supprimer le responsable',
removeMember_title: 'Supprimer le membre',
searchCards: 'Chercher une carte...',
searchLabels: 'Chercher une étiquette...',
searchMembers: 'Chercher un membre...',
searchUsers: 'Chercher un utilisateur...',
role: 'Rôle',
searchCards: 'Rechercher une carte...',
searchCustomFieldGroups: 'Chercher un groupe de champs personnalisés...',
searchCustomFields: 'Chercher un champ personnalisé...',
searchLabels: 'Rechercher une étiquette...',
searchLists: 'Rechercher une liste...',
searchMembers: 'Rechercher un membre...',
searchProjects: 'Rechercher un projet...',
searchUsers: 'Rechercher un utilisateur...',
seconds: 'Secondes',
selectAssignee_title: 'Sélectionner un responsable',
selectBoard: 'Sélectionner un tableau',
selectList: 'Sélectionner une liste',
selectListToRestoreThisCard: 'Sélectionner une liste pour restaurer cette carte',
selectOrder_title: 'Sélectionner lordre',
selectPermissions_title: 'Sélectionner les permissions',
selectProject: 'Sélectionner un projet',
selectRole_title: 'Sélectionner un rôle',
selectType_title: 'Sélectionner un type',
sequentialDisplayOfCards: 'Affichage séquentiel des cartes.',
settings: 'Réglages',
shared: 'Partagé',
sharedWithMe_title: 'Partagé avec moi',
showOnFrontOfCard: 'Afficher sur le devant de la carte',
sortList_title: 'Trier la liste',
stopwatch: 'Minuteur',
story: 'Story',
subscribeToCardWhenCommenting: 'Sabonner à la carte lors de la rédaction dun commentaire',
subscribeToMyOwnCardsByDefault: "M'abonner à mes propres cartes par défaut",
taskActions_title: 'Actions de tâche',
taskAssignmentAndProjectCompletion: 'Completion de tâches et dun projet.',
taskListActions_title: 'Actions de la liste de tâches',
taskList_title: 'Liste de tâches',
team: "Mes projets d'équipe",
thereIsNoPreviewAvailableForThisAttachment:
"Il n'y a pas d'aperçu disponible pour cette pièce jointe.",
time: 'Temps',
title: 'Titre',
trash: 'Corbeille',
trashHasBeenSuccessfullyEmptied: 'La corbeille a été vidée avec succès.',
turnOffRecentCardHighlighting: 'Désactiver la mise en évidence des cartes récentes',
typeNameToConfirm: 'Saissir le nom pour confirmer.',
typeTitleToConfirm: 'Saisir le titre pour confirmer.',
unsavedChanges: 'Modifications non enregistrées',
uploadedImages: 'Images téléchargées',
url: 'URL',
userActions_title: "Actions de l'utilisateur",
userAddedCardToList: '<0>{{user}}</0> a ajouté <2>{{card}}</2> à {{list}}',
userAddedThisCardToList: '<0>{{user}}</0> a ajouté cette carte à {{list}}',
userAddedUserToCard: '<0>{{actorUser}}</0> a ajouté {{addedUser}} à <4>{{card}}</4>',
userAddedUserToThisCard: '<0>{{actorUser}}</0> a ajouté {{addedUser}} à cette carte',
userAddedYouToCard: '<0>{{user}}</0> vous a ajouté à <2>{{card}}</2>',
userCompletedTaskOnCard: '<0>{{user}}</0> a finalisé {{task}} dans <4>{{card}}</4>',
userCompletedTaskOnThisCard: '<0>{{user}}</0> a finalisé {{task}} dans cette carte',
userJoinedCard: '<0>{{user}}</0> a rejoint <2>{{card}}</2>',
userJoinedThisCard: '<0>{{user}}</0> a rejoint cette carte',
userLeftCard: '<0>{{user}}</0> a quitté <2>{{card}}</2>',
userLeftNewCommentToCard:
'<0>{{user}}</0> a laissé un nouveau commentaire {{comment}} à <2>{{card}}</2>',
userLeftThisCard: '<0>{{user}}</0> a quitté cette carte',
userMarkedTaskIncompleteOnCard:
'<0>{{user}}</0> a marqué {{task}} comme incomplete dans <4>{{card}}</4>',
userMarkedTaskIncompleteOnThisCard:
'<0>{{user}}</0> a marqué {{task}} comme incomplete dans cette carte',
userMentionedYouInCommentOnCard:
'<0>{{user}}</0> vous a mentionné dans un commentaire «{{comment}}» dans <2>{{card}}</2>',
userMovedCardFromListToList:
'<0>{{user}}</0> a déplacé <2>{{card}}</2> de {{fromList}} vers {{toList}}',
userMovedThisCardFromListToList:
'<0>{{user}}</0> a déplacé cette carte de {{fromList}} vers {{toList}}',
userRemovedUserFromCard: '<0>{{actorUser}}</0> a retiré {{removedUser}} de <4>{{card}}</4>',
userRemovedUserFromThisCard: '<0>{{actorUser}}</0> a retiré {{removedUser}} de cette carte',
username: "Nom d'utilisateur",
users: 'Utilisateurs',
viewer: 'Spectateur',
viewers: 'Spectateurs',
visualTaskManagementWithLists: 'Management visuel des tâches avec des listes.',
webhooks: 'Webhooks',
withoutBaseGroup: 'Sans groupe de base',
writeComment: 'Écrire un commentaire...',
},
action: {
activateUser: 'Activer lutilisateur',
activateUser_title: 'Activer lutilisateur',
addAnotherCard: 'Ajouter une autre carte',
addAnotherList: 'Ajouter une autre liste',
addAnotherTask: 'Ajouter une autre tâche',
addCard: 'Ajouter une carte',
addCard_title: 'Ajouter une carte',
addComment: 'Ajouter un commentaire',
addCustomField: 'Ajouter un champ personnalisé',
addCustomFieldGroup: 'Ajouter un groupe de champs personnalisés',
addList: 'Ajouter la liste',
addMember: 'Ajouter un membre',
addMoreDetailedDescription: 'Ajouter une description plus détaillée',
addTask: 'Ajouter une tâche',
addTaskList: 'Ajouter une liste de tâches',
addToCard: 'Ajouter à la carte',
addUser: 'Ajouter un utilisateur',
addWebhook: 'Ajouter un webhook',
archive: 'Archiver',
archiveCard: 'Archiver la carte',
archiveCard_title: 'Archiver la carte',
archiveCards: 'Archiver les cartes',
archiveCards_title: 'Archiver les cartes',
assignAsOwner: 'Assigner comme propriétaire',
cancel: 'Annuler',
createBoard: 'Créer un tableau',
createCustomFieldGroup: 'Créer un groupe de champs personnalisés',
createFile: 'Créer un fichier',
createLabel: 'Créer une étiquette',
createNewLabel: 'Créer une nouvelle étiquette',
createProject: 'Créer un projet',
deactivateUser: 'Désactiver lutilisateur',
deactivateUser_title: 'Désactiver lutilisateur',
delete: 'Supprimer',
deleteAttachment: 'Supprimer la pièce jointe',
deleteAvatar: "Supprimer l'avatar",
deleteBackgroundImage: 'TODO Delete background image',
deleteBoard: 'Supprimer le tableau',
deleteBoard_title: 'Supprimer le tableau',
deleteCard: 'Supprimer la carte',
deleteCardForever: 'Supprimer la carte définitivement',
deleteCard_title: 'Supprimer la carte',
deleteComment: 'Supprimer le commentaire',
deleteCustomField: 'Supprimer le champ personnalisé',
deleteCustomFieldGroup: 'Supprimer le groupe de champs personnalisés',
deleteForever_title: 'Supprimer définitivement',
deleteGroup: 'Supprimer le groupe',
deleteLabel: "Supprimer l'étiquette",
deleteList: 'Supprimer la liste',
deleteList_title: 'Supprimer la liste',
deleteNotificationService: 'Supprimer le service de notification',
deleteProject: 'Supprimer le projet',
deleteProject_title: 'Supprimer le projet',
deleteTask: 'Supprimer la tâche',
deleteTaskList: 'Supprimer la liste de tâches',
deleteTask_title: 'Supprimer la tâche',
deleteUser: "Supprimer l'utilisateur",
deleteUser_title: 'Supprimer lutilisateur',
deleteWebhook: 'Supprimer le webhook',
dismissAll: 'Tout rejeter',
duplicate: 'Dupliquer',
duplicateCard_title: 'Dupliquer la carte',
edit: 'Modifier',
@ -209,29 +399,46 @@ export default {
editDescription_title: 'Modifier la description',
editDueDate_title: "Modifier la date d'échéance",
editEmail_title: "Modifier l'e-mail",
editGroup: 'Modifier le groupe',
editInformation_title: 'Modifier les informations',
editPassword_title: 'Modifier le mot de passe',
editPermissions: 'Modifier les permissions',
editRole_title: 'Modifier le rôle',
editStopwatch_title: 'Modifier la minuterie',
editTitle_title: 'Modifier le titre',
editType_title: 'Modifier le type',
editUsername_title: "Modifier le nom d'utilisateur",
emptyTrash: 'Vider la corbeille',
emptyTrash_title: 'Vider la corbeille',
import: 'Importer',
join: 'Rejoindre',
leave: 'Quitter',
leaveBoard: 'Quitter le tableau',
leaveProject: 'Quitter le projet',
logOut_title: 'Se déconnecter',
makeCover_title: 'Faire la couverture',
makeProjectShared: "Transformer le projet en projet d'équipe",
makeProjectShared_title: "Transformer le projet en projet d'équipe",
move: 'Déplacer',
moveCard_title: 'Déplacer la carte',
remove: 'Supprimer',
removeAssignee: 'Retirer le responsable',
removeColor: 'Supprimer la couleur',
removeCover_title: 'Supprimer la couverture',
removeFromBoard: 'Supprimer du tableau',
removeFromProject: 'Supprimer du projet',
removeManager: 'Supprimer le manager',
removeManager: 'Supprimer le responsable',
removeMember: 'Supprimer le membre',
restoreToList: 'Restauré dans {{list}}',
returnToBoard: 'Retourner au tableau',
save: 'Sauvegarder',
showActive: 'Voir les actifs',
showAllAttachments: 'Afficher toutes les pièces jointes ({{hidden}} masquées)',
showCardsWithThisUser: 'Voir les cartes avec cet utilisateur',
showDeactivated: 'Voir les désactivés',
showFewerAttachments: 'Afficher moins de pièces jointes',
showLess: 'Voir moins',
showMore: 'Voir plus',
sortList_title: 'Trier la liste',
start: 'Commencer',
stop: 'Arrêter',

View file

@ -1,14 +1,18 @@
export default {
translation: {
common: {
activeUsersLimitReached: 'La limite dutilisateurs actifs a été atteinte',
emailAlreadyInUse: 'E-mail déjà utilisé',
emailOrUsername: "E-mail ou nom d'utilisateur",
invalidCredentials: 'Identifiants invalides',
invalidEmailOrUsername: "E-mail ou nom d'utilisateur invalide",
invalidPassword: 'Mot de passe invalide',
logIn_title: 'Se connecter',
noInternetConnection: 'Aucune connexion Internet',
or: 'Ou',
pageNotFound_title: 'Page non trouvée',
password: 'Mot de passe',
poweredByPlanka: 'Propulsé par <1>PLANKA</1>',
serverConnectionFailed: 'Échec de la connexion au serveur',
unknownError: 'Erreur inconnue, réessayez plus tard',
useSingleSignOn: "Utiliser l'authentification unique",

View file

@ -12,6 +12,7 @@ import elGR from './el-GR';
import enGB from './en-GB';
import enUS from './en-US';
import esES from './es-ES';
import etEE from './et-EE';
import faIR from './fa-IR';
import fiFI from './fi-FI';
import frFR from './fr-FR';
@ -45,6 +46,7 @@ const locales = [
enGB,
enUS,
esES,
etEE,
faIR,
fiFI,
frFR,

View file

@ -361,7 +361,20 @@ export default class extends BaseModel {
if (filterUserIds.length > 0) {
cardModels = cardModels.filter((cardModel) => {
const users = cardModel.users.toRefArray();
return users.some((user) => filterUserIds.includes(user.id));
if (users.some((user) => filterUserIds.includes(user.id))) {
return true;
}
return cardModel
.getTaskListsQuerySet()
.toModelArray()
.some((taskListModel) =>
taskListModel
.getTasksQuerySet()
.toRefArray()
.some((task) => task.assigneeUserId && filterUserIds.includes(task.assigneeUserId)),
);
});
}

View file

@ -280,7 +280,20 @@ export default class extends BaseModel {
if (filterUserIds.length > 0) {
cardModels = cardModels.filter((cardModel) => {
const users = cardModel.users.toRefArray();
return users.some((user) => filterUserIds.includes(user.id));
if (users.some((user) => filterUserIds.includes(user.id))) {
return true;
}
return cardModel
.getTaskListsQuerySet()
.toModelArray()
.some((taskListModel) =>
taskListModel
.getTasksQuerySet()
.toRefArray()
.some((task) => task.assigneeUserId && filterUserIds.includes(task.assigneeUserId)),
);
});
}

View file

@ -0,0 +1,88 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { attr, fk } from 'redux-orm';
import BaseModel from './BaseModel';
import ActionTypes from '../constants/ActionTypes';
export default class extends BaseModel {
static modelName = 'Webhook';
static fields = {
id: attr(),
name: attr(),
url: attr(),
accessToken: attr(),
events: attr(),
excludedEvents: attr(),
boardId: fk({
to: 'Board',
as: 'board',
relatedName: 'webhooks',
}),
};
static reducer({ type, payload }, Webhook) {
switch (type) {
case ActionTypes.SOCKET_RECONNECT_HANDLE:
Webhook.all().delete();
payload.webhooks.forEach((webhook) => {
Webhook.upsert(webhook);
});
break;
case ActionTypes.CORE_INITIALIZE:
case ActionTypes.USER_UPDATE_HANDLE:
if (payload.webhooks) {
payload.webhooks.forEach((webhook) => {
Webhook.upsert(webhook);
});
}
break;
case ActionTypes.WEBHOOK_CREATE:
case ActionTypes.WEBHOOK_CREATE_HANDLE:
case ActionTypes.WEBHOOK_UPDATE__SUCCESS:
case ActionTypes.WEBHOOK_UPDATE_HANDLE:
Webhook.upsert(payload.webhook);
break;
case ActionTypes.WEBHOOK_CREATE__SUCCESS:
Webhook.withId(payload.localId).delete();
Webhook.upsert(payload.webhook);
break;
case ActionTypes.WEBHOOK_CREATE__FAILURE:
Webhook.withId(payload.localId).delete();
break;
case ActionTypes.WEBHOOK_UPDATE:
Webhook.withId(payload.id).update(payload.data);
break;
case ActionTypes.WEBHOOK_DELETE:
Webhook.withId(payload.id).delete();
break;
case ActionTypes.WEBHOOK_DELETE__SUCCESS:
case ActionTypes.WEBHOOK_DELETE_HANDLE: {
const webhookModel = Webhook.withId(payload.webhook.id);
if (webhookModel) {
webhookModel.delete();
}
break;
}
default:
}
}
static getAllQuerySet() {
return this.orderBy(['id.length', 'id']);
}
}

View file

@ -3,6 +3,7 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import Webhook from './Webhook';
import User from './User';
import Project from './Project';
import ProjectManager from './ProjectManager';
@ -25,6 +26,7 @@ import Notification from './Notification';
import NotificationService from './NotificationService';
export {
Webhook,
User,
Project,
ProjectManager,

View file

@ -26,6 +26,7 @@ import {
Task,
TaskList,
User,
Webhook,
} from './models';
const orm = new ORM({
@ -33,6 +34,7 @@ const orm = new ORM({
});
orm.register(
Webhook,
User,
Project,
ProjectManager,

View file

@ -10,6 +10,7 @@ import request from '../request';
import api from '../../../api';
import mergeRecords from '../../../utils/merge-records';
import { isUserAdminOrProjectOwner } from '../../../utils/record-helpers';
import { UserRoles } from '../../../constants/Enums';
export function* fetchCore() {
const {
@ -17,6 +18,11 @@ export function* fetchCore() {
included: { notificationServices: notificationServices1 },
} = yield call(request, api.getCurrentUser, true);
let webhooks;
if (user.role === UserRoles.ADMIN) {
({ items: webhooks } = yield call(request, api.getWebhooks));
}
let users1;
if (isUserAdminOrProjectOwner(user)) {
({ items: users1 } = yield call(request, api.getUsers));
@ -101,6 +107,7 @@ export function* fetchCore() {
return {
user,
board,
webhooks,
projectManagers,
backgroundImages,
baseCustomFieldGroups,

View file

@ -21,6 +21,7 @@ export function* initializeCore() {
const {
user,
board,
webhooks,
users,
projects,
projectManagers,
@ -50,6 +51,7 @@ export function* initializeCore() {
actions.initializeCore(
user,
board,
webhooks,
users,
projects,
projectManagers,

View file

@ -7,6 +7,7 @@ import router from './router';
import socket from './socket';
import core from './core';
import modals from './modals';
import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@ -33,6 +34,7 @@ export default {
...socket,
...core,
...modals,
...webhooks,
...users,
...projects,
...projectManagers,

View file

@ -24,6 +24,7 @@ export function* handleSocketReconnect() {
let config;
let user;
let board;
let webhooks;
let users;
let projects;
let projectManagers;
@ -51,6 +52,7 @@ export function* handleSocketReconnect() {
({
user,
board,
webhooks,
users,
projects,
projectManagers,
@ -81,6 +83,7 @@ export function* handleSocketReconnect() {
config,
user,
board,
webhooks,
users,
projects,
projectManagers,

View file

@ -70,6 +70,7 @@ export function* handleUserUpdate(user) {
let config;
let board;
let webhooks;
let users1;
let users2;
let users3;
@ -102,6 +103,7 @@ export function* handleUserUpdate(user) {
if (user.role === UserRoles.ADMIN) {
({ item: config } = yield call(request, api.getConfig));
({ items: webhooks } = yield call(request, api.getWebhooks));
({
items: projects,
@ -164,6 +166,7 @@ export function* handleUserUpdate(user) {
boardIds,
config,
board,
webhooks,
mergeRecords(users1, users2, users3),
projects,
projectManagers,

View file

@ -0,0 +1,89 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { call, put } from 'redux-saga/effects';
import request from '../request';
import actions from '../../../actions';
import api from '../../../api';
import { createLocalId } from '../../../utils/local-id';
export function* createWebhook(data) {
const localId = yield call(createLocalId);
yield put(
actions.createWebhook({
...data,
id: localId,
}),
);
let webhook;
try {
({ item: webhook } = yield call(request, api.createWebhook, {
...data,
events: data.events && data.events.join(','),
excludedEvents: data.excludedEvents && data.excludedEvents.join(','),
}));
} catch (error) {
yield put(actions.createWebhook.failure(localId, error));
return;
}
yield put(actions.createWebhook.success(localId, webhook));
}
export function* handleWebhookCreate(webhook) {
yield put(actions.handleWebhookCreate(webhook));
}
export function* updateWebhook(id, data) {
yield put(actions.updateWebhook(id, data));
let webhook;
try {
({ item: webhook } = yield call(request, api.updateWebhook, id, {
...data,
events: data.events && data.events.join(','),
excludedEvents: data.excludedEvents && data.excludedEvents.join(','),
}));
} catch (error) {
yield put(actions.updateWebhook.failure(id, error));
return;
}
yield put(actions.updateWebhook.success(webhook));
}
export function* handleWebhookUpdate(webhook) {
yield put(actions.handleWebhookUpdate(webhook));
}
export function* deleteWebhook(id) {
yield put(actions.deleteWebhook(id));
let webhook;
try {
({ item: webhook } = yield call(request, api.deleteWebhook, id));
} catch (error) {
yield put(actions.deleteWebhook.failure(id, error));
return;
}
yield put(actions.deleteWebhook.success(webhook));
}
export function* handleWebhookDelete(webhook) {
yield put(actions.handleWebhookDelete(webhook));
}
export default {
createWebhook,
handleWebhookCreate,
updateWebhook,
handleWebhookUpdate,
deleteWebhook,
handleWebhookDelete,
};

View file

@ -7,6 +7,7 @@ import router from './router';
import socket from './socket';
import core from './core';
import modals from './modals';
import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@ -33,6 +34,7 @@ export default [
socket,
core,
modals,
webhooks,
users,
projects,
projectManagers,

View file

@ -0,0 +1,30 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { all, takeEvery } from 'redux-saga/effects';
import services from '../services';
import EntryActionTypes from '../../../constants/EntryActionTypes';
export default function* webhooksWatchers() {
yield all([
takeEvery(EntryActionTypes.WEBHOOK_CREATE, ({ payload: { data } }) =>
services.createWebhook(data),
),
takeEvery(EntryActionTypes.WEBHOOK_CREATE_HANDLE, ({ payload: { webhook } }) =>
services.handleWebhookCreate(webhook),
),
takeEvery(EntryActionTypes.WEBHOOK_UPDATE, ({ payload: { id, data } }) =>
services.updateWebhook(id, data),
),
takeEvery(EntryActionTypes.WEBHOOK_UPDATE_HANDLE, ({ payload: { webhook } }) =>
services.handleWebhookUpdate(webhook),
),
takeEvery(EntryActionTypes.WEBHOOK_DELETE, ({ payload: { id } }) => services.deleteWebhook(id)),
takeEvery(EntryActionTypes.WEBHOOK_DELETE_HANDLE, ({ payload: { webhook } }) =>
services.handleWebhookDelete(webhook),
),
]);
}

View file

@ -8,6 +8,7 @@ import common from './common';
import core from './core';
import modals from './modals';
import positioning from './positioning';
import webhooks from './webhooks';
import users from './users';
import projects from './projects';
import projectManagers from './project-managers';
@ -35,6 +36,7 @@ export default {
...core,
...modals,
...positioning,
...webhooks,
...users,
...projects,
...projectManagers,

View file

@ -0,0 +1,41 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import { createSelector } from 'redux-orm';
import orm from '../orm';
import { isLocalId } from '../utils/local-id';
export const makeSelectWebhookById = () =>
createSelector(
orm,
(_, id) => id,
({ Webhook }, id) => {
const webhookModel = Webhook.withId(id);
if (!webhookModel) {
return webhookModel;
}
return {
...webhookModel.ref,
isPersisted: !isLocalId(webhookModel.id),
};
},
);
export const selectWebhookById = makeSelectWebhookById();
export const selectWebhookIds = createSelector(orm, ({ Webhook }) =>
Webhook.getAllQuerySet()
.toRefArray()
.map((webhook) => webhook.id),
);
export default {
makeSelectWebhookById,
selectWebhookById,
selectWebhookIds,
};

View file

@ -60,6 +60,8 @@ services:
# - OIDC_RESPONSE_MODE=fragment
# - OIDC_USE_DEFAULT_RESPONSE_MODE=true
# - OIDC_ADMIN_ROLES=admin
# - OIDC_PROJECT_OWNER_ROLES=project_owner
# - OIDC_BOARD_USER_ROLES=board_user
# - OIDC_CLAIMS_SOURCE=userinfo
# - OIDC_EMAIL_ATTRIBUTE=email
# - OIDC_NAME_ATTRIBUTE=name
@ -78,15 +80,6 @@ services:
# - SMTP_PASSWORD=
# - SMTP_FROM="Demo Demo" <demo@demo.demo>
# - SMTP_TLS_REJECT_UNAUTHORIZED=false
# Optional fields: accessToken, events, excludedEvents
# - |
# WEBHOOKS=[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]
depends_on:
postgres:
condition: service_healthy

View file

@ -78,6 +78,8 @@ services:
# - OIDC_RESPONSE_MODE=fragment
# - OIDC_USE_DEFAULT_RESPONSE_MODE=true
# - OIDC_ADMIN_ROLES=admin
# - OIDC_PROJECT_OWNER_ROLES=project_owner
# - OIDC_BOARD_USER_ROLES=board_user
# - OIDC_CLAIMS_SOURCE=userinfo
# - OIDC_EMAIL_ATTRIBUTE=email
# - OIDC_NAME_ATTRIBUTE=name
@ -98,15 +100,6 @@ services:
# - SMTP_PASSWORD__FILE=/run/secrets/smtp_password
# - SMTP_FROM="Demo Demo" <demo@demo.demo>
# - SMTP_TLS_REJECT_UNAUTHORIZED=false
# Optional fields: accessToken, events, excludedEvents
# - |
# WEBHOOKS=[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]
depends_on:
postgres:
condition: service_healthy

154
package-lock.json generated
View file

@ -16,9 +16,10 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.27.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz",
"integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==",
"version": "7.27.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@ -27,6 +28,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
"integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
"license": "MIT",
"dependencies": {
"environment": "^1.0.0"
},
@ -41,6 +43,7 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -52,6 +55,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@ -65,17 +69,20 @@
"node_modules/async": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"license": "MIT"
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -85,6 +92,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
@ -96,6 +104,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@ -111,6 +120,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@ -122,6 +132,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"license": "MIT",
"dependencies": {
"restore-cursor": "^5.0.0"
},
@ -136,6 +147,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
"integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
"license": "MIT",
"dependencies": {
"slice-ansi": "^5.0.0",
"string-width": "^7.0.0"
@ -151,6 +163,7 @@
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@ -164,6 +177,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -171,12 +185,14 @@
"node_modules/cliui/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/cliui/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -185,6 +201,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -198,6 +215,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@ -209,6 +227,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@ -225,6 +244,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@ -235,17 +255,20 @@
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/colorette": {
"version": "2.0.20",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"license": "MIT"
},
"node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"license": "MIT",
"engines": {
"node": ">= 10"
}
@ -253,12 +276,14 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/concurrently": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz",
"integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==",
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"date-fns": "^2.30.0",
@ -285,6 +310,7 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@ -298,6 +324,7 @@
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.21.0"
},
@ -313,6 +340,7 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
@ -329,6 +357,7 @@
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"license": "Apache-2.0",
"dependencies": {
"jake": "^10.8.5"
},
@ -342,12 +371,14 @@
"node_modules/emoji-regex": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
"license": "MIT"
},
"node_modules/environment": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
"integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
"license": "MIT",
"engines": {
"node": ">=18"
},
@ -359,6 +390,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
@ -366,12 +398,14 @@
"node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
"license": "MIT"
},
"node_modules/execa": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^8.0.1",
@ -394,14 +428,16 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"license": "Apache-2.0",
"dependencies": {
"minimatch": "^5.0.1"
}
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@ -410,6 +446,7 @@
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@ -421,6 +458,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -432,6 +470,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/find-package/-/find-package-1.0.0.tgz",
"integrity": "sha512-yVn71XCCaNgxz58ERTl8nA/8YYtIQDY9mHSrgFBfiFtdNNfY0h183Vh8BRkKxD8x9TUw3ec290uJKhDVxqGZBw==",
"license": "MIT",
"dependencies": {
"parents": "^1.0.1"
}
@ -440,6 +479,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/genversion/-/genversion-3.2.0.tgz",
"integrity": "sha512-OIYSX6XYA8PHecLDCTri30hadSZfAjZ8Iq1+BBDXqLWP4dRLuJNLoNjsSWtTpw97IccK2LDWzkEstxAB8GdN7g==",
"license": "MIT",
"dependencies": {
"commander": "^7.2.0",
"ejs": "^3.1.9",
@ -456,6 +496,7 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@ -464,6 +505,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
"integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
@ -475,6 +517,7 @@
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"license": "MIT",
"engines": {
"node": ">=16"
},
@ -486,6 +529,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -494,6 +538,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=16.17.0"
}
@ -502,6 +547,7 @@
"version": "9.1.7",
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
"license": "MIT",
"bin": {
"husky": "bin.js"
},
@ -516,6 +562,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -527,6 +574,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@ -535,6 +583,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@ -545,12 +594,14 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jake": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
"integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
"license": "Apache-2.0",
"dependencies": {
"async": "^3.2.3",
"chalk": "^4.0.2",
@ -568,6 +619,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"license": "MIT",
"engines": {
"node": ">=14"
},
@ -579,6 +631,7 @@
"version": "15.5.2",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz",
"integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==",
"license": "MIT",
"dependencies": {
"chalk": "^5.4.1",
"commander": "^13.1.0",
@ -605,6 +658,7 @@
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
@ -616,6 +670,7 @@
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"license": "MIT",
"engines": {
"node": ">=18"
}
@ -624,6 +679,7 @@
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz",
"integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==",
"license": "MIT",
"dependencies": {
"cli-truncate": "^4.0.0",
"colorette": "^2.0.20",
@ -639,12 +695,14 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/log-update": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
"integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
"license": "MIT",
"dependencies": {
"ansi-escapes": "^7.0.0",
"cli-cursor": "^5.0.0",
@ -663,6 +721,7 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -674,6 +733,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
"integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
"license": "MIT",
"dependencies": {
"get-east-asian-width": "^1.0.0"
},
@ -688,6 +748,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
"integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"is-fullwidth-code-point": "^5.0.0"
@ -702,12 +763,14 @@
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"license": "MIT"
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@ -720,6 +783,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -731,6 +795,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
"license": "MIT",
"engines": {
"node": ">=18"
},
@ -742,6 +807,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -752,12 +818,14 @@
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/npm-run-path": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"license": "MIT",
"dependencies": {
"path-key": "^4.0.0"
},
@ -772,6 +840,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -783,6 +852,7 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"license": "MIT",
"dependencies": {
"mimic-fn": "^4.0.0"
},
@ -797,6 +867,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
"integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==",
"license": "MIT",
"dependencies": {
"path-platform": "~0.11.15"
}
@ -805,6 +876,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -813,6 +885,7 @@
"version": "0.11.15",
"resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
"integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==",
"license": "MIT",
"engines": {
"node": ">= 0.8.0"
}
@ -821,6 +894,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
@ -832,6 +906,7 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
"license": "MIT",
"bin": {
"pidtree": "bin/pidtree.js"
},
@ -843,6 +918,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@ -851,6 +927,7 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"license": "MIT",
"dependencies": {
"onetime": "^7.0.0",
"signal-exit": "^4.1.0"
@ -866,6 +943,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"license": "MIT",
"dependencies": {
"mimic-function": "^5.0.0"
},
@ -879,12 +957,14 @@
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"license": "MIT"
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
@ -893,6 +973,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
@ -904,6 +985,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -912,6 +994,7 @@
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
@ -923,6 +1006,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"license": "ISC",
"engines": {
"node": ">=14"
},
@ -934,6 +1018,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
"integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.0.0",
"is-fullwidth-code-point": "^4.0.0"
@ -949,6 +1034,7 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -965,6 +1051,7 @@
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"license": "MIT",
"engines": {
"node": ">=0.6.19"
}
@ -973,6 +1060,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
@ -989,6 +1077,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
},
@ -1003,6 +1092,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -1014,6 +1104,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@ -1028,6 +1119,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@ -1039,6 +1131,7 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"license": "MIT",
"bin": {
"tree-kill": "cli.js"
}
@ -1046,12 +1139,14 @@
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
@ -1066,6 +1161,7 @@
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
"integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"string-width": "^7.0.0",
@ -1082,6 +1178,7 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
},
@ -1093,6 +1190,7 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"license": "ISC",
"engines": {
"node": ">=10"
}
@ -1101,6 +1199,7 @@
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
@ -1112,6 +1211,7 @@
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"license": "MIT",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@ -1129,6 +1229,7 @@
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"license": "ISC",
"engines": {
"node": ">=12"
}
@ -1137,6 +1238,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -1144,12 +1246,14 @@
"node_modules/yargs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/yargs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@ -1158,6 +1262,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -1171,6 +1276,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},

View file

@ -72,14 +72,6 @@ SECRET_KEY=notsecretkey
# SMTP_FROM="Demo Demo" <demo@demo.demo>
# SMTP_TLS_REJECT_UNAUTHORIZED=false
# Optional fields: accessToken, events, excludedEvents
# WEBHOOKS='[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]'
## Do not edit this
TZ=UTC

View file

@ -0,0 +1,76 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const { isUrl } = require('../../../utils/validators');
const Errors = {
LIMIT_REACHED: {
limitReached: 'Limit reached',
},
};
module.exports = {
inputs: {
name: {
type: 'string',
maxLength: 128,
required: true,
},
url: {
type: 'string',
maxLength: 2048,
custom: isUrl,
required: true,
},
accessToken: {
type: 'string',
isNotEmptyString: true,
maxLength: 512,
allowNull: true,
},
events: {
type: 'string',
isNotEmptyString: true,
maxLength: 2048,
allowNull: true,
},
excludedEvents: {
type: 'string',
isNotEmptyString: true,
maxLength: 2048,
allowNull: true,
},
},
exits: {
limitReached: {
responseType: 'conflict',
},
},
async fn(inputs) {
const { currentUser } = this.req;
const values = _.pick(inputs, ['name', 'url', 'accessToken']);
const events = inputs.events && inputs.events.split(',');
const excludedEvents = inputs.excludedEvents && inputs.excludedEvents.split(',');
const webhook = await sails.helpers.webhooks.createOne
.with({
values: {
...values,
events,
excludedEvents,
},
actorUser: currentUser,
request: this.req,
})
.intercept('limitReached', () => Errors.LIMIT_REACHED);
return {
item: webhook,
};
},
};

View file

@ -0,0 +1,51 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const { idInput } = require('../../../utils/inputs');
const Errors = {
WEBHOOK_NOT_FOUND: {
webhookNotFound: 'Webhook not found',
},
};
module.exports = {
inputs: {
id: {
...idInput,
required: true,
},
},
exits: {
webhookNotFound: {
responseType: 'notFound',
},
},
async fn(inputs) {
const { currentUser } = this.req;
let webhook = await Webhook.qm.getOneById(inputs.id);
if (!webhook) {
throw Errors.WEBHOOK_NOT_FOUND;
}
webhook = await sails.helpers.webhooks.deleteOne.with({
record: webhook,
actorUser: currentUser,
request: this.req,
});
if (!webhook) {
throw Errors.WEBHOOK_NOT_FOUND;
}
return {
item: webhook,
};
},
};

View file

@ -0,0 +1,14 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
module.exports = {
async fn() {
const webhooks = await Webhook.qm.getAll();
return {
items: webhooks,
};
},
};

View file

@ -0,0 +1,89 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const { isUrl } = require('../../../utils/validators');
const { idInput } = require('../../../utils/inputs');
const Errors = {
WEBHOOK_NOT_FOUND: {
webhookNotFound: 'Webhook not found',
},
};
module.exports = {
inputs: {
id: {
...idInput,
required: true,
},
name: {
type: 'string',
isNotEmptyString: true,
maxLength: 128,
},
url: {
type: 'string',
maxLength: 2048,
custom: isUrl,
},
accessToken: {
type: 'string',
isNotEmptyString: true,
maxLength: 512,
allowNull: true,
},
events: {
type: 'string',
isNotEmptyString: true,
maxLength: 2048,
allowNull: true,
},
excludedEvents: {
type: 'string',
isNotEmptyString: true,
maxLength: 2048,
allowNull: true,
},
},
exits: {
webhookNotFound: {
responseType: 'notFound',
},
},
async fn(inputs) {
const { currentUser } = this.req;
let webhook = await Webhook.qm.getOneById(inputs.id);
if (!webhook) {
throw Errors.WEBHOOK_NOT_FOUND;
}
const values = _.pick(inputs, ['name', 'url', 'accessToken']);
const events = inputs.events && inputs.events.split(',');
const excludedEvents = inputs.excludedEvents && inputs.excludedEvents.split(',');
webhook = await sails.helpers.webhooks.updateOne.with({
record: webhook,
values: {
...values,
events,
excludedEvents,
},
actorUser: currentUser,
request: this.req,
});
if (!webhook) {
throw Errors.WEBHOOK_NOT_FOUND;
}
return {
item: webhook,
};
},
};

View file

@ -105,6 +105,10 @@ module.exports = {
type: 'ref',
required: true,
},
webhooks: {
type: 'ref',
required: true,
},
request: {
type: 'ref',
},
@ -130,7 +134,8 @@ module.exports = {
);
sails.helpers.utils.sendWebhooks.with({
event: 'actionCreate',
webhooks: inputs.webhooks,
event: Webhook.Events.ACTION_CREATE,
buildData: () => ({
item: action,
included: {
@ -158,6 +163,7 @@ module.exports = {
project: inputs.project,
board: inputs.board,
list: inputs.list,
webhooks: inputs.webhooks,
});
}
} else {
@ -187,6 +193,7 @@ module.exports = {
project: inputs.project,
board: inputs.board,
list: inputs.list,
webhooks: inputs.webhooks,
}),
),
);

View file

@ -48,8 +48,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'attachmentCreate',
webhooks,
event: Webhook.Events.ATTACHMENT_CREATE,
buildData: () => ({
item: sails.helpers.attachments.presentOne(attachment),
included: {
@ -65,6 +68,7 @@ module.exports = {
if (!values.card.coverAttachmentId) {
if (attachment.type === Attachment.Types.FILE && attachment.data.image) {
await sails.helpers.cards.updateOne.with({
webhooks,
record: values.card,
values: {
coverAttachmentId: attachment.id,

View file

@ -37,6 +37,7 @@ module.exports = {
async fn(inputs) {
if (inputs.record.id === inputs.card.coverAttachmentId) {
await sails.helpers.cards.updateOne.with({
webhooks,
record: inputs.card,
values: {
coverAttachmentId: null,
@ -66,8 +67,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'attachmentDelete',
webhooks,
event: Webhook.Events.ATTACHMENT_DELETE,
buildData: () => ({
item: sails.helpers.attachments.presentOne(attachment),
included: {

View file

@ -53,8 +53,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'attachmentUpdate',
webhooks,
event: Webhook.Events.ATTACHMENT_UPDATE,
buildData: () => ({
item: sails.helpers.attachments.presentOne(attachment),
included: {

View file

@ -47,8 +47,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'backgroundImageCreate',
webhooks,
event: Webhook.Events.BACKGROUND_IMAGE_CREATE,
buildData: () => ({
item: sails.helpers.backgroundImages.presentOne(backgroundImage),
included: {
@ -60,6 +63,7 @@ module.exports = {
await sails.helpers.projects.updateOne.with({
scoper,
webhooks,
record: values.project,
values: {
backgroundImage,

View file

@ -31,6 +31,7 @@ module.exports = {
if (inputs.record.id === inputs.project.backgroundImageId) {
await sails.helpers.projects.updateOne.with({
scoper,
webhooks,
record: inputs.project,
values: {
backgroundType: null,
@ -58,8 +59,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'backgroundImageDelete',
webhooks,
event: Webhook.Events.BACKGROUND_IMAGE_DELETE,
buildData: () => ({
item: sails.helpers.backgroundImages.presentOne(backgroundImage),
included: {

View file

@ -43,8 +43,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'baseCustomFieldGroupCreate',
webhooks,
event: Webhook.Events.BASE_CUSTOM_FIELD_GROUP_CREATE,
buildData: () => ({
item: baseCustomFieldGroup,
included: {

View file

@ -45,8 +45,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'baseCustomFieldGroupDelete',
webhooks,
event: Webhook.Events.BASE_CUSTOM_FIELD_GROUP_DELETE,
buildData: () => ({
item: baseCustomFieldGroup,
included: {

View file

@ -49,8 +49,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'baseCustomFieldGroupUpdate',
webhooks,
event: Webhook.Events.BASE_CUSTOM_FIELD_GROUP_UPDATE,
buildData: () => ({
item: baseCustomFieldGroup,
included: {

View file

@ -86,8 +86,11 @@ module.exports = {
});
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'boardMembershipCreate',
webhooks,
event: Webhook.Events.BOARD_MEMBERSHIP_CREATE,
buildData: () => ({
item: boardMembership,
included: {

View file

@ -106,8 +106,11 @@ module.exports = {
});
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'boardMembershipDelete',
webhooks,
event: Webhook.Events.BOARD_MEMBERSHIP_DELETE,
buildData: () => ({
item: boardMembership,
included: {

View file

@ -75,8 +75,11 @@ module.exports = {
});
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'boardMembershipUpdate',
webhooks,
event: Webhook.Events.BOARD_MEMBERSHIP_UPDATE,
buildData: () => ({
item: boardMembership,
included: {

View file

@ -108,8 +108,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'boardCreate',
webhooks,
event: Webhook.Events.BOARD_CREATE,
buildData: () => ({
item: board,
included: {

View file

@ -49,8 +49,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'boardDelete',
webhooks,
event: Webhook.Events.BOARD_DELETE,
buildData: () => ({
item: board,
included: {

View file

@ -104,8 +104,11 @@ module.exports = {
);
});
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'boardUpdate',
webhooks,
event: Webhook.Events.BOARD_UPDATE,
buildData: () => ({
item: board,
included: {

View file

@ -61,8 +61,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardLabelCreate',
webhooks,
event: Webhook.Events.CARD_LABEL_CREATE,
buildData: () => ({
item: cardLabel,
included: {

View file

@ -47,8 +47,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardLabelDelete',
webhooks,
event: Webhook.Events.CARD_LABEL_DELETE,
buildData: () => ({
item: cardLabel,
included: {

View file

@ -61,8 +61,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardMembershipCreate',
webhooks,
event: Webhook.Events.CARD_MEMBERSHIP_CREATE,
buildData: () => ({
item: cardMembership,
included: {
@ -106,6 +109,7 @@ module.exports = {
}
await sails.helpers.actions.createOne.with({
webhooks,
values: {
type: Action.Types.ADD_MEMBER_TO_CARD,
data: {

View file

@ -51,8 +51,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardMembershipDelete',
webhooks,
event: Webhook.Events.CARD_MEMBERSHIP_DELETE,
buildData: () => ({
item: cardMembership,
included: {
@ -82,6 +85,7 @@ module.exports = {
}
await sails.helpers.actions.createOne.with({
webhooks,
values: {
type: Action.Types.REMOVE_MEMBER_FROM_CARD,
data: {

View file

@ -84,8 +84,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardCreate',
webhooks,
event: Webhook.Events.CARD_CREATE,
buildData: () => ({
item: card,
included: {
@ -120,6 +123,7 @@ module.exports = {
}
await sails.helpers.actions.createOne.with({
webhooks,
values: {
card,
type: Action.Types.CREATE_CARD,

View file

@ -45,8 +45,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardDelete',
webhooks,
event: Webhook.Events.CARD_DELETE,
buildData: () => ({
item: card,
included: {

View file

@ -228,8 +228,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'cardCreate',
webhooks,
event: Webhook.Events.CARD_CREATE,
buildData: () => ({
item: card,
included: {
@ -272,6 +275,7 @@ module.exports = {
}
await sails.helpers.actions.createOne.with({
webhooks,
values: {
card,
type: Action.Types.CREATE_CARD, // TODO: introduce separate type?

View file

@ -31,6 +31,8 @@ module.exports = {
},
);
const webhooks = await Webhook.qm.getAll();
notifications.forEach((notification) => {
sails.sockets.broadcast(
`user:${notification.userId}`,
@ -43,7 +45,8 @@ module.exports = {
// TODO: with prevData?
sails.helpers.utils.sendWebhooks.with({
event: 'notificationUpdate',
webhooks,
event: Webhook.Events.NOTIFICATION_UPDATE,
buildData: () => ({
item: notification,
}),

View file

@ -31,6 +31,9 @@ module.exports = {
type: 'ref',
required: true,
},
webhooks: {
type: 'ref',
},
request: {
type: 'ref',
},
@ -104,6 +107,8 @@ module.exports = {
if (_.isEmpty(values)) {
card = inputs.record;
} else {
const { webhooks = await Webhook.qm.getAll() } = inputs;
if (!_.isNil(values.position)) {
const cards = await Card.qm.getByListId(list.id, {
exceptIdOrIds: inputs.record.id,
@ -402,6 +407,7 @@ module.exports = {
const { id } = await sails.helpers.labels.createOne.with({
project,
webhooks,
values: {
..._.omit(label, ['id', 'boardId', 'createdAt', 'updatedAt']),
board,
@ -459,6 +465,7 @@ module.exports = {
if (values.list) {
await sails.helpers.actions.createOne.with({
webhooks,
values: {
card,
type: Action.Types.MOVE_CARD,
@ -477,7 +484,8 @@ module.exports = {
}
sails.helpers.utils.sendWebhooks.with({
event: 'cardUpdate',
webhooks,
event: Webhook.Events.CARD_UPDATE,
buildData: () => ({
item: card,
included: {

View file

@ -79,8 +79,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'commentCreate',
webhooks,
event: Webhook.Events.COMMENT_CREATE,
buildData: () => ({
item: comment,
included: {
@ -125,6 +128,7 @@ module.exports = {
await Promise.all(
notifiableUserIds.map((userId) =>
sails.helpers.notifications.createOne.with({
webhooks,
values: {
userId,
comment,

View file

@ -47,8 +47,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'commentDelete',
webhooks,
event: Webhook.Events.COMMENT_DELETE,
buildData: () => ({
item: comment,
included: {

View file

@ -53,8 +53,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'commentUpdate',
webhooks,
event: Webhook.Events.COMMENT_UPDATE,
buildData: () => ({
item: comment,
included: {

View file

@ -87,8 +87,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'customFieldGroupCreate',
webhooks,
event: Webhook.Events.CUSTOM_FIELD_GROUP_CREATE,
buildData: () => ({
item: customFieldGroup,
included: {

View file

@ -95,8 +95,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'customFieldGroupCreate',
webhooks,
event: Webhook.Events.CUSTOM_FIELD_GROUP_CREATE,
buildData: () => ({
item: customFieldGroup,
included: {

View file

@ -41,8 +41,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'customFieldGroupDelete',
webhooks,
event: Webhook.Events.CUSTOM_FIELD_GROUP_DELETE,
buildData: () => ({
item: customFieldGroup,
included: {

View file

@ -49,8 +49,11 @@ module.exports = {
inputs.request,
);
const webhooks = await Webhook.qm.getAll();
sails.helpers.utils.sendWebhooks.with({
event: 'customFieldGroupDelete',
webhooks,
event: Webhook.Events.CUSTOM_FIELD_GROUP_DELETE,
buildData: () => ({
item: customFieldGroup,
included: {

Some files were not shown because too many files have changed in this diff Show more