Compare commits

...

8 Commits

Author SHA1 Message Date
Maksim Eltyshev
fe8f7d172b chore: Update version 2025-03-01 22:10:49 +01:00
Nikhil Taneja
142f35d8a2 fix: Configurable database schema name (#1046) 2025-03-01 22:03:15 +01:00
Maksim Eltyshev
b88a2894b6 build: Pin pnpm version 2025-02-26 17:14:41 +01:00
Lukas Corona
2732570607 feat: Ability to set list color indicator (#1033)
Closes #840
2025-02-25 15:58:59 +01:00
dependabot[bot]
b0e9ed6162 chore(deps): Bump path-to-regexp and express in /client (#1013)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `path-to-regexp` from 0.1.10 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12)

Updates `express` from 4.21.1 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-13 16:20:25 +01:00
dependabot[bot]
8b99e38615 chore(deps): Bump path-to-regexp and sails in /server (#1012)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 1.9.0 and updates ancestor dependency [sails](https://github.com/balderdashy/sails). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.11 to 1.9.0
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.11...v1.9.0)

Updates `sails` from 1.5.13 to 1.5.14
- [Release notes](https://github.com/balderdashy/sails/releases)
- [Changelog](https://github.com/balderdashy/sails/blob/master/CHANGELOG.md)
- [Commits](https://github.com/balderdashy/sails/compare/v1.5.13...v1.5.14)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: sails
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-13 16:20:13 +01:00
dependabot[bot]
3bc6991002 chore(deps): Bump nanoid in /client (#1011)
Bumps  and [nanoid](https://github.com/ai/nanoid). These dependencies needed to be updated together.

Updates `nanoid` from 5.0.8 to 5.0.9
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.0.8...5.0.9)

Updates `nanoid` from 3.3.7 to 5.0.9
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.0.8...5.0.9)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: direct:production
- dependency-name: nanoid
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-13 16:20:04 +01:00
Marc-Andrieu
ff689b6273 fix: Update French translation (#1030) 2025-02-13 16:03:11 +01:00
34 changed files with 478 additions and 252 deletions

View File

@@ -16,7 +16,7 @@ jobs:
cache: 'npm'
- name: Workflow install pnpm
run: npm install pnpm -g
run: npm install pnpm@9 -g
- name: Client install dependencies
run: pnpm install

View File

@@ -1,15 +1,14 @@
FROM node:18-alpine AS server-dependencies
RUN apk -U upgrade \
&& apk add build-base python3 \
--no-cache
&& apk add build-base python3 --no-cache
WORKDIR /app
COPY server/package.json server/package-lock.json ./
RUN npm install npm --global \
&& npm install pnpm --global \
&& npm install pnpm@9 --global \
&& pnpm import \
&& pnpm install --prod
@@ -17,28 +16,26 @@ FROM node:lts AS client
WORKDIR /app
COPY client/package.json client/package-lock.json ./
COPY client .
RUN npm install npm --global \
&& npm install pnpm --global \
&& npm install pnpm@9 --global \
&& pnpm import \
&& pnpm install --prod
COPY client .
RUN DISABLE_ESLINT_PLUGIN=true npm run build
FROM node:18-alpine
RUN apk -U upgrade \
&& apk add bash \
--no-cache
&& apk add bash --no-cache
USER node
WORKDIR /app
COPY --chown=node:node start.sh .
COPY --chown=node:node server .
COPY --chown=node:node healthcheck.js .
COPY --chown=node:node server .
RUN mv .env.sample .env
@@ -56,5 +53,4 @@ EXPOSE 1337
HEALTHCHECK --interval=10s --timeout=2s --start-period=15s \
CMD node ./healthcheck.js
CMD [ "bash", "start.sh" ]
CMD ["./start.sh"]

View File

@@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.2.20
version: 0.2.21
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.24.4"
appVersion: "1.25.0"
dependencies:
- alias: postgresql

View File

@@ -20,7 +20,7 @@
"linkify-react": "^4.1.4",
"linkifyjs": "^4.1.4",
"lodash": "^4.17.21",
"nanoid": "^5.0.8",
"nanoid": "^5.0.9",
"node-sass": "^9.0.0",
"photoswipe": "^5.4.4",
"prop-types": "^15.8.1",
@@ -8875,9 +8875,10 @@
}
},
"node_modules/express": {
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -8898,7 +8899,7 @@
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.10",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
@@ -8913,6 +8914,10 @@
},
"engines": {
"node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/express/node_modules/debug": {
@@ -13927,15 +13932,16 @@
"integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw=="
},
"node_modules/nanoid": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz",
"integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==",
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
"integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.js"
},
@@ -14772,9 +14778,10 @@
}
},
"node_modules/path-to-regexp": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
"node_modules/path-type": {
"version": "4.0.0",

2
client/package.json Executable file → Normal file
View File

@@ -74,7 +74,7 @@
"linkify-react": "^4.1.4",
"linkifyjs": "^4.1.4",
"lodash": "^4.17.21",
"nanoid": "^5.0.8",
"nanoid": "^5.0.9",
"node-sass": "^9.0.0",
"photoswipe": "^5.4.4",
"prop-types": "^15.8.1",

View File

@@ -0,0 +1,52 @@
import classNames from 'classnames';
import camelCase from 'lodash/camelCase';
import upperFirst from 'lodash/upperFirst';
import PropTypes from 'prop-types';
import React from 'react';
import { Button } from 'semantic-ui-react';
import { useTranslation } from 'react-i18next';
import globalStyles from '../../styles.module.scss';
import styles from './ColorPicker.module.scss';
const ColorPicker = React.memo(({ current, onChange, colors, allowDeletion }) => {
const { t } = useTranslation();
return (
<>
<div className={styles.colorButtons}>
{colors.map((color) => (
<Button
key={color}
type="button"
name="color"
value={color}
className={classNames(
styles.colorButton,
color === current && styles.colorButtonActive,
globalStyles[`background${upperFirst(camelCase(color))}`],
)}
onClick={onChange}
/>
))}
</div>
{current && allowDeletion && (
<Button fluid value={undefined} onClick={onChange} content={t('action.removeColor')} />
)}
</>
);
});
ColorPicker.propTypes = {
current: PropTypes.string,
colors: PropTypes.arrayOf(PropTypes.string).isRequired,
onChange: PropTypes.func,
allowDeletion: PropTypes.bool,
};
ColorPicker.defaultProps = {
current: undefined,
onChange: undefined,
allowDeletion: false,
};
export default ColorPicker;

View File

@@ -0,0 +1,40 @@
:global(#app) {
.colorButton {
float: left;
height: 40px;
margin: 4px;
padding: 0;
position: relative;
width: 49.6px;
&:hover {
opacity: 0.9;
}
}
.colorButtonActive:before {
bottom: 3px;
color: #ffffff;
content: 'Г';
font-size: 18px;
line-height: 36px;
position: absolute;
right: 6px;
text-align: center;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
top: 0;
transform: rotate(-135deg);
width: 36px;
}
.colorButtons {
margin: -4px;
padding-bottom: 16px;
&:after {
content: '';
display: table;
clear: both;
}
}
}

View File

@@ -0,0 +1,3 @@
import ColorPicker from './ColorPicker';
export default ColorPicker;

View File

@@ -1,16 +1,12 @@
import upperFirst from 'lodash/upperFirst';
import camelCase from 'lodash/camelCase';
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { Button } from 'semantic-ui-react';
import { Input } from '../../lib/custom-ui';
import LabelColors from '../../constants/LabelColors';
import ColorPicker from '../ColorPicker';
import styles from './Editor.module.scss';
import globalStyles from '../../styles.module.scss';
const Editor = React.memo(({ data, onFieldChange }) => {
const [t] = useTranslation();
@@ -33,22 +29,7 @@ const Editor = React.memo(({ data, onFieldChange }) => {
onChange={onFieldChange}
/>
<div className={styles.text}>{t('common.color')}</div>
<div className={styles.colorButtons}>
{LabelColors.map((color) => (
<Button
key={color}
type="button"
name="color"
value={color}
className={classNames(
styles.colorButton,
color === data.color && styles.colorButtonActive,
globalStyles[`background${upperFirst(camelCase(color))}`],
)}
onClick={onFieldChange}
/>
))}
</div>
<ColorPicker colors={LabelColors} current={data.color} onChange={onFieldChange} />
</>
);
});

View File

@@ -1,43 +1,4 @@
:global(#app) {
.colorButton {
float: left;
height: 40px;
margin: 4px;
padding: 0;
position: relative;
width: 49.6px;
&:hover {
opacity: 0.9;
}
}
.colorButtonActive:before {
bottom: 3px;
color: #ffffff;
content: "Г";
font-size: 18px;
line-height: 36px;
position: absolute;
right: 6px;
text-align: center;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
top: 0;
transform: rotate(-135deg);
width: 36px;
}
.colorButtons {
margin: -4px;
padding-bottom: 16px;
&:after {
content: "";
display: table;
clear: both;
}
}
.field {
margin-bottom: 8px;
}

View File

@@ -4,7 +4,9 @@ import { useTranslation } from 'react-i18next';
import { Menu } from 'semantic-ui-react';
import { Popup } from '../../lib/custom-ui';
import ListColors from '../../constants/ListColors';
import { useSteps } from '../../hooks';
import ColorPicker from '../ColorPicker';
import ListSortStep from '../ListSortStep';
import DeleteStep from '../DeleteStep';
@@ -13,93 +15,123 @@ import styles from './ActionsStep.module.scss';
const StepTypes = {
DELETE: 'DELETE',
SORT: 'SORT',
EDIT_COLOR: 'CHANGE_COLOR',
};
const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onSort, onDelete, onClose }) => {
const [t] = useTranslation();
const [step, openStep, handleBack] = useSteps();
const handleEditNameClick = useCallback(() => {
onNameEdit();
onClose();
}, [onNameEdit, onClose]);
const handleAddCardClick = useCallback(() => {
onCardAdd();
onClose();
}, [onCardAdd, onClose]);
const handleSortClick = useCallback(() => {
openStep(StepTypes.SORT);
}, [openStep]);
const handleDeleteClick = useCallback(() => {
openStep(StepTypes.DELETE);
}, [openStep]);
const handleSortTypeSelect = useCallback(
(type) => {
onSort({
type,
});
const ActionsStep = React.memo(
({ onNameEdit, onCardAdd, onSort, onDelete, onClose, onColorEdit, color }) => {
const [t] = useTranslation();
const [step, openStep, handleBack] = useSteps();
const handleEditNameClick = useCallback(() => {
onNameEdit();
onClose();
},
[onSort, onClose],
);
}, [onNameEdit, onClose]);
if (step && step.type) {
switch (step.type) {
case StepTypes.SORT:
return <ListSortStep onTypeSelect={handleSortTypeSelect} onBack={handleBack} />;
case StepTypes.DELETE:
return (
<DeleteStep
title="common.deleteList"
content="common.areYouSureYouWantToDeleteThisList"
buttonContent="action.deleteList"
onConfirm={onDelete}
onBack={handleBack}
/>
);
default:
const handleAddCardClick = useCallback(() => {
onCardAdd();
onClose();
}, [onCardAdd, onClose]);
const handleSortClick = useCallback(() => {
openStep(StepTypes.SORT);
}, [openStep]);
const handleDeleteClick = useCallback(() => {
openStep(StepTypes.DELETE);
}, [openStep]);
const hanndleEditColorClick = useCallback(() => {
openStep(StepTypes.EDIT_COLOR);
}, [openStep]);
const handleSortTypeSelect = useCallback(
(type) => {
onSort({
type,
});
onClose();
},
[onSort, onClose],
);
if (step && step.type) {
switch (step.type) {
case StepTypes.SORT:
return <ListSortStep onTypeSelect={handleSortTypeSelect} onBack={handleBack} />;
case StepTypes.DELETE:
return (
<DeleteStep
title="common.deleteList"
content="common.areYouSureYouWantToDeleteThisList"
buttonContent="action.deleteList"
onConfirm={onDelete}
onBack={handleBack}
/>
);
case StepTypes.EDIT_COLOR:
return (
<>
<Popup.Header onBack={handleBack}>
{t('action.editColor', {
context: 'title',
})}
</Popup.Header>
<Popup.Content>
<ColorPicker
colors={ListColors}
current={color}
allowDeletion
onChange={(e) => onColorEdit(e.currentTarget.value)}
/>
</Popup.Content>
</>
);
default:
}
}
}
return (
<>
<Popup.Header>
{t('common.listActions', {
context: 'title',
})}
</Popup.Header>
<Popup.Content>
<Menu secondary vertical className={styles.menu}>
<Menu.Item className={styles.menuItem} onClick={handleEditNameClick}>
{t('action.editTitle', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleAddCardClick}>
{t('action.addCard', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleSortClick}>
{t('action.sortList', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}>
{t('action.deleteList', {
context: 'title',
})}
</Menu.Item>
</Menu>
</Popup.Content>
</>
);
});
return (
<>
<Popup.Header>
{t('common.listActions', {
context: 'title',
})}
</Popup.Header>
<Popup.Content>
<Menu secondary vertical className={styles.menu}>
<Menu.Item className={styles.menuItem} onClick={handleEditNameClick}>
{t('action.editTitle', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={hanndleEditColorClick}>
{t('action.editColor', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleAddCardClick}>
{t('action.addCard', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleSortClick}>
{t('action.sortList', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}>
{t('action.deleteList', {
context: 'title',
})}
</Menu.Item>
</Menu>
</Popup.Content>
</>
);
},
);
ActionsStep.propTypes = {
onNameEdit: PropTypes.func.isRequired,
@@ -107,6 +139,12 @@ ActionsStep.propTypes = {
onDelete: PropTypes.func.isRequired,
onSort: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
onColorEdit: PropTypes.func.isRequired,
color: PropTypes.string,
};
ActionsStep.defaultProps = {
color: undefined,
};
export default ActionsStep;

View File

@@ -1,25 +1,29 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import camelCase from 'lodash/camelCase';
import { useTranslation } from 'react-i18next';
import upperFirst from 'lodash/upperFirst';
import { Draggable, Droppable } from 'react-beautiful-dnd';
import { Button, Icon } from 'semantic-ui-react';
import { usePopup } from '../../lib/popup';
import DroppableTypes from '../../constants/DroppableTypes';
import CardContainer from '../../containers/CardContainer';
import NameEdit from './NameEdit';
import CardAdd from './CardAdd';
import NameEdit from './NameEdit';
import ActionsStep from './ActionsStep';
import { ReactComponent as PlusMathIcon } from '../../assets/images/plus-math-icon.svg';
import styles from './List.module.scss';
import globalStyles from '../../styles.module.scss';
const List = React.memo(
({
id,
index,
name,
color,
isPersisted,
cardIds,
canEdit,
@@ -49,6 +53,15 @@ const List = React.memo(
[onUpdate],
);
const handleColorEdit = useCallback(
(newColor) => {
onUpdate({
color: newColor,
});
},
[onUpdate],
);
const handleAddCardClick = useCallback(() => {
setIsAddCardOpened(true);
}, []);
@@ -118,7 +131,18 @@ const List = React.memo(
onClick={handleHeaderClick}
>
<NameEdit ref={nameEdit} defaultValue={name} onUpdate={handleNameUpdate}>
<div className={styles.headerName}>{name}</div>
<div className={styles.headerName}>
{color && (
<Icon
name="circle"
className={classNames(
styles.headerNameColor,
globalStyles[`color${upperFirst(camelCase(color))}`],
)}
/>
)}
{name}
</div>
</NameEdit>
{isPersisted && canEdit && (
<ActionsPopup
@@ -126,6 +150,8 @@ const List = React.memo(
onCardAdd={handleCardAdd}
onDelete={onDelete}
onSort={onSort}
color={color}
onColorEdit={handleColorEdit}
>
<Button className={classNames(styles.headerButton, styles.target)}>
<Icon fitted name="pencil" size="small" />
@@ -140,7 +166,7 @@ const List = React.memo(
<button
type="button"
disabled={!isPersisted}
className={classNames(styles.addCardButton)}
className={styles.addCardButton}
onClick={handleAddCardClick}
>
<PlusMathIcon className={styles.addCardButtonIcon} />
@@ -161,6 +187,7 @@ List.propTypes = {
id: PropTypes.string.isRequired,
index: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
color: PropTypes.string,
isPersisted: PropTypes.bool.isRequired,
cardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
canEdit: PropTypes.bool.isRequired,
@@ -170,4 +197,8 @@ List.propTypes = {
onCardCreate: PropTypes.func.isRequired,
};
List.defaultProps = {
color: undefined,
};
export default List;

View File

@@ -127,6 +127,11 @@
word-break: break-word;
}
.headerNameColor {
line-height: 1;
margin-right: 6px;
}
.innerWrapper {
margin-right: 8px;
width: 272px;

View File

@@ -1,18 +1,15 @@
import { dequal } from 'dequal';
import upperFirst from 'lodash/upperFirst';
import camelCase from 'lodash/camelCase';
import React, { useCallback, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { Button, Image } from 'semantic-ui-react';
import { FilePicker } from '../../lib/custom-ui';
import ProjectBackgroundGradients from '../../constants/ProjectBackgroundGradients';
import { ProjectBackgroundTypes } from '../../constants/Enums';
import ColorPicker from '../ColorPicker';
import styles from './BackgroundPane.module.scss';
import globalStyles from '../../styles.module.scss';
const BackgroundPane = React.memo(
({ item, imageCoverUrl, isImageUpdating, onUpdate, onImageUpdate, onImageDelete }) => {
@@ -68,23 +65,11 @@ const BackgroundPane = React.memo(
return (
<>
<div className={styles.gradientButtons}>
{ProjectBackgroundGradients.map((gradient) => (
<Button
key={gradient}
type="button"
name="gradient"
value={gradient}
className={classNames(
styles.gradientButton,
item &&
item.type === ProjectBackgroundTypes.GRADIENT &&
gradient === item.name &&
styles.gradientButtonActive,
globalStyles[`background${upperFirst(camelCase(gradient))}`],
)}
onClick={handleGradientClick}
/>
))}
<ColorPicker
colors={ProjectBackgroundGradients}
current={item?.name}
onChange={handleGradientClick}
/>
</div>
{imageCoverUrl && (
// TODO: wrap in button

View File

@@ -0,0 +1,12 @@
export default [
'berry-red',
'pumpkin-orange',
'lagoon-blue',
'pink-tulip',
'light-mud',
'orange-peel',
'bright-moss',
'antique-blue',
'dark-granite',
'lagune-blue',
];

View File

@@ -11,7 +11,7 @@ const makeMapStateToProps = () => {
const selectCardIdsByListId = selectors.makeSelectCardIdsByListId();
return (state, { id, index }) => {
const { name, isPersisted } = selectListById(state, id);
const { name, color, isPersisted } = selectListById(state, id);
const cardIds = selectCardIdsByListId(state, id);
const currentUserMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state);
@@ -22,6 +22,7 @@ const makeMapStateToProps = () => {
id,
index,
name,
color,
isPersisted,
cardIds,
canEdit: isCurrentUserEditor,

View File

@@ -196,6 +196,7 @@ export default {
duplicate: 'Kopieren',
duplicateCard_title: 'Karte kopieren',
edit: 'Bearbeiten',
editColor_title: 'Farbe ändern',
editDueDate_title: 'Fälligkeitsdatum bearbeiten',
editDescription_title: 'Beschreibung ändern',
editEmail_title: 'E-Mail-Adresse bearbeiten',
@@ -212,6 +213,7 @@ export default {
moveCard_title: 'Karte bewegen',
remove: 'Löschen',
removeBackground: 'Hintergrund löschen',
removeColor: 'Farbe löschen',
removeCover_title: 'Vorschau löschen',
removeFromBoard: 'Vom Board entfernen',
removeFromProject: 'Vom Projekt entfernen',

View File

@@ -214,6 +214,7 @@ export default {
duplicate: 'Duplicate',
duplicateCard_title: 'Duplicate Card',
edit: 'Edit',
editColor_title: 'Edit Color',
editDueDate_title: 'Edit Due Date',
editDescription_title: 'Edit Description',
editEmail_title: 'Edit E-mail',
@@ -233,6 +234,7 @@ export default {
moveCard_title: 'Move Card',
remove: 'Remove',
removeBackground: 'Remove background',
removeColor: 'Remove color',
removeCover_title: 'Remove Cover',
removeFromBoard: 'Remove from board',
removeFromProject: 'Remove from project',

View File

@@ -210,6 +210,7 @@ export default {
duplicate: 'Duplicate',
duplicateCard_title: 'Duplicate Card',
edit: 'Edit',
editColor_title: 'Edit Color',
editDueDate_title: 'Edit Due Date',
editDescription_title: 'Edit Description',
editEmail_title: 'Edit E-mail',
@@ -229,6 +230,7 @@ export default {
moveCard_title: 'Move Card',
remove: 'Remove',
removeBackground: 'Remove background',
removeColor: 'Remove color',
removeCover_title: 'Remove Cover',
removeFromBoard: 'Remove from board',
removeFromProject: 'Remove from project',

View File

@@ -27,21 +27,22 @@ export default {
all: 'Tout',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Toutes les modifications seront automatiquement enregistrées<br />une fois la connexion rétablie.',
areYouSureYouWantToDeleteThisAttachment: 'Voulez-vous vraiment supprimer cette pièce jointe?',
areYouSureYouWantToDeleteThisBoard: 'Êtes-vous sûr de vouloir supprimer ce tableau?',
areYouSureYouWantToDeleteThisCard: 'Voulez-vous vraiment supprimer cette carte?',
areYouSureYouWantToDeleteThisComment: 'Êtes-vous sûr de vouloir supprimer ce commentaire?',
areYouSureYouWantToDeleteThisLabel: 'Voulez-vous vraiment supprimer cette étiquette?',
areYouSureYouWantToDeleteThisList: 'Êtes-vous sûr de vouloir supprimer cette liste?',
areYouSureYouWantToDeleteThisProject: 'Êtes-vous sûr de vouloir supprimer ce projet?',
areYouSureYouWantToDeleteThisTask: 'Êtes-vous sûr de vouloir supprimer cette tâche?',
areYouSureYouWantToDeleteThisUser: 'Êtes-vous sûr de vouloir supprimer cet utilisateur?',
areYouSureYouWantToDeleteThisAttachment:
'Êtes-vous sûr de vouloir supprimer cette pièce jointe ?',
areYouSureYouWantToDeleteThisBoard: 'Êtes-vous sûr de vouloir supprimer ce tableau ?',
areYouSureYouWantToDeleteThisCard: 'Êtes-vous sûr de vouloir supprimer cette carte ?',
areYouSureYouWantToDeleteThisComment: 'Êtes-vous sûr de vouloir supprimer ce commentaire ?',
areYouSureYouWantToDeleteThisLabel: 'Êtes-vous sûr de vouloir supprimer cette étiquette ?',
areYouSureYouWantToDeleteThisList: 'Êtes-vous sûr de vouloir supprimer cette liste ?',
areYouSureYouWantToDeleteThisProject: 'Êtes-vous sûr de vouloir supprimer ce projet ?',
areYouSureYouWantToDeleteThisTask: 'Êtes-vous sûr de vouloir supprimer cette tâche ?',
areYouSureYouWantToDeleteThisUser: 'Êtes-vous sûr de vouloir supprimer cet utilisateur ?',
areYouSureYouWantToLeaveBoard: 'Êtes-vous sûr de vouloir quitter ce tableau ?',
areYouSureYouWantToLeaveProject: 'Êtes-vous sûr de vouloir quitter ce projet ?',
areYouSureYouWantToRemoveThisManagerFromProject:
'Êtes-vous sûr de vouloir supprimer ce manager du projet ?',
areYouSureYouWantToRemoveThisMemberFromProject:
'Êtes-vous sûr de vouloir supprimer ce membre du projet?',
'Êtes-vous sûr de vouloir supprimer ce membre du projet ?',
attachment: 'Pièce jointe',
attachments: 'Pièces jointes',
authentication: 'Authentification',
@@ -49,11 +50,11 @@ export default {
board: 'Tableau',
boardNotFound_title: 'Carte non trouvée',
canComment: 'Peut commenter',
canEditContentOfBoard: 'Peut éditer le contenu du tableau.',
canOnlyViewBoard: 'Peut uniquement voir le tableau.',
canEditContentOfBoard: 'Peut éditer le contenu du tableau',
canOnlyViewBoard: 'Peut uniquement voir le tableau',
cardActions_title: 'Actions sur la carte',
cardNotFound_title: 'Carte non trouvée',
cardOrActionAreDeleted: "La carte ou l'action sont supprimées.",
cardOrActionAreDeleted: "La carte ou l'action est supprimée.",
color: 'Couleur',
copy_inline: 'copie',
createBoard_title: 'Créer un tableau',
@@ -80,10 +81,10 @@ export default {
dropFileToUpload: 'Déposer le fichier à télécharger',
editor: 'Éditeur',
editAttachment_title: 'Modifier la pièce jointe',
editAvatar_title: 'Modifier Avatar',
editAvatar_title: "Modifier l'avatar",
editBoard_title: 'Modifier le tableau',
editDueDate_title: "Modifier la date d'échéance",
editEmail_title: "Modifier l'email",
editEmail_title: "Modifier l'e-mail",
editInformation_title: 'Modifier les informations',
editLabel_title: "Modifier l'étiquette",
editPassword_title: 'Modifier le mot de passe',
@@ -91,8 +92,8 @@ export default {
editStopwatch_title: 'Modifier la minuterie',
editUsername_title: "Modifier le nom d'utilisateur",
email: 'E-mail',
emailAlreadyInUse: 'Email déjà utilisé',
enterCardTitle: 'Saisir le titre de la carte... [Ctrl+Enter] pour ouvrir automatiquement',
emailAlreadyInUse: 'E-mail déjà utilisé',
enterCardTitle: 'Saisir le titre de la carte... [Ctrl+Entrée] pour ouvrir automatiquement',
enterDescription: 'Saisir la description...',
enterFilename: 'Saisir le nom du fichier',
enterListTitle: 'Saisie le titre de la liste...',
@@ -121,13 +122,13 @@ export default {
moveCard_title: 'Déplacer la carte',
name: 'Nom',
newestFirst: 'Le plus récent en premier',
newEmail: 'Nouveau email',
newEmail: 'Nouvel e-mail',
newPassword: 'Nouveau mot de passe',
newUsername: "Nouveau nom d'utilisateur",
noConnectionToServer: 'Pas de connexion au serveur',
noBoards: 'Pas de tableau',
noLists: 'Pas de listes',
noProjects: 'Pas de projets',
noLists: 'Pas de liste',
noProjects: 'Pas de projet',
notifications: 'Notifications',
noUnreadNotifications: 'Aucune notification non lue.',
oldestFirst: 'Le plus ancien en premier',
@@ -154,11 +155,11 @@ export default {
settings: 'Réglages',
sortList_title: 'Trier la liste',
stopwatch: 'Minuteur',
subscribeToMyOwnCardsByDefault: 'Abonnez-vous à mes propres cartes par défaut',
subscribeToMyOwnCardsByDefault: "M'abonner à mes propres cartes par défaut",
taskActions_title: 'Actions de tâche',
tasks: 'Tâches',
thereIsNoPreviewAvailableForThisAttachment:
"Il n'y a pas de prévisualisation de disponible pour cette pièce jointe.",
"Il n'y a pas d'aperçu disponible pour cette pièce jointe.",
time: 'Temps',
title: 'Titre',
userActions_title: "Actions de l'utilisateur",
@@ -218,7 +219,7 @@ export default {
edit: 'Modifier',
editDueDate_title: "Modifier la date d'échéance",
editDescription_title: 'Modifier la description',
editEmail_title: "Modifier l'email",
editEmail_title: "Modifier l'e-mail",
editInformation_title: 'Modifier les informations',
editPassword_title: 'Modifier le mot de passe',
editPermissions: 'Modifier les permissions',
@@ -230,12 +231,12 @@ export default {
leaveBoard: 'Quitter le tableau',
leaveProject: 'Quitter le projet',
logOut_title: 'Se déconnecter',
makeCover_title: 'Faire la jaquette',
makeCover_title: 'Faire la couverture',
move: 'Déplacer',
moveCard_title: 'Déplacer la carte',
remove: 'Supprimer',
removeBackground: "Supprimer l'arrière-plan",
removeCover_title: 'Supprimer la jaquette',
removeCover_title: 'Supprimer la couverture',
removeFromBoard: 'Supprimer le tableau',
removeFromProject: 'Supprimer du projet',
removeManager: 'Supprimer le manager',
@@ -245,7 +246,7 @@ export default {
showDetails: 'Afficher les détails',
showFewerAttachments: 'Afficher moins de pièces jointes',
sortList_title: 'Trier la liste',
start: 'Début',
start: 'Commencer',
stop: 'Arrêter',
subscribe: "S'abonner",
unsubscribe: 'Se désabonner',

View File

@@ -1,16 +1,16 @@
export default {
translation: {
common: {
emailOrUsername: "Email ou nom d'utilisateur",
invalidEmailOrUsername: "Email ou nom d'utilisateur invalide",
emailOrUsername: "E-mail ou nom d'utilisateur",
invalidEmailOrUsername: "E-mail ou nom d'utilisateur invalide",
invalidCredentials: 'Identifiants invalides',
invalidPassword: 'Mot de passe invalide',
logInToPlanka: 'Se connecter à Planka',
noInternetConnection: 'Aucune connection internet',
noInternetConnection: 'Aucune connexion Internet',
pageNotFound_title: 'Page non trouvée',
password: 'Mot de passe',
projectManagement: 'Gestion de projet',
serverConnectionFailed: 'Connection au serveur échouée',
serverConnectionFailed: 'Échec de la connexion au serveur',
unknownError: 'Erreur inconnue, réessayez plus tard',
useSingleSignOn: "Utiliser l'authentification unique",
},

View File

@@ -11,6 +11,7 @@ export default class extends BaseModel {
id: attr(),
position: attr(),
name: attr(),
color: attr(),
boardId: fk({
to: 'Board',
as: 'board',

View File

@@ -384,4 +384,46 @@
.backgroundRedCurtain {
background: radial-gradient(circle 371px at 2.9% 14.3%, rgba(255, 0, 102, 1) 0%, rgba(80, 5, 35, 1) 100.7%) !important;
}
/* Colors */
.colorBerryRed {
color: #e04556 !important;
}
.colorPumpkinOrange {
color: #f0982d !important;
}
.colorLagoonBlue {
color: #109dc0 !important;
}
.colorPinkTulip {
color: #f97394 !important;
}
.colorLightMud {
color: #c7a57b !important;
}
.colorOrangePeel {
color: #fab623 !important;
}
.colorBrightMoss {
color: #a5c261 !important;
}
.colorAntiqueBlue {
color: #6c99bb !important;
}
.colorDarkGranite {
color: #8b8680 !important;
}
.colorLaguneBlue {
color: #00b4b1 !important;
}
}

View File

@@ -1 +1 @@
export default '1.24.4';
export default '1.25.0';

View File

@@ -1,18 +1,20 @@
FROM node:18-alpine AS server-dependencies
RUN apk -U upgrade \
&& apk add build-base python3 \
--no-cache
&& apk add build-base python3 --no-cache
WORKDIR /app/client
COPY package.json package-lock.json /app/client/
COPY package.json package-lock.json .
RUN npm install npm --global \
&& npm install pnpm --global \
&& npm install pnpm@9 --global \
&& pnpm import \
&& pnpm install
WORKDIR /app
COPY ../../package.json ../../package-lock.json .
WORKDIR /app/
COPY ../../package.json ../../package-lock.json /app/
RUN pnpm import \
&& pnpm install

View File

@@ -1,14 +1,13 @@
FROM node:18-alpine AS server-dependencies
RUN apk -U upgrade \
&& apk add build-base python3 \
--no-cache
&& apk add build-base python3 --no-cache
WORKDIR /app
COPY package.json package-lock.json ./
COPY package.json package-lock.json .
RUN npm install npm --global \
&& npm install pnpm --global \
&& npm install pnpm@9 --global \
&& pnpm import \
&& pnpm install

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "planka",
"version": "1.24.4",
"version": "1.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "planka",
"version": "1.24.4",
"version": "1.25.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "planka",
"version": "1.24.4",
"version": "1.25.0",
"private": true,
"homepage": "https://plankanban.github.io/planka",
"repository": {

View File

@@ -21,6 +21,11 @@ module.exports = {
type: 'string',
isNotEmptyString: true,
},
color: {
type: 'string',
isIn: List.COLORS,
allowNull: true,
},
},
exits: {
@@ -55,7 +60,7 @@ module.exports = {
throw Errors.NOT_ENOUGH_RIGHTS;
}
const values = _.pick(inputs, ['position', 'name']);
const values = _.pick(inputs, ['position', 'name', 'color']);
list = await sails.helpers.lists.updateOne.with({
values,

View File

@@ -12,8 +12,22 @@ const SortTypes = {
CREATED_AT_DESC: 'createdAt_desc',
};
const COLORS = [
'berry-red',
'pumpkin-orange',
'lagoon-blue',
'pink-tulip',
'light-mud',
'orange-peel',
'bright-moss',
'antique-blue',
'dark-granite',
'lagune-blue',
];
module.exports = {
SortTypes,
COLORS,
attributes: {
// ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗
@@ -28,6 +42,11 @@ module.exports = {
type: 'string',
required: true,
},
color: {
type: 'string',
isIn: COLORS,
allowNull: true,
},
// ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
// ║╣ ║║║╠╩╗║╣ ║║╚═╗

View File

@@ -48,5 +48,6 @@ module.exports.datastores = {
adapter: 'sails-postgresql',
url: process.env.DATABASE_URL,
schemaName: process.env.DATABASE_SCHEMA,
},
};

View File

@@ -0,0 +1,17 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = (knex) =>
knex.schema.alterTable('list', (table) => {
table.text('color');
});
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = (knex) =>
knex.schema.alterTable('list', (table) => {
table.dropColumn('color');
});

View File

@@ -18,7 +18,7 @@
"nodemailer": "^6.9.16",
"openid-client": "^5.7.1",
"rimraf": "^5.0.10",
"sails": "^1.5.13",
"sails": "^1.5.14",
"sails-hook-orm": "^4.0.3",
"sails-hook-sockets": "^3.0.1",
"sails-postgresql": "^5.0.1",
@@ -3235,6 +3235,7 @@
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
},
@@ -4109,9 +4110,10 @@
}
},
"node_modules/express": {
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -4132,7 +4134,7 @@
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.10",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
@@ -4147,6 +4149,10 @@
},
"engines": {
"node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/express-session": {
@@ -4196,12 +4202,14 @@
"node_modules/express/node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/express/node_modules/cookie": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -4209,12 +4217,14 @@
"node_modules/express/node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/express/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
@@ -4223,6 +4233,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
@@ -4240,6 +4251,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
@@ -4254,25 +4266,29 @@
"node_modules/express/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/express/node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/express/node_modules/path-to-regexp": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
"node_modules/express/node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
@@ -4588,6 +4604,7 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -5153,6 +5170,7 @@
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
@@ -6161,6 +6179,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
@@ -7081,6 +7100,7 @@
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
@@ -7590,9 +7610,10 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sails": {
"version": "1.5.13",
"resolved": "https://registry.npmjs.org/sails/-/sails-1.5.13.tgz",
"integrity": "sha512-6XTlCnXPbQZuGlDE+ZqCbYCkbQrFDQGJP3tQ76xSQYX7kDJIzaYvcviPye0zWiZEWYtfZIku0kRAlaNWAgYBsA==",
"version": "1.5.14",
"resolved": "https://registry.npmjs.org/sails/-/sails-1.5.14.tgz",
"integrity": "sha512-u4EOT94me18E2MRJtumorgRS+b0TiBLdnAj2WIKmy4mYvc/SNuzcs8Fd/HCmqw979MwQb8hYdwnpwaSBdNaIDg==",
"license": "MIT",
"dependencies": {
"@sailshq/csurf": "1.11.1",
"@sailshq/lodash": "^3.10.6",
@@ -7608,7 +7629,7 @@
"cookie-parser": "1.4.7",
"cookie-signature": "1.1.0",
"ejs": "3.1.10",
"express": "4.21.1",
"express": "4.21.2",
"express-session": "1.18.1",
"flaverr": "^1.10.0",
"glob": "7.1.2",

View File

@@ -39,7 +39,7 @@
"nodemailer": "^6.9.16",
"openid-client": "^5.7.1",
"rimraf": "^5.0.10",
"sails": "^1.5.13",
"sails": "^1.5.14",
"sails-hook-orm": "^4.0.3",
"sails-hook-sockets": "^3.0.1",
"sails-postgresql": "^5.0.1",