Compare commits

...

11 Commits

Author SHA1 Message Date
Laurent Bossavit 38cfaff81f Fix typo 2024-10-25 13:00:37 +02:00
Laurent Bossavit 80ac55b6e2 (ci) add docker layer caching 2024-10-24 16:32:13 +02:00
Sabrina Demagny 230ed75d8d 🔖(patch) release version 1.4.1
Update all version files and changelog for patch release.
2024-10-23 22:55:56 +02:00
NathanPanchout 5ac3454c5a 🚑️(frontend) fix MailDomainsLayout
The content is not scrollable. We add an auto overflow to solve this problem
2024-10-23 21:44:28 +02:00
Sabrina Demagny bbac34b62a 🔖(minor) release version 1.4.0 (#483)
Update all version files and changelog for minor release.
2024-10-23 19:15:14 +02:00
Sabrina Demagny 38508c272e 📝(CHANGELOG) fix modification declaration
One of unreleased modification declaration was
declared in a wrong place
2024-10-23 18:46:04 +02:00
Sabrina Demagny 10a81f14e6 ✏️(mail) fix typo in mailbox creation email
Whitespace missing in french translation after ':'
2024-10-23 17:56:40 +02:00
Nathan Panchout a08689a64d (frontend) add tabs for mail domain page (#466)
Currently, it is complicated to understand the navigation between mailbox
management and role management for an email domain.
This is why we add tabs with explicit naming
2024-10-23 17:45:42 +02:00
Marie PUPO JEAMMET 30229e11f9 🐛(sentry) fix duplicated sentry errors
errors were sent to sentry twice
2024-10-22 18:03:01 +02:00
Sabrina Demagny d11d1f3bd0 🐛(script) improve and fix release script
Use regex to replace version and add missing
frontend update version.
2024-10-22 00:28:08 +02:00
renovate[bot] 6a22169dae ⬆️(dependencies) update python dependencies 2024-10-21 12:22:49 +02:00
28 changed files with 423 additions and 212 deletions
+18 -4
View File
@@ -150,7 +150,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set services env variables
run: |
make create-env-files
@@ -175,15 +175,29 @@ jobs:
with:
path: src/frontend/apps/desk/out/
key: build-front-${{ github.run_id }}
# Pull the latest image to build, and avoid caching pull-only images.
# (docker pull is faster than caching in most cases.)
- run: docker compose pull
# In this step, this action saves a list of existing images,
# the cache is created without them in the post run.
# It also restores the cache if it exists.
- uses: satackey/action-docker-layer-caching@v0.0.11
# Ignore the failure of a step and avoid terminating the job.
continue-on-error: true
- name: Build and Start Docker Servers
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
run: |
docker compose build --pull --build-arg BUILDKIT_INLINE_CACHE=1
docker compose build --build-arg BUILDKIT_INLINE_CACHE=1
make run
# Finally, "Post Run satackey/action-docker-layer-caching@v0.0.11",
# which is the process of saving the cache, will be executed.
- name: Apply DRF migrations
run: |
make migrate
+21 -1
View File
@@ -8,6 +8,24 @@ and this project adheres to
## [Unreleased]
## [1.4.1] - 2024-10-23
### Fixed
- 🚑️(frontend) fix MailDomainsLayout
## [1.4.0] - 2024-10-23
### Added
- ✨(frontend) add tabs inside #466
### Fixed
- ✏️(mail) fix typo into mailbox creation email
- 🐛(sentry) fix duplicated sentry errors #479
- 🐛(script) improve and fix release script
## [1.3.1] - 2024-10-18
## [1.3.0] - 2024-10-18
@@ -106,7 +124,9 @@ and this project adheres to
- ✨(domains) create and manage domains on admin + API
- ✨(domains) mailbox creation + link to email provisioning API
[unreleased]: https://github.com/numerique-gouv/people/compare/v1.3.1...main
[unreleased]: https://github.com/numerique-gouv/people/compare/v1.4.1...main
[1.4.1]: https://github.com/numerique-gouv/people/releases/v1.4.1
[1.4.0]: https://github.com/numerique-gouv/people/releases/v1.4.0
[1.3.1]: https://github.com/numerique-gouv/people/releases/v1.3.1
[1.3.0]: https://github.com/numerique-gouv/people/releases/v1.3.0
[1.2.1]: https://github.com/numerique-gouv/people/releases/v1.2.1
+6 -7
View File
@@ -1,5 +1,6 @@
import datetime
import os
import re
import sys
from utils import run_command
@@ -17,9 +18,7 @@ def update_files(version):
lines = file.readlines()
for index, line in enumerate(lines):
if line.startswith("version = "):
last_version = line.split("=")[-1]
new_line = line.replace(last_version, f' "{version}"\n')
lines[index] = new_line
lines[index] = re.sub(r'\"(.*?)\"', f'"{version}"', line)
with open(path, 'w+') as file:
file.writelines(lines)
@@ -30,8 +29,8 @@ def update_files(version):
with open(path, 'r') as file:
lines = file.readlines()
for index, line in enumerate(lines):
if line.startswith(" tag: "):
lines[index] = f' tag: "v{version}"\n'
if "tag:" in line:
lines[index] = re.sub(r'\"(.*?)\"', f'"v{version}"', line)
with open(path, 'w+') as file:
file.writelines(lines)
@@ -47,8 +46,8 @@ def update_files(version):
with open(path, 'r') as file:
lines = file.readlines()
for index, line in enumerate(lines):
if line.startswith(' "version": '):
lines[index] = f' "version": "{version}",\n'
if "version" in line:
lines[index] = re.sub(r'"version": \"(.*?)\"', f'"version": "{version}"', line)
with open(path, 'w+') as file:
file.writelines(lines)
return
Binary file not shown.
@@ -403,7 +403,7 @@ msgstr "Adresse email : "
#: core/templates/mail/html/new_mailbox.html:233
#: core/templates/mail/text/new_mailbox.txt:11
msgid "Temporary password (to be modify on first login): "
msgstr "Mot de passe temporaire (à modifier à la première connexion) :"
msgstr "Mot de passe temporaire (à modifier à la première connexion) : "
#: core/templates/mail/html/new_mailbox.html:261
#: core/templates/mail/text/new_mailbox.txt:13
@@ -470,7 +470,7 @@ msgstr ""
#: mailbox_manager/utils/dimail.py:137
msgid "Your new mailbox information"
msgstr ""
msgstr "Informations concernant votre nouvelle boîte mail"
#: people/settings.py:134
msgid "English"
+1
View File
@@ -488,6 +488,7 @@ class Base(Configuration):
release=get_release(),
integrations=[DjangoIntegration()],
traces_sample_rate=0.1,
default_integrations=False,
)
with sentry_sdk.configure_scope() as scope:
scope.set_extra("application", "backend")
+9 -9
View File
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "people"
version = "1.3.1"
version = "1.4.1"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
@@ -25,18 +25,18 @@ license = { file = "LICENSE" }
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"boto3==1.35.34",
"boto3==1.35.44",
"Brotli==1.1.0",
"celery[redis]==5.4.0",
"django-configurations==2.5.1",
"django-cors-headers==4.4.0",
"django-cors-headers==4.5.0",
"django-countries==7.6.1",
"django-parler==2.3",
"redis==5.1.1",
"django-redis==5.4.0",
"django-storages==1.14.4",
"django-timezone-field>=5.1",
"django==5.1.1",
"django==5.1.2",
"djangorestframework==3.15.2",
"drf_spectacular==0.27.2",
"dockerflow==2024.4.2",
@@ -49,7 +49,7 @@ dependencies = [
"PyJWT==2.9.0",
"joserfc==1.0.0",
"requests==2.32.3",
"sentry-sdk[django]==2.15.0",
"sentry-sdk[django]==2.17.0",
"url-normalize==1.4.3",
"whitenoise==6.7.0",
"mozilla-django-oidc==4.0.1",
@@ -67,8 +67,8 @@ dev = [
"drf-spectacular-sidecar==2024.7.1",
"ipdb==0.13.13",
"ipython==8.28.0",
"pyfakefs==5.6.0",
"pylint-django==2.5.5",
"pyfakefs==5.7.1",
"pylint-django==2.6.1",
"pylint==3.3.1",
"pytest-cov==5.0.0",
"pytest-django==4.9.0",
@@ -76,8 +76,8 @@ dev = [
"pytest-icdiff==0.9",
"pytest-xdist==3.6.1",
"responses==0.25.3",
"ruff==0.6.9",
"types-requests==2.32.0.20240914",
"ruff==0.7.0",
"types-requests==2.32.0.20241016",
"freezegun==1.5.1",
]
+5
View File
@@ -1,3 +1,5 @@
const path = require('path');
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
@@ -5,6 +7,9 @@ const nextConfig = {
images: {
unoptimized: true,
},
sassOptions: {
includePaths: [path.join(__dirname, 'src')],
},
compiler: {
// Enables the styled-components SWC transform
styledComponents: true,
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "app-desk",
"version": "1.3.1",
"version": "1.4.1",
"private": true,
"scripts": {
"dev": "next dev",
@@ -29,6 +29,7 @@
"react-hook-form": "7.53.0",
"react-i18next": "15.0.2",
"react-select": "5.8.1",
"sass": "1.80.3",
"styled-components": "6.1.13",
"zod": "3.23.8",
"zustand": "4.5.5"
@@ -0,0 +1,54 @@
import * as React from 'react';
import { ReactNode } from 'react';
import { Tab, TabList, TabPanel, Tabs } from 'react-aria-components';
import { Box } from '@/components';
import style from './custom-tabs.module.scss';
type TabsOption = {
ariaLabel?: string;
label: string;
iconName?: string;
id?: string;
content: ReactNode;
};
type Props = {
tabs: TabsOption[];
};
export const CustomTabs = ({ tabs }: Props) => {
return (
<div className={style.customTabsContainer}>
<Tabs>
<TabList>
{tabs.map((tab) => {
const id = tab.id ?? tab.label;
return (
<Tab key={id} aria-label={tab.ariaLabel} id={id}>
<Box $direction="row" $align="center" $gap="5px">
{tab.iconName && (
<span className="material-icons" aria-hidden="true">
{tab.iconName}
</span>
)}
{tab.label}
</Box>
</Tab>
);
})}
</TabList>
{tabs.map((tab) => {
const id = tab.id ?? tab.label;
return (
<TabPanel key={id} id={id}>
{tab.content}
</TabPanel>
);
})}
</Tabs>
</div>
);
};
@@ -0,0 +1,63 @@
.customTabsContainer {
:global {
.react-aria-TabList {
display: flex;
&[data-orientation='horizontal'] {
.react-aria-Tab {
border-bottom: 2px solid var(--c--theme--colors--greyscale-500);
}
}
}
.react-aria-Tab {
padding: 10px;
cursor: pointer;
outline: none;
position: relative;
color: var(--c--theme--colors--greyscale-700);
transition: color 200ms;
--border-color: transparent;
forced-color-adjust: none;
&[data-hovered],
&[data-focused] {
color: var(--c--theme--colors--greyscale-900);
}
&[data-selected] {
border-bottom: 2px solid var(--c--theme--colors--primary-600) !important;
color: var(--c--theme--colors--primary-600);
}
&[data-disabled] {
color: var(--c--theme--colors--greyscale-500);
&[data-selected] {
--border-color: var(--c--theme--colors--greyscale-200);
}
}
&[data-focus-visible]::after {
content: '';
position: absolute;
inset: 4px;
border-radius: 4px;
border: 1px solid var(--c--theme--colors--primary-600);
}
}
.react-aria-TabPanel {
margin-top: 4px;
padding: 10px;
border-radius: 4px;
outline: none;
&[data-focus-visible] {
outline: 2px solid var(--c--theme--colors--primary-600);
}
}
}
}
@@ -1,11 +1,6 @@
import { Button } from '@openfun/cunningham-react';
import { useRouter } from 'next/navigation';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Text } from '@/components';
import { AccessesGrid } from '@/features/mail-domains/access-management/components/AccessesGrid';
import MailDomainsLogo from '@/features/mail-domains/assets/mail-domains-logo.svg';
import { MailDomain, Role } from '../../domains';
@@ -17,50 +12,6 @@ export const AccessesContent = ({
currentRole: Role;
}) => (
<>
<TopBanner mailDomain={mailDomain} />
<AccessesGrid mailDomain={mailDomain} currentRole={currentRole} />
</>
);
const TopBanner = ({ mailDomain }: { mailDomain: MailDomain }) => {
const router = useRouter();
const { t } = useTranslation();
return (
<Box
$direction="column"
$margin={{ all: 'big', bottom: 'tiny' }}
$gap="1rem"
>
<Box
$direction="row"
$align="center"
$gap="2.25rem"
$justify="space-between"
>
<Box $direction="row" $margin="none" $gap="0.5rem">
<MailDomainsLogo aria-hidden="true" />
<Text $margin="none" as="h3" $size="h3">
{mailDomain?.name}
</Text>
</Box>
</Box>
<Box $direction="row" $justify="flex-end">
<Box $display="flex" $direction="row" $gap="8rem">
{mailDomain?.abilities?.manage_accesses && (
<Button
color="tertiary"
aria-label={t('Manage {{name}} domain mailboxes', {
name: mailDomain?.name,
})}
onClick={() => router.push(`/mail-domains/${mailDomain.slug}/`)}
>
{t('Manage mailboxes')}
</Button>
)}
</Box>
</Box>
</Box>
);
};
@@ -106,8 +106,6 @@ export const AccessesGrid = ({
return (
<Card
$padding={{ bottom: 'small' }}
$margin={{ all: 'big', top: 'none' }}
$overflow="auto"
$css={`
& .c__pagination__goto {
@@ -1,8 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
import { useRouter } from 'next/navigation';
import { AccessesGrid } from '@/features/mail-domains/access-management';
import { AppWrapper } from '@/tests/utils';
import { MailDomain, Role } from '../../../domains';
@@ -61,58 +59,9 @@ describe('AccessesContent', () => {
});
});
it('renders the top banner and accesses grid correctly', () => {
it('renders the accesses grid correctly', () => {
renderAccessesContent();
expect(screen.getByText(mockMailDomain.name)).toBeInTheDocument();
expect(screen.getByTestId('mail-domains-logo')).toBeInTheDocument();
expect(screen.getByText('Mock AccessesGrid')).toBeInTheDocument();
});
it('renders the "Manage mailboxes" button when the user has access', () => {
renderAccessesContent();
const manageMailboxesButton = screen.getByRole('button', {
name: /Manage example.com domain mailboxes/,
});
expect(manageMailboxesButton).toBeInTheDocument();
expect(AccessesGrid).toHaveBeenCalledWith(
{ currentRole: Role.ADMIN, mailDomain: mockMailDomain },
{}, // adding this empty object is necessary to load jest context and that AccessesGrid is a mock
);
});
it('does not render the "Manage mailboxes" button if the user lacks manage_accesses ability', () => {
const mailDomainWithoutAccess = {
...mockMailDomain,
abilities: {
...mockMailDomain.abilities,
manage_accesses: false,
},
};
renderAccessesContent(Role.ADMIN, mailDomainWithoutAccess);
expect(
screen.queryByRole('button', {
name: /Manage mailboxes/i,
}),
).not.toBeInTheDocument();
});
it('navigates to the mailboxes management page when "Manage mailboxes" is clicked', async () => {
renderAccessesContent();
const manageMailboxesButton = screen.getByRole('button', {
name: /Manage example.com domain mailboxes/,
});
await userEvent.click(manageMailboxesButton);
await waitFor(() => {
expect(mockRouterPush).toHaveBeenCalledWith(`/mail-domains/example-com/`);
});
});
});
@@ -0,0 +1,68 @@
import * as React from 'react';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Text } from '@/components';
import { CustomTabs } from '@/components/tabs/CustomTabs';
import { AccessesContent } from '@/features/mail-domains/access-management';
import MailDomainsLogo from '@/features/mail-domains/assets/mail-domains-logo.svg';
import { MailDomain, Role } from '@/features/mail-domains/domains';
import { MailDomainsContent } from '@/features/mail-domains/mailboxes';
type Props = {
mailDomain: MailDomain;
};
export const MailDomainView = ({ mailDomain }: Props) => {
const { t } = useTranslation();
const currentRole = mailDomain.abilities.delete
? Role.OWNER
: mailDomain.abilities.manage_accesses
? Role.ADMIN
: Role.VIEWER;
const tabs = useMemo(() => {
return [
{
ariaLabel: t('Go to mailbox management'),
id: 'mails',
iconName: 'mail',
label: t('Mailbox management'),
content: <MailDomainsContent mailDomain={mailDomain} />,
},
{
ariaLabel: t('Go to accesses management'),
id: 'accesses',
iconName: 'people',
label: t('Access management'),
content: (
<AccessesContent mailDomain={mailDomain} currentRole={currentRole} />
),
},
];
}, [t, currentRole, mailDomain]);
return (
<Box $padding="big">
<Box
$width="100%"
$direction="row"
$align="center"
$gap="2.25rem"
$justify="center"
>
<Box
$direction="row"
$justify="center"
$margin={{ bottom: 'big' }}
$gap="0.5rem"
>
<MailDomainsLogo aria-hidden="true" />
<Text $margin="none" as="h3" $size="h3">
{mailDomain?.name}
</Text>
</Box>
</Box>
<CustomTabs tabs={tabs} />
</Box>
);
};
@@ -16,6 +16,7 @@ export function MailDomainsLayout({ children }: PropsWithChildren) {
<Box
$background={colorsTokens()['primary-bg']}
$width="100%"
$overflow="auto"
$height="inherit"
>
{children}
@@ -9,14 +9,12 @@ import {
VariantType,
usePagination,
} from '@openfun/cunningham-react';
import { useRouter } from 'next/navigation';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Card, Text, TextErrors, TextStyled } from '@/components';
import { ModalCreateMailbox } from '@/features/mail-domains/mailboxes';
import { default as MailDomainsLogo } from '../../assets/mail-domains-logo.svg';
import { PAGE_SIZE } from '../../conf';
import { MailDomain } from '../../domains/types';
import { useMailboxes } from '../api/useMailboxes';
@@ -99,12 +97,7 @@ export function MailDomainsContent({ mailDomain }: { mailDomain: MailDomain }) {
showMailBoxCreationForm={setIsCreateMailboxFormVisible}
/>
<Card
$padding={{ bottom: 'small' }}
$margin={{ all: 'big', top: 'none' }}
$overflow="auto"
aria-label={t('Mailboxes list card')}
>
<Card $overflow="auto" aria-label={t('Mailboxes list card')}>
{error && <TextErrors causes={error.cause} />}
<DataGrid
@@ -153,47 +146,19 @@ const TopBanner = ({
mailDomain: MailDomain;
showMailBoxCreationForm: (value: boolean) => void;
}) => {
const router = useRouter();
const { t } = useTranslation();
return (
<Box
$direction="column"
$margin={{ all: 'big', bottom: 'tiny' }}
$gap="1rem"
>
<Box $direction="column" $gap="1rem">
<AlertStatus status={mailDomain.status} />
<Box
$direction="row"
$justify="flex-end"
$margin={{ bottom: 'small' }}
$align="center"
$gap="2.25rem"
$justify="space-between"
>
<Box $direction="row" $margin="none" $gap="0.5rem">
<MailDomainsLogo aria-hidden="true" />
<Text $margin="none" as="h3" $size="h3">
{mailDomain?.name}
</Text>
</Box>
</Box>
<Box $direction="row" $justify="space-between">
<AlertStatus status={mailDomain.status} />
</Box>
<Box $direction="row" $justify="flex-end">
<Box $display="flex" $direction="row" $gap="0.5rem">
{mailDomain?.abilities?.manage_accesses && (
<Button
color="tertiary"
aria-label={t('Manage {{name}} domain members', {
name: mailDomain?.name,
})}
onClick={() =>
router.push(`/mail-domains/${mailDomain.slug}/accesses/`)
}
>
{t('Manage accesses')}
</Button>
)}
<Box $display="flex" $direction="row">
{mailDomain?.abilities.post && (
<Button
aria-label={t('Create a mailbox in {{name}} domain', {
@@ -187,25 +187,6 @@ describe('MailDomainsContent', () => {
});
});
it('redirects to accesses management page when button is clicked by granted user', async () => {
fetchMock.get('end:/mail-domains/example-com/mailboxes/?page=1', {
count: 0,
results: [],
});
render(<MailDomainsContent mailDomain={mockMailDomain} />, {
wrapper: AppWrapper,
});
await waitFor(async () => {
await userEvent.click(screen.getByText('Manage accesses'));
});
expect(mockPush).toHaveBeenCalledWith(
'/mail-domains/example-com/accesses/',
);
});
it('displays the correct alert based on mail domain status', async () => {
fetchMock.get('end:/mail-domains/example-com/mailboxes/?page=1', {
count: 0,
@@ -1,5 +1,4 @@
{
"de": { "translation": {} },
"en": {
"translation": {
"{{count}} member_many": "{{count}} members",
@@ -11,6 +10,7 @@
"translation": {
"0 group to display.": "0 groupe à afficher.",
"Access icon": "Icône d'accès",
"Access management": "Gestion des rôles",
"Accesses list card": "Carte de la liste des accès",
"Accessibility statement": "Déclaration d'accessibilité",
"Accessibility: non-compliant": "Accessibilité : non conforme",
@@ -68,6 +68,8 @@
"First name": "Prénom",
"Freedom Equality Fraternity Logo": "Logo Liberté Égalité Fraternité",
"French Interministerial Directorate for Digital Affairs (DINUM), 20 avenue de Ségur 75007 Paris.": "Direction interministérielle des affaires numériques (DINUM), 20 avenue de Segur 75007 Paris.",
"Go to accesses management": "Aller à la gestion des rôles",
"Go to mailbox management": "Aller à la gestion des mails",
"Group details": "Détails du groupe",
"Group members": "Membres du groupe",
"Groups": "Groupes",
@@ -94,12 +96,9 @@
"Mail domains panel": "Panel des domaines de messagerie",
"Mailbox created!": "Boîte mail créée !",
"Mailbox creation form": "Formulaire de création de boite mail",
"Mailbox management": "Gestion des boîtes mails",
"Mailboxes list": "Liste des boîtes mail",
"Mailboxes list card": "Carte liste des boîtes mails",
"Manage accesses": "Gérer les accès",
"Manage mailboxes": "Gérer les boîtes mails",
"Manage {{name}} domain mailboxes": "Gérer les boîtes mails du domaine {{name}}",
"Manage {{name}} domain members": "Gérer les membres du domaine {{name}}",
"Marianne Logo": "Logo Marianne",
"Member": "Membre",
"Member icon": "Icône de membre",
@@ -155,6 +154,7 @@
"The National Agency for Territorial Cohesion undertakes to make its\n service accessible, in accordance with article 47 of law no. 2005-102\n of February 11, 2005.": "L'Agence Nationale de la Cohésion des Territoires sengage à rendre son service accessible, conformément à larticle 47 de la loi n° 2005-102 du 11 février 2005.",
"The access has been removed from the domain": "L'accès a été supprimé du domaine",
"The domain name encounters an error. Please contact our support team to solve the problem:": "Le nom de domaine rencontre une erreur. Veuillez contacter notre support pour résoudre le problème :",
"The mail domain secret is misconfigured. Please, contact our support team to solve the issue: suiteterritoriale@anct.gouv.fr": "Le secret du domaine de messagerie est mal configuré. Veuillez contacter notre support pour résoudre le problème : suiteterritoriale@anct.gouv.fr",
"The member has been removed from the team": "Le membre a été supprimé de votre groupe",
"The role has been updated": "Le rôle a bien été mis à jour",
"The team has been removed.": "Le groupe a été supprimé.",
@@ -177,11 +177,11 @@
"Update the team": "Mettre à jour le groupe",
"Validate": "Valider",
"Validate the modification": "Valider la modification",
"Version: {{release}}": "Version : {{release}}",
"Viewer": "Lecteur",
"We simply comply with the law, which states that certain audience measurement tools, properly configured to respect privacy, are exempt from prior authorization.": "Nous nous conformons simplement à la loi, qui stipule que certains outils de mesure daudience, correctement configurés pour respecter la vie privée, sont exemptés de toute autorisation préalable.",
"You are the last owner, you cannot be removed from your domain.": "Vous êtes le dernier propriétaire, vous ne pouvez pas être retiré de votre domaine.",
"You are the last owner, you cannot be removed from your team.": "Vous êtes le dernier propriétaire, vous ne pouvez pas être retiré de votre groupe.",
"You are the sole owner of this domain. Make another member the domain owner, before you can change your own role.": "Vous êtes le seul propriétaire de ce domaine. Faites d'un autre membre le propriétaire du domaine avant de modifier votre rôle.",
"You are the sole owner of this group. Make another member the group owner, before you can change your own role.": "Vous êtes lunique propriétaire de ce groupe. Désignez un autre membre comme propriétaire du groupe, avant de pouvoir modifier votre propre rôle.",
"You can oppose the tracking of your browsing on this website.": "Vous pouvez vous opposer au suivi de votre navigation sur ce site.",
"You can:": "Vous pouvez :",
@@ -190,7 +190,6 @@
"You must have minimum 1 character": "Vous devez entrer au moins 1 caractère",
"Your domain name is being validated. You will not be able to create mailboxes until your domain name has been validated by our team.": "Votre nom de domaine est en cours de validation. Vous ne pourrez créer de boîtes mail que lorsque votre nom de domaine sera validé par notre équipe.",
"Your request cannot be processed because the server is experiencing an error. If the problem persists, please contact our support to resolve the issue: suiteterritoriale@anct.gouv.fr": "Votre demande ne peut pas être traitée car le serveur rencontre une erreur. Si le problème persiste, veuillez contacter notre support pour résoudre le problème : suiteterritoriale@anct.gouv.fr",
"Your request to create a mailbox cannot be completed due to incorrect settings on our server. Please contact our support team to resolve the problem: suiteterritoriale@anct.gouv.fr": "Votre demande de création de boîte mail ne peut pas être complétée en raison de paramètres incorrects sur notre serveur. Veuillez contacter notre équipe support pour résoudre le problème : suiteterritoriale@anct.gouv.fr",
"[disabled]": "[désactivé]",
"[enabled]": "[actif]",
"[failed]": "[erroné]",
@@ -1,7 +1,7 @@
import { Loader } from '@openfun/cunningham-react';
import { useRouter as useNavigate } from 'next/navigation';
import { useRouter } from 'next/router';
import { ReactElement } from 'react';
import React, { ReactElement } from 'react';
import { Box } from '@/components';
import { TextErrors } from '@/components/TextErrors';
@@ -9,7 +9,7 @@ import {
MailDomainsLayout,
useMailDomain,
} from '@/features/mail-domains/domains';
import { MailDomainsContent } from '@/features/mail-domains/mailboxes';
import { MailDomainView } from '@/features/mail-domains/domains/components/MailDomainView';
import { NextPageWithLayout } from '@/types/next';
const MailboxesPage: NextPageWithLayout = () => {
@@ -45,9 +45,13 @@ const MailboxesPage: NextPageWithLayout = () => {
<Loader />
</Box>
);
} else {
return mailDomain ? <MailDomainsContent mailDomain={mailDomain} /> : null;
}
if (!mailDomain) {
return null;
}
return <MailDomainView mailDomain={mailDomain} />;
};
MailboxesPage.getLayout = function getLayout(page: ReactElement) {
@@ -211,6 +211,19 @@ test.describe('Mail domain', () => {
},
];
test('checks if all tabs are visible', async ({ page }) => {
await interceptCommonApiCalls(page, mailDomainsFixtures);
await clickOnMailDomainsNavButton(page);
await assertMailDomainUpperElementsAreVisible(page);
await expect(
page.getByLabel('Go to accesses management'),
).toBeVisible();
await expect(page.getByLabel('Go to mailbox management')).toBeVisible();
});
test('checks all the elements are visible when domain exist but contains no mailboxes', async ({
page,
}) => {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "app-e2e",
"version": "1.3.1",
"version": "1.4.1",
"private": true,
"scripts": {
"lint": "eslint . --ext .ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "people",
"version": "1.3.1",
"version": "1.4.1",
"private": true,
"workspaces": {
"packages": [
@@ -1,6 +1,6 @@
{
"name": "eslint-config-people",
"version": "1.3.1",
"version": "1.4.1",
"license": "MIT",
"scripts": {
"lint": "eslint --ext .js ."
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "packages-i18n",
"version": "1.3.1",
"version": "1.4.1",
"private": true,
"scripts": {
"extract-translation": "yarn extract-translation:desk",
+129 -4
View File
@@ -1880,6 +1880,89 @@
figlet "1.7.0"
ts-node "10.9.2"
"@parcel/watcher-android-arm64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84"
integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==
"@parcel/watcher-darwin-arm64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34"
integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==
"@parcel/watcher-darwin-x64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020"
integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==
"@parcel/watcher-freebsd-x64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8"
integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==
"@parcel/watcher-linux-arm-glibc@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d"
integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==
"@parcel/watcher-linux-arm64-glibc@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7"
integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==
"@parcel/watcher-linux-arm64-musl@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635"
integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==
"@parcel/watcher-linux-x64-glibc@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39"
integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==
"@parcel/watcher-linux-x64-musl@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16"
integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==
"@parcel/watcher-win32-arm64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc"
integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==
"@parcel/watcher-win32-ia32@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7"
integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==
"@parcel/watcher-win32-x64@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf"
integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==
"@parcel/watcher@^2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8"
integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==
dependencies:
detect-libc "^1.0.3"
is-glob "^4.0.3"
micromatch "^4.0.5"
node-addon-api "^7.0.0"
optionalDependencies:
"@parcel/watcher-android-arm64" "2.4.1"
"@parcel/watcher-darwin-arm64" "2.4.1"
"@parcel/watcher-darwin-x64" "2.4.1"
"@parcel/watcher-freebsd-x64" "2.4.1"
"@parcel/watcher-linux-arm-glibc" "2.4.1"
"@parcel/watcher-linux-arm64-glibc" "2.4.1"
"@parcel/watcher-linux-arm64-musl" "2.4.1"
"@parcel/watcher-linux-x64-glibc" "2.4.1"
"@parcel/watcher-linux-x64-musl" "2.4.1"
"@parcel/watcher-win32-arm64" "2.4.1"
"@parcel/watcher-win32-ia32" "2.4.1"
"@parcel/watcher-win32-x64" "2.4.1"
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
@@ -3409,7 +3492,7 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/node@*", "@types/node@20.16.10":
"@types/node@*":
version "20.16.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.10.tgz#0cc3fdd3daf114a4776f54ba19726a01c907ef71"
integrity sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==
@@ -3426,7 +3509,7 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==
"@types/react-dom@*", "@types/react-dom@18.3.0":
"@types/react-dom@*":
version "18.3.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0"
integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==
@@ -4363,6 +4446,13 @@ cheerio@^1.0.0:
undici "^6.19.5"
whatwg-mimetype "^4.0.0"
chokidar@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41"
integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==
dependencies:
readdirp "^4.0.1"
chromatic@11.7.1:
version "11.7.1"
resolved "https://registry.yarnpkg.com/chromatic/-/chromatic-11.7.1.tgz#9de59dd9d0e2a847627bccd959f05881335b524e"
@@ -4797,6 +4887,11 @@ dequal@^2.0.2, dequal@^2.0.3:
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
@@ -6171,6 +6266,11 @@ ignore@^5.2.0, ignore@^5.3.1, ignore@^5.3.2:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
immutable@^4.0.0:
version "4.3.7"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381"
integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==
import-fresh@^3.2.1, import-fresh@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@@ -7278,7 +7378,7 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4, micromatch@^4.0.8:
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
@@ -7400,6 +7500,11 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-addon-api@^7.0.0:
version "7.1.1"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
node-fetch@2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
@@ -8154,6 +8259,11 @@ readable-stream@~2.3.6:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readdirp@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a"
integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==
redent@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
@@ -8375,6 +8485,16 @@ safe-regex-test@^1.0.3:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sass@^1.80.3:
version "1.80.3"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.80.3.tgz#3f63dd527647d2b3de35f36acb971bda80517423"
integrity sha512-ptDWyVmDMVielpz/oWy3YP3nfs7LpJTHIJZboMVs8GEC9eUmtZTZhMHlTW98wY4aEorDfjN38+Wr/XjskFWcfA==
dependencies:
"@parcel/watcher" "^2.4.1"
chokidar "^4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
saxes@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5"
@@ -8492,6 +8612,11 @@ sort-keys@^5.0.0:
dependencies:
is-plain-obj "^4.0.0"
"source-map-js@>=0.6.2 <2.0.0":
version "1.2.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
@@ -9134,7 +9259,7 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
typescript@*, typescript@5.6.2, typescript@^5.0.4:
typescript@*, typescript@^5.0.4:
version "5.6.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0"
integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==
@@ -1,7 +1,7 @@
image:
repository: lasuite/people-backend
pullPolicy: Always
tag: "v1.3.1"
tag: "v1.4.1"
backend:
migrateJobAnnotations:
@@ -113,7 +113,7 @@ frontend:
image:
repository: lasuite/people-frontend
pullPolicy: Always
tag: "v1.3.1"
tag: "v1.4.1"
ingress:
enabled: true
@@ -1,7 +1,7 @@
image:
repository: lasuite/people-backend
pullPolicy: Always
tag: "v1.3.1"
tag: "v1.4.1"
backend:
migrateJobAnnotations:
@@ -113,7 +113,7 @@ frontend:
image:
repository: lasuite/people-frontend
pullPolicy: Always
tag: "v1.3.1"
tag: "v1.4.1"
ingress:
enabled: true