Compare commits

..

10 Commits

Author SHA1 Message Date
Nathan Panchout
25f0914a8b wip 2024-11-14 17:09:35 +01:00
Nathan Panchout
4a4953b344 wip 2024-11-14 14:39:43 +01:00
Nathan Panchout
8268b26d7a 📱(frontend) make left panel responsive
We modify the left panel so that when the value changes in the
useResponsiveStore it is displayed on the screen
2024-11-14 08:59:44 +01:00
Nathan Panchout
61c093cb54 📱(frontend) update header for the new responsive layout [FIRST_COMMIT_HEADER]
The new version of the responsive layout adds a burger menu to show
the left-panel  with a slide-in animation.
We move the logout and language change button in this responsive panel.
2024-11-14 08:57:40 +01:00
Nathan Panchout
7a072e902d (frontend) update tests
Some minor changes have been integrated into the list of documents.
The tests must therefore be adapted accordingly.
2024-11-13 17:33:25 +01:00
Nathan Panchout
7d14309032 💄(frontend) add left panel
In the new interface there is a new left panel. We implement it and add it
to the MainLayout
2024-11-13 17:33:25 +01:00
Nathan Panchout
d523493fa9 💄(frontend) add cunningham tokens
In order to use the spaces and grays of the DSFR,
we update the cunningham.ts file
2024-11-13 17:33:25 +01:00
Nathan Panchout
9b33a1f464 (frontend) implement new UI
This branch is a transition branch to gradually merge the new UI.
2024-11-12 17:58:34 +01:00
Anthony LC
5ee6a43f08 (frontend) add useBroadcastStore
Add the useBroadcastStore.
It will give us the ability to easily
broadcast actions to all connected clients.

In this case, we requery the doc to everyone
when a change relative to the doc rights is made.
2024-11-09 10:21:24 +01:00
Anthony LC
8bd83cbfcd 🚚(frontend) move useDocStore to doc-management
We want to make more accessible the doc store
to every feature, so we move it to the
doc-management folder.
2024-11-09 10:21:24 +01:00
91 changed files with 1685 additions and 2938 deletions

View File

@@ -12,7 +12,10 @@ and this project adheres to
## Added
- 🌐(frontend) Add German translation #255
- 🧑‍💻(helm) demo helm config #404
- ✨(frontend) Add a broadcast store #387
- ✨(frontend) WIP: New ui
- 💄(frontend) Add left panel
- 💄(frontend) update header layout #421
## Changed
@@ -23,6 +26,7 @@ and this project adheres to
- 🦺(backend) add comma to sub regex #408
- 🐛(editor) collaborative user tag hidden when read only #385
- 🐛(frontend) user have view access when revoked #387
## [1.7.0] - 2024-10-24

View File

@@ -36,7 +36,7 @@ export const createDoc = async (
await page
.getByRole('button', {
name: 'Create a new document',
name: 'New doc',
})
.click();

View File

@@ -86,7 +86,7 @@ test.describe('Doc Header', () => {
test('it updates the title doc from editor heading', async ({ page }) => {
await page
.getByRole('button', {
name: 'Create a new document',
name: 'New doc',
})
.click();
@@ -159,9 +159,7 @@ test.describe('Doc Header', () => {
page.getByText('The document has been deleted.'),
).toBeVisible();
await expect(
page.getByRole('button', { name: 'Create a new document' }),
).toBeVisible();
await expect(page.getByRole('button', { name: 'New do' })).toBeVisible();
const row = page
.getByLabel('Datagrid of the documents page 1')
@@ -414,7 +412,7 @@ test.describe('Doc Header', () => {
// create page and navigate to it
await page
.getByRole('button', {
name: 'Create a new document',
name: 'New doc',
})
.click();
@@ -449,7 +447,7 @@ test.describe('Doc Header', () => {
// create page and navigate to it
await page
.getByRole('button', {
name: 'Create a new document',
name: 'New doc',
})
.click();

View File

@@ -9,7 +9,7 @@ test.describe('Doc Routing', () => {
test('Check the presence of the meta tag noindex', async ({ page }) => {
const buttonCreateHomepage = page.getByRole('button', {
name: 'Create a new document',
name: 'New doc',
});
await expect(buttonCreateHomepage).toBeVisible();
@@ -27,7 +27,7 @@ test.describe('Doc Routing', () => {
await expect(page).toHaveURL('/');
const buttonCreateHomepage = page.getByRole('button', {
name: 'Create a new document',
name: 'New doc',
});
await expect(buttonCreateHomepage).toBeVisible();

View File

@@ -36,6 +36,7 @@ test.describe('Doc Table Content', () => {
await page.getByRole('button', { name: 'Strike' }).click();
await page.locator('.bn-block-outer').first().click();
await editor.click();
await page.locator('.bn-block-outer').last().click();
// Create space to fill the viewport

View File

@@ -1,77 +0,0 @@
import { expect, test } from '@playwright/test';
import { goToGridDoc } from './common';
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test.describe('Footer', () => {
test('checks all the elements are visible', async ({ page }) => {
const footer = page.locator('footer').first();
await expect(footer.getByAltText('Gouvernement Logo')).toBeVisible();
await expect(
footer.getByRole('link', { name: 'legifrance.gouv.fr' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'info.gouv.fr' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'service-public.fr' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'data.gouv.fr' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'Legal Notice' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'Personal data and cookies' }),
).toBeVisible();
await expect(
footer.getByRole('link', { name: 'Accessibility' }),
).toBeVisible();
await expect(
footer.getByText(
'Unless otherwise stated, all content on this site is under licence',
),
).toBeVisible();
});
test('checks footer is not visible on doc editor', async ({ page }) => {
await expect(page.locator('footer')).toBeVisible();
await goToGridDoc(page);
await expect(page.locator('footer')).toBeHidden();
});
const legalPages = [
{ name: 'Legal Notice', url: '/legal-notice/' },
{ name: 'Personal data and cookies', url: '/personal-data-cookies/' },
{ name: 'Accessibility', url: '/accessibility/' },
];
for (const { name, url } of legalPages) {
test(`checks ${name} page`, async ({ page }) => {
const footer = page.locator('footer').first();
await footer.getByRole('link', { name }).click();
await expect(
page
.getByRole('heading', {
name,
})
.first(),
).toBeVisible();
await expect(page).toHaveURL(url);
});
}
});

View File

@@ -75,29 +75,13 @@ test.describe('Header mobile', () => {
test('it checks the header when mobile', async ({ page }) => {
const header = page.locator('header').first();
await expect(header.getByLabel('Open the header menu')).toBeVisible();
await expect(
header.getByRole('button', {
name: 'Les services de La Suite numérique',
}),
header.getByRole('link', { name: 'Docs Logo Docs' }),
).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Logout',
}),
).toBeHidden();
await expect(page.getByText('English')).toBeHidden();
await header.getByLabel('Open the header menu').click();
await expect(
page.getByRole('button', {
name: 'Logout',
}),
header.getByRole('button', { name: 'Les services de La Suite numé' }),
).toBeVisible();
await expect(page.getByText('English')).toBeVisible();
});
});

View File

@@ -6,11 +6,7 @@ test.beforeEach(async ({ page }) => {
test.describe('Language', () => {
test('checks the language picker', async ({ page }) => {
await expect(
page.getByRole('button', {
name: 'Create a new document',
}),
).toBeVisible();
await expect(page.getByLabel('Logout')).toBeVisible();
const header = page.locator('header').first();
await header.getByRole('combobox').getByText('English').click();
@@ -19,11 +15,7 @@ test.describe('Language', () => {
header.getByRole('combobox').getByText('Français'),
).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Créer un nouveau document',
}),
).toBeVisible();
await expect(page.getByLabel('Se déconnecter')).toBeVisible();
await header.getByRole('combobox').getByText('Français').click();
await header.getByRole('option', { name: 'Deutsch' }).click();
@@ -31,11 +23,7 @@ test.describe('Language', () => {
header.getByRole('combobox').getByText('Deutsch'),
).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Neues Dokument erstellen',
}),
).toBeVisible();
await expect(page.getByLabel('Abmelden')).toBeVisible();
});
test('checks that backend uses the same language as the frontend', async ({

View File

@@ -0,0 +1,48 @@
import { expect, test } from '@playwright/test';
test.describe('Left panel desktop', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('checks all the elements are visible', async ({ page }) => {
await expect(page.getByTestId('left-panel-desktop')).toBeVisible();
await expect(page.getByTestId('left-panel-mobile')).toBeHidden();
await expect(page.getByRole('button', { name: 'house' })).toBeVisible();
await expect(page.getByRole('button', { name: 'New doc' })).toBeVisible();
});
});
test.describe('Left panel mobile', () => {
test.use({ viewport: { width: 500, height: 1200 } });
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('checks all the desktop elements are hidden and all mobile elements are visible', async ({
page,
}) => {
await expect(page.getByTestId('left-panel-desktop')).toBeHidden();
await expect(page.getByTestId('left-panel-mobile')).not.toBeInViewport();
const header = page.locator('header').first();
const homeButton = page.getByRole('button', { name: 'house' });
const newDocButton = page.getByRole('button', { name: 'New doc' });
const languageButton = page.getByRole('combobox', { name: 'Language' });
const logoutButton = page.getByRole('button', { name: 'Logout' });
await expect(homeButton).not.toBeInViewport();
await expect(newDocButton).not.toBeInViewport();
await expect(languageButton).not.toBeInViewport();
await expect(logoutButton).not.toBeInViewport();
await header.getByLabel('Open the header menu').click();
await expect(page.getByTestId('left-panel-mobile')).toBeInViewport();
await expect(homeButton).toBeInViewport();
await expect(newDocButton).toBeInViewport();
await expect(languageButton).toBeInViewport();
await expect(logoutButton).toBeInViewport();
});
});

View File

@@ -3,24 +3,30 @@ const config = {
default: {
theme: {
colors: {
'card-border': '#ededed',
'card-border': '#E5E5E5',
'primary-bg': '#FAFAFA',
'primary-100': '#EDF5FA',
'primary-150': '#E5EEFA',
'info-150': '#E5EEFA',
'greyscale-000': '#fff',
'greyscale-1000': '#161616',
},
font: {
sizes: {
ml: '0.938rem',
xl: '1.50rem',
t: '0.6875rem',
s: '0.75rem',
h1: '2.2rem',
h2: '1.7rem',
h3: '1.37rem',
h4: '1.15rem',
h5: '1rem',
h6: '0.87rem',
xl: '20px',
lg: '18px',
md: '16px',
sm: '14px',
xs: '12px',
h1: '32px',
h2: '28px',
h3: '24px',
h4: '22px',
h5: '20px',
h6: '18px',
},
weights: {
thin: 100,
@@ -34,6 +40,21 @@ const config = {
auto: 'auto',
bx: '2.2rem',
full: '100%',
'050V': '2px',
'100V': '4px',
'150V': '6px',
'100W': '8px',
'300V': '12px',
'200W': '16px',
'300W': '24px',
'400W': '32px',
'500W': '40px',
'600W': '48px',
'700W': '56px',
'800W': '64px',
'900W': '72px',
'1200W': '96px',
'1500W': '120px',
},
breakpoints: {
xxs: '320px',
@@ -46,6 +67,11 @@ const config = {
alt: '',
},
},
global: {
hover: {
'greyscale-100': '#055fd214',
},
},
components: {
datagrid: {
header: {
@@ -104,7 +130,7 @@ const config = {
focus: 'var(--c--components--forms-select--border-radius)',
},
'font-size': 'var(--c--theme--font--sizes--ml)',
'menu-background-color': '#ffffff',
'menu-background-color': '#fff',
'item-background-color': {
hover: 'var(--c--theme--colors--primary-300)',
},
@@ -126,7 +152,7 @@ const config = {
},
},
modal: {
'background-color': '#ffffff',
'background-color': '#fff',
},
button: {
'border-radius': {
@@ -196,6 +222,23 @@ const config = {
},
dsfr: {
theme: {
spacings: {
'050V': '2px',
'100V': '4px',
'150V': '6px',
'100W': '8px',
'300V': '12px',
'200W': '16px',
'300W': '24px',
'400W': '32px',
'500W': '40px',
'600W': '48px',
'700W': '56px',
'800W': '64px',
'900W': '72px',
'1200W': '96px',
'1500W': '120px',
},
colors: {
'card-border': '#ededed',
'primary-text': '#000091',
@@ -209,7 +252,7 @@ const config = {
'primary-700': '#272747',
'primary-800': '#21213f',
'primary-900': '#1c1a36',
'secondary-text': '#FFFFFF',
'secondary-text': '#fff',
'secondary-100': '#fee9ea',
'secondary-200': '#fedfdf',
'secondary-300': '#fdbfbf',
@@ -220,16 +263,16 @@ const config = {
'secondary-800': '#341f1f',
'secondary-900': '#2b1919',
'greyscale-text': '#303C4B',
'greyscale-000': '#f6f6f6',
'greyscale-100': '#eeeeee',
'greyscale-200': '#e5e5e5',
'greyscale-300': '#e1e1e1',
'greyscale-400': '#dddddd',
'greyscale-500': '#cecece',
'greyscale-600': '#7b7b7b',
'greyscale-700': '#666666',
'greyscale-800': '#2a2a2a',
'greyscale-900': '#1e1e1e',
'greyscale-000': '#fff',
'greyscale-050': '#F6F6F6',
'greyscale-100': '#eee',
'greyscale-200': '#E5E5E5',
'greyscale-250': '#ddd',
'greyscale-300': '#CECECE',
'greyscale-400': '#929292',
'greyscale-500': '#666',
'greyscale-700': '#3A3A3A',
'greyscale-1000': '#161616',
'success-text': '#1f8d49',
'success-100': '#dffee6',
'success-200': '#b8fec9',
@@ -276,6 +319,22 @@ const config = {
accent: 'Marianne',
base: 'Marianne',
},
size: {
ml: '0.938rem',
t: '0.6875rem',
s: '0.75rem',
xl: '20px',
lg: '18px',
md: '16px',
sm: '14px',
xs: '12px',
h1: '32px',
h2: '28px',
h3: '24px',
h4: '22px',
h5: '20px',
h6: '18px',
},
},
logo: {
src: '/assets/logo-gouv.svg',
@@ -297,9 +356,9 @@ const config = {
'color-hover': '#1212ff',
'color-active': '#2323ff',
},
color: '#ffffff',
'color-hover': '#ffffff',
'color-active': '#ffffff',
color: '#fff',
'color-hover': '#fff',
'color-active': '#fff',
},
'primary-text': {
background: {
@@ -363,7 +422,7 @@ const config = {
},
'forms-input': {
'border-radius': '4px',
'background-color': '#ffffff',
'background-color': '#fff',
'border-color': 'var(--c--theme--colors--primary-text)',
'box-shadow-color': 'var(--c--theme--colors--primary-text)',
'value-color': 'var(--c--theme--colors--primary-text)',
@@ -381,7 +440,7 @@ const config = {
'item-font-size': '14px',
'border-radius': '4px',
'border-radius-hover': '4px',
'background-color': '#ffffff',
'background-color': '#fff',
'border-color': 'var(--c--theme--colors--primary-text)',
'border-color-hover': 'var(--c--theme--colors--primary-text)',
'box-shadow-color': 'var(--c--theme--colors--primary-text)',

View File

@@ -33,6 +33,7 @@
"react-dom": "*",
"react-i18next": "15.0.3",
"react-select": "5.8.1",
"react-intersection-observer": "9.13.1",
"styled-components": "6.1.13",
"y-protocols": "1.0.6",
"yjs": "*",

View File

@@ -1,26 +0,0 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import { AppWrapper } from '@/tests/utils';
import Page from '../pages';
jest.mock('next/navigation', () => ({
useRouter() {
return {
push: jest.fn(),
};
},
}));
describe('Page', () => {
it('checks Page rendering', () => {
render(<Page />, { wrapper: AppWrapper });
expect(
screen.getByRole('button', {
name: /Create a new document/i,
}),
).toBeInTheDocument();
});
});

View File

@@ -1,6 +1,6 @@
import { ComponentPropsWithRef, ReactHTML } from 'react';
import styled from 'styled-components';
import { CSSProperties } from 'styled-components/dist/types';
import { CSSProperties, RuleSet } from 'styled-components/dist/types';
import {
MarginPadding,
@@ -15,7 +15,7 @@ export interface BoxProps {
$align?: CSSProperties['alignItems'];
$background?: CSSProperties['background'];
$color?: CSSProperties['color'];
$css?: string;
$css?: string | RuleSet<object>;
$direction?: CSSProperties['flexDirection'];
$display?: CSSProperties['display'];
$effect?: 'show' | 'hide';
@@ -45,6 +45,7 @@ export type BoxType = ComponentPropsWithRef<typeof Box>;
export const Box = styled('div')<BoxProps>`
display: flex;
flex-direction: column;
${({ $align }) => $align && `align-items: ${$align};`}
${({ $background }) => $background && `background: ${$background};`}
${({ $color }) => $color && `color: ${$color};`}
@@ -73,7 +74,7 @@ export const Box = styled('div')<BoxProps>`
${({ $transition }) => $transition && `transition: ${$transition};`}
${({ $width }) => $width && `width: ${$width};`}
${({ $wrap }) => $wrap && `flex-wrap: ${$wrap};`}
${({ $css }) => $css && `${$css};`}
${({ $css }) => $css && (typeof $css === 'string' ? `${$css};` : $css)}
${({ $zIndex }) => $zIndex && `z-index: ${$zIndex};`}
${({ $effect }) => {
let effect;

View File

@@ -16,7 +16,7 @@ export const Card = ({
$background="white"
$radius="4px"
$css={`
box-shadow: 2px 2px 5px ${colorsTokens()['greyscale-300']};
border: 1px solid ${colorsTokens()['card-border']};
${$css}
`}

View File

@@ -1,9 +1,4 @@
import React, {
PropsWithChildren,
ReactNode,
useEffect,
useState,
} from 'react';
import { PropsWithChildren, ReactNode, useEffect, useState } from 'react';
import { Button, DialogTrigger, Popover } from 'react-aria-components';
import styled from 'styled-components';
@@ -29,7 +24,7 @@ const StyledButton = styled(Button)`
text-wrap: nowrap;
`;
interface DropButtonProps {
export interface DropButtonProps {
button: ReactNode;
isOpen?: boolean;
onOpenChange?: (isOpen: boolean) => void;

View File

@@ -1,6 +1,14 @@
import { Text, TextType } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
type Props = {
iconName: string;
className?: string;
};
export const Icon = ({ iconName, className }: Props) => {
return <span className={`material-icons ${className}`}>{iconName}</span>;
};
interface IconBGProps extends TextType {
iconName: string;
}

View File

@@ -23,6 +23,7 @@ export interface TextProps extends BoxProps {
$weight?: CSSProperties['fontWeight'];
$textAlign?: CSSProperties['textAlign'];
$size?: TextSizes | (string & {});
$theme?:
| 'primary'
| 'secondary'
@@ -31,6 +32,7 @@ export interface TextProps extends BoxProps {
| 'warning'
| 'danger'
| 'greyscale';
$variation?:
| 'text'
| '100'
@@ -41,7 +43,8 @@ export interface TextProps extends BoxProps {
| '600'
| '700'
| '800'
| '900';
| '900'
| '1000';
}
export type TextType = ComponentPropsWithRef<typeof Text>;
@@ -63,14 +66,16 @@ export const TextStyled = styled(Box)<TextProps>`
const Text = forwardRef<HTMLElement, ComponentPropsWithRef<typeof TextStyled>>(
({ className, $isMaterialIcon, ...props }, ref) => {
return (
<TextStyled
ref={ref}
as="span"
$theme="greyscale"
$variation="text"
className={`${className || ''}${$isMaterialIcon ? ' material-icons' : ''}`}
{...props}
/>
<>
<TextStyled
ref={ref}
as="span"
$theme={props.$theme ?? 'greyscale'}
$variation={props.$variation ?? 'text'}
className={`${className || ''}${$isMaterialIcon ? ' material-icons' : ''}`}
{...props}
/>
</>
);
},
);

View File

@@ -0,0 +1,87 @@
import { PropsWithChildren, useMemo } from 'react';
import { DropButton, DropButtonProps } from '@/components';
import { Icon } from '@/components/Icon';
import styles from './dropdown-menu.module.scss';
export type DropdownMenuOption = {
icon?: string;
label: string;
callback?: () => void | Promise<unknown>;
danger?: boolean;
show?: boolean;
};
export type DropdownMenuProps = Omit<DropButtonProps, 'button'> & {
options: DropdownMenuOption[];
showArrow?: boolean;
arrowClassname?: string;
};
export const DropdownMenu = ({
options,
children,
showArrow = false,
arrowClassname,
...dropButtonProps
}: PropsWithChildren<DropdownMenuProps>) => {
const showDropdown = useMemo(() => {
let show = false;
options.forEach((option) => {
show = show || (option.show !== undefined ? option.show : true);
});
return show;
}, [options]);
const getButton = () => {
if (!showArrow) {
return children;
}
return (
<div className={styles.withArrowContainer}>
<div>{children}</div>
<Icon
className={arrowClassname ?? 'clr-primary-600'}
iconName={
dropButtonProps.isOpen ? 'arrow_drop_up' : 'arrow_drop_down'
}
/>
</div>
);
};
if (!showDropdown) {
return;
}
return (
<DropButton {...dropButtonProps} button={getButton()}>
<div className={styles.listOption}>
{options.map((option) => {
if (option.show !== undefined && !option.show) {
return;
}
return (
<button
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
dropButtonProps.onOpenChange?.(false);
void option.callback?.();
}}
key={option.label}
className={styles.item}
>
{option.icon && (
<Icon className={styles.itemIcon} iconName={option.icon} />
)}
{option.label}
</button>
);
})}
</div>
</DropButton>
);
};

View File

@@ -0,0 +1,42 @@
.simpleContent {
display: flex;
align-items: center;
gap: var(--c--theme--spacings--st);
}
.listOption {
display: flex;
flex-direction: column;
.item:not(:last-child) {
border-bottom: 1px solid var(--c--theme--colors--greyscale-200);
}
}
.item {
display: flex;
align-items: center;
gap: var(--c--theme--spacings--200W);
border: none;
background-color: white;
font-size: var(--c--theme--font--sizes--sm);
color: var(--c--theme--colors--primary-600);
font-weight: 500;
padding: var(--c--theme--spacings--100W) var(--c--theme--spacings--200W);
width: 100%;
cursor: pointer;
user-select: none;
&:hover {
background-color: var(--c--theme--colors--greyscale-050);
}
.itemIcon {
font-size: 24px;
}
}
.withArrowContainer {
display: flex;
align-items: center;
gap: 5px;
}

View File

@@ -0,0 +1,14 @@
import { useState } from 'react';
export const useDropdownMenu = () => {
const [isOpen, setIsOpen] = useState(false);
const onOpenChange = (isOpen: boolean) => {
setIsOpen(isOpen);
};
return {
isOpen,
onOpenChange,
};
};

View File

@@ -0,0 +1,34 @@
import { useCunninghamTheme } from '@/cunningham';
import { Box } from '../Box';
export enum SeparatorVariant {
LIGHT = 'light',
DARK = 'dark',
}
type Props = {
variant?: SeparatorVariant;
};
export const HorizontalSeparator = ({
variant = SeparatorVariant.LIGHT,
}: Props) => {
const { colorsTokens, themeTokens } = useCunninghamTheme();
const colors = colorsTokens();
const spacings = themeTokens().spacings;
return (
<Box
$css={`
width: 100%;
height: 1px;
margin: ${spacings?.['300W'] ?? '0.5rem'} 0 ;
background-color: ${
variant === SeparatorVariant.LIGHT
? colors['greyscale-200']
: colors['greyscale-800']
};
`}
/>
);
};

View File

@@ -0,0 +1,29 @@
import { PropsWithChildren } from 'react';
import { useCunninghamTheme } from '@/cunningham';
import { Box } from '../Box';
type Props = {
showSeparator?: boolean;
};
export const SeparatedSection = ({
showSeparator = true,
children,
}: PropsWithChildren<Props>) => {
const theme = useCunninghamTheme();
const colors = theme.colorsTokens();
return (
<Box
className="toto"
$padding={{ vertical: '100V' }}
$css={`
padding: 12px 0;
${showSeparator ? `border-bottom: 1px solid ${(colors?.['greyscale-200'] as string) ?? '#E5E5E5'};` : ''}
`}
>
{children}
</Box>
);
};

View File

@@ -13,7 +13,7 @@ export const tokens = {
'secondary-700': '#97A3AE',
'secondary-800': '#757E87',
'secondary-900': '#596067',
'info-text': '#FFFFFF',
'info-text': '#fff',
'info-100': '#EBF2FC',
'info-200': '#8CB5EA',
'info-300': '#5894E1',
@@ -32,7 +32,7 @@ export const tokens = {
'greyscale-700': '#555F6B',
'greyscale-800': '#303C4B',
'greyscale-900': '#0C1A2B',
'greyscale-000': '#FFFFFF',
'greyscale-000': '#fff',
'primary-100': '#EDF5FA',
'primary-200': '#8CB5EA',
'primary-300': '#5894E1',
@@ -69,29 +69,34 @@ export const tokens = {
'danger-700': '#9B0000',
'danger-800': '#780000',
'danger-900': '#5C0000',
'primary-text': '#FFFFFF',
'success-text': '#FFFFFF',
'warning-text': '#FFFFFF',
'danger-text': '#FFFFFF',
'card-border': '#ededed',
'primary-text': '#fff',
'success-text': '#fff',
'warning-text': '#fff',
'danger-text': '#fff',
'card-border': '#E5E5E5',
'primary-bg': '#FAFAFA',
'primary-150': '#E5EEFA',
'info-150': '#E5EEFA',
'greyscale-1000': '#161616',
},
font: {
sizes: {
h1: '2.2rem',
h2: '1.7rem',
h3: '1.37rem',
h4: '1.15rem',
h5: '1rem',
h6: '0.87rem',
h1: '32px',
h2: '28px',
h3: '24px',
h4: '22px',
h5: '20px',
h6: '18px',
l: '1rem',
m: '0.8125rem',
s: '0.75rem',
ml: '0.938rem',
xl: '1.50rem',
t: '0.6875rem',
xl: '20px',
lg: '18px',
md: '16px',
sm: '14px',
xs: '12px',
},
weights: {
thin: 100,
@@ -130,6 +135,21 @@ export const tokens = {
auto: 'auto',
bx: '2.2rem',
full: '100%',
'050V': '2px',
'100V': '4px',
'150V': '6px',
'100W': '8px',
'300V': '12px',
'200W': '16px',
'300W': '24px',
'400W': '32px',
'500W': '40px',
'600W': '48px',
'700W': '56px',
'800W': '64px',
'900W': '72px',
'1200W': '96px',
'1500W': '120px',
},
transitions: {
'ease-in': 'cubic-bezier(0.32, 0, 0.67, 0)',
@@ -202,7 +222,7 @@ export const tokens = {
focus: 'var(--c--components--forms-select--border-radius)',
},
'font-size': 'var(--c--theme--font--sizes--ml)',
'menu-background-color': '#ffffff',
'menu-background-color': '#fff',
'item-background-color': {
hover: 'var(--c--theme--colors--primary-300)',
},
@@ -223,7 +243,7 @@ export const tokens = {
'border-color-hover': 'var(--c--theme--colors--greyscale-200)',
},
},
modal: { 'background-color': '#ffffff' },
modal: { 'background-color': '#fff' },
button: {
'border-radius': {
active: 'var(--c--components--button--border-radius)',
@@ -333,6 +353,23 @@ export const tokens = {
},
dsfr: {
theme: {
spacings: {
'050V': '2px',
'100V': '4px',
'150V': '6px',
'100W': '8px',
'300V': '12px',
'200W': '16px',
'300W': '24px',
'400W': '32px',
'500W': '40px',
'600W': '48px',
'700W': '56px',
'800W': '64px',
'900W': '72px',
'1200W': '96px',
'1500W': '120px',
},
colors: {
'card-border': '#ededed',
'primary-text': '#000091',
@@ -346,7 +383,7 @@ export const tokens = {
'primary-700': '#272747',
'primary-800': '#21213f',
'primary-900': '#1c1a36',
'secondary-text': '#FFFFFF',
'secondary-text': '#fff',
'secondary-100': '#fee9ea',
'secondary-200': '#fedfdf',
'secondary-300': '#fdbfbf',
@@ -357,16 +394,16 @@ export const tokens = {
'secondary-800': '#341f1f',
'secondary-900': '#2b1919',
'greyscale-text': '#303C4B',
'greyscale-000': '#f6f6f6',
'greyscale-100': '#eeeeee',
'greyscale-200': '#e5e5e5',
'greyscale-300': '#e1e1e1',
'greyscale-400': '#dddddd',
'greyscale-500': '#cecece',
'greyscale-600': '#7b7b7b',
'greyscale-700': '#666666',
'greyscale-800': '#2a2a2a',
'greyscale-900': '#1e1e1e',
'greyscale-000': '#fff',
'greyscale-050': '#F6F6F6',
'greyscale-100': '#eee',
'greyscale-200': '#E5E5E5',
'greyscale-250': '#ddd',
'greyscale-300': '#CECECE',
'greyscale-400': '#929292',
'greyscale-500': '#666',
'greyscale-700': '#3A3A3A',
'greyscale-1000': '#161616',
'success-text': '#1f8d49',
'success-100': '#dffee6',
'success-200': '#b8fec9',
@@ -408,7 +445,25 @@ export const tokens = {
'danger-800': '#412121',
'danger-900': '#3a1c1c',
},
font: { families: { accent: 'Marianne', base: 'Marianne' } },
font: {
families: { accent: 'Marianne', base: 'Marianne' },
size: {
ml: '0.938rem',
t: '0.6875rem',
s: '0.75rem',
xl: '20px',
lg: '18px',
md: '16px',
sm: '14px',
xs: '12px',
h1: '32px',
h2: '28px',
h3: '24px',
h4: '22px',
h5: '20px',
h6: '18px',
},
},
logo: {
src: '/assets/logo-gouv.svg',
widthHeader: '110px',
@@ -427,9 +482,9 @@ export const tokens = {
'color-hover': '#1212ff',
'color-active': '#2323ff',
},
color: '#ffffff',
'color-hover': '#ffffff',
'color-active': '#ffffff',
color: '#fff',
'color-hover': '#fff',
'color-active': '#fff',
},
'primary-text': {
background: {
@@ -486,7 +541,7 @@ export const tokens = {
},
'forms-input': {
'border-radius': '4px',
'background-color': '#ffffff',
'background-color': '#fff',
'border-color': 'var(--c--theme--colors--primary-text)',
'box-shadow-color': 'var(--c--theme--colors--primary-text)',
'value-color': 'var(--c--theme--colors--primary-text)',
@@ -502,7 +557,7 @@ export const tokens = {
'item-font-size': '14px',
'border-radius': '4px',
'border-radius-hover': '4px',
'background-color': '#ffffff',
'background-color': '#fff',
'border-color': 'var(--c--theme--colors--primary-text)',
'border-color-hover': 'var(--c--theme--colors--primary-text)',
'box-shadow-color': 'var(--c--theme--colors--primary-text)',

View File

@@ -5,6 +5,7 @@ import { tokens } from './cunningham-tokens';
type Tokens = typeof tokens.themes.default & Partial<typeof tokens.themes.dsfr>;
type ColorsTokens = Tokens['theme']['colors'];
type SpacingsTokens = Tokens['theme']['spacings'];
type ComponentTokens = Tokens['components'];
type Theme = 'default' | 'dsfr';
@@ -13,6 +14,7 @@ interface AuthStore {
setTheme: (theme: Theme) => void;
themeTokens: () => Partial<Tokens['theme']>;
colorsTokens: () => Partial<ColorsTokens>;
spacingsTokens: () => SpacingsTokens;
componentTokens: () => ComponentTokens;
}
@@ -25,6 +27,7 @@ const useCunninghamTheme = create<AuthStore>((set, get) => {
themeTokens: () => currentTheme().theme,
colorsTokens: () => currentTheme().theme.colors,
componentTokens: () => currentTheme().components,
spacingsTokens: () => currentTheme().theme.spacings,
setTheme: (theme: Theme) => {
set({ theme });
},

View File

@@ -14,14 +14,13 @@ import { useTranslation } from 'react-i18next';
import { isAPIError } from '@/api';
import { Box, Text } from '@/components';
import { useDocOptions } from '@/features/docs/doc-management/';
import { useDocOptions, useDocStore } from '@/features/docs/doc-management/';
import {
AITransformActions,
useDocAITransform,
useDocAITranslate,
} from '../api/';
import { useDocStore } from '../stores';
type LanguageTranslate = {
value: string;

View File

@@ -11,12 +11,11 @@ import { useTranslation } from 'react-i18next';
import { Box, TextErrors } from '@/components';
import { mediaUrl } from '@/core';
import { useAuthStore } from '@/core/auth';
import { Doc } from '@/features/docs/doc-management';
import { Version } from '@/features/docs/doc-versioning/';
import { Doc, useDocStore } from '@/features/docs/doc-management';
import { useCreateDocAttachment } from '../api/useCreateDocUpload';
import useSaveDoc from '../hook/useSaveDoc';
import { useDocStore, useHeadingStore } from '../stores';
import { useHeadingStore } from '../stores';
import { randomColor } from '../utils';
import { BlockNoteToolbar } from './BlockNoteToolbar';
@@ -75,40 +74,16 @@ const cssEditor = (readonly: boolean) => `
`;
interface BlockNoteEditorProps {
doc: Doc;
version?: Version;
}
export const BlockNoteEditor = ({ doc, version }: BlockNoteEditorProps) => {
const { createProvider, docsStore } = useDocStore();
const storeId = version?.id || doc.id;
const initialContent = version?.content || doc.content;
const provider = docsStore?.[storeId]?.provider;
useEffect(() => {
if (!provider || provider.document.guid !== storeId) {
createProvider(storeId, initialContent);
}
}, [createProvider, initialContent, provider, storeId]);
if (!provider) {
return null;
}
return <BlockNoteContent doc={doc} provider={provider} storeId={storeId} />;
};
interface BlockNoteContentProps {
doc: Doc;
provider: HocuspocusProvider;
storeId: string;
}
export const BlockNoteContent = ({
export const BlockNoteEditor = ({
doc,
provider,
storeId,
}: BlockNoteContentProps) => {
}: BlockNoteEditorProps) => {
const isVersion = doc.id !== storeId;
const { userData } = useAuthStore();
const { setStore, docsStore } = useDocStore();

View File

@@ -1,13 +1,13 @@
import { Alert, Loader, VariantType } from '@openfun/cunningham-react';
import { useRouter as useNavigate } from 'next/navigation';
import { useRouter } from 'next/router';
import React from 'react';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Card, Text, TextErrors } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { DocHeader } from '@/features/docs/doc-header';
import { Doc } from '@/features/docs/doc-management';
import { Doc, useDocStore } from '@/features/docs/doc-management';
import { Versions, useDocVersion } from '@/features/docs/doc-versioning/';
import { useResponsiveStore } from '@/stores';
@@ -32,6 +32,13 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
const { colorsTokens } = useCunninghamTheme();
const { docsStore } = useDocStore();
const provider = docsStore?.[doc.id]?.provider;
if (!provider) {
return null;
}
return (
<>
<DocHeader doc={doc} versionId={versionId as Versions['version_id']} />
@@ -51,10 +58,10 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
)}
<Box
$background={colorsTokens()['primary-bg']}
$height="100%"
$direction="row"
$width="100%"
$margin={{ all: isMobile ? 'tiny' : 'small', top: 'none' }}
$css="overflow-x: clip;"
$css="overflow-x: clip; flex: 1;"
$position="relative"
>
<Card
@@ -66,7 +73,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
{isVersion ? (
<DocVersionEditor doc={doc} versionId={versionId} />
) : (
<BlockNoteEditor doc={doc} />
<BlockNoteEditor doc={doc} storeId={doc.id} provider={provider} />
)}
{!isMobile && <IconOpenPanelEditor headings={headings} />}
</Card>
@@ -91,9 +98,21 @@ export const DocVersionEditor = ({ doc, versionId }: DocVersionEditorProps) => {
docId: doc.id,
versionId,
});
const { createProvider, docsStore } = useDocStore();
const navigate = useNavigate();
useEffect(() => {
if (!version?.id) {
return;
}
const provider = docsStore?.[version.id]?.provider;
if (!provider || provider.document.guid !== version.id) {
createProvider(version.id, version.content);
}
}, [createProvider, docsStore, version]);
if (isError && error) {
if (error.status === 404) {
navigate.replace(`/404`);
@@ -124,5 +143,11 @@ export const DocVersionEditor = ({ doc, versionId }: DocVersionEditorProps) => {
);
}
return <BlockNoteEditor doc={doc} version={version} />;
const provider = docsStore?.[version.id]?.provider;
if (!provider) {
return null;
}
return <BlockNoteEditor doc={doc} storeId={version.id} provider={provider} />;
};

View File

@@ -1,3 +1,2 @@
export * from './useDocStore';
export * from './useHeadingStore';
export * from './usePanelEditorStore';

View File

@@ -1,5 +1,3 @@
import * as Y from 'yjs';
export const randomColor = () => {
const randomInt = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
@@ -28,20 +26,3 @@ function hslToHex(h: number, s: number, l: number) {
export const toBase64 = (
str: WithImplicitCoercion<ArrayBuffer | SharedArrayBuffer>,
) => Buffer.from(str).toString('base64');
type BasicBlock = {
type: string;
content: string;
};
export const blocksToYDoc = (blocks: BasicBlock[], doc: Y.Doc) => {
const xmlFragment = doc.getXmlFragment('document-store');
blocks.forEach((block) => {
const xmlElement = new Y.XmlElement(block.type);
if (block.content) {
xmlElement.insert(0, [new Y.XmlText(block.content)]);
}
xmlFragment.push([xmlElement]);
});
};

View File

@@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Card, StyledLink, Text } from '@/components';
@@ -32,6 +32,7 @@ export const DocHeader = ({ doc, versionId }: DocHeaderProps) => {
return (
<>
<Card
$width="100%"
$margin={isMobile ? 'tiny' : 'small'}
aria-label={t('It is the card information about the document.')}
>

View File

@@ -18,7 +18,7 @@ import {
useTrans,
useUpdateDoc,
} from '@/features/docs/doc-management';
import { useResponsiveStore } from '@/stores';
import { useBroadcastStore, useResponsiveStore } from '@/stores';
import { isFirefox } from '@/utils/userAgent';
interface DocTitleProps {
@@ -54,6 +54,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
const headingText = headings?.[0]?.contentText;
const debounceRef = useRef<NodeJS.Timeout>();
const { isMobile } = useResponsiveStore();
const { broadcast } = useBroadcastStore();
const { mutate: updateDoc } = useUpdateDoc({
listInvalideQueries: [KEY_DOC, KEY_LIST_DOC],
@@ -61,6 +62,9 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
if (data.title !== untitledDocument) {
toast(t('Document title updated successfully'), VariantType.SUCCESS);
}
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${data.id}`);
},
});

View File

@@ -8,11 +8,12 @@ import { useTranslation } from 'react-i18next';
import { Box, DropButton, IconOptions } from '@/components';
import { useAuthStore } from '@/core';
import { useDocStore, usePanelEditorStore } from '@/features/docs/doc-editor/';
import { usePanelEditorStore } from '@/features/docs/doc-editor/';
import {
Doc,
ModalRemoveDoc,
ModalShare,
useDocStore,
} from '@/features/docs/doc-management';
import { useResponsiveStore } from '@/stores';

View File

@@ -14,8 +14,7 @@ import { t } from 'i18next';
import { useEffect, useMemo, useState } from 'react';
import { Box, Text } from '@/components';
import { useDocStore } from '@/features/docs/doc-editor/';
import { Doc } from '@/features/docs/doc-management';
import { Doc, useDocStore } from '@/features/docs/doc-management';
import { useExport } from '../api/useExport';
import { TemplatesOrdering, useTemplates } from '../api/useTemplates';

View File

@@ -1,4 +1,8 @@
import { UseQueryOptions, useQuery } from '@tanstack/react-query';
import {
UseQueryOptions,
useInfiniteQuery,
useQuery,
} from '@tanstack/react-query';
import { APIError, APIList, errorCauses, fetchAPI } from '@/api';
@@ -52,3 +56,14 @@ export function useDocs(
...queryConfig,
});
}
export const useInfiniteDocs = (params: DocsParams) => {
return useInfiniteQuery({
initialPageParam: 1,
queryKey: [KEY_LIST_DOC, 'infinite', params],
queryFn: ({ pageParam }) => getDocs({ ...params, page: pageParam }),
getNextPageParam: (lastPage, allPages) => {
return lastPage.next ? allPages.length + 1 : undefined;
},
});
};

View File

@@ -1,7 +1,8 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { APIError, errorCauses, fetchAPI } from '@/api';
import { Doc } from '@/features/docs';
import { Doc, KEY_DOC } from '@/features/docs/doc-management';
import { useBroadcastStore } from '@/stores';
export type UpdateDocLinkParams = Pick<Doc, 'id'> &
Partial<Pick<Doc, 'link_role' | 'link_reach'>>;
@@ -37,14 +38,20 @@ export function useUpdateDocLink({
listInvalideQueries,
}: UpdateDocLinkProps = {}) {
const queryClient = useQueryClient();
const { broadcast } = useBroadcastStore();
return useMutation<Doc, APIError, UpdateDocLinkParams>({
mutationFn: updateDocLink,
onSuccess: (data) => {
onSuccess: (data, variable) => {
listInvalideQueries?.forEach((queryKey) => {
void queryClient.resetQueries({
queryKey: [queryKey],
});
});
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${variable.id}`);
onSuccess?.(data);
},
});

View File

@@ -0,0 +1,9 @@
<svg width="32" height="36" viewBox="0 0 32 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.01394" y="1.23611" width="25.9722" height="33.5278" rx="3.54167" fill="white"/>
<rect x="2.01394" y="1.23611" width="25.9722" height="33.5278" rx="3.54167" stroke="#DCDCFC" stroke-width="0.472222"/>
<path d="M6.5 8.55556H15" stroke="#6A6AF4" stroke-width="1.88889" stroke-linecap="round"/>
<path d="M6.5 11.3889H23.5M6.5 14.2222H23.5M6.5 17.0556H23.5M6.5 19.8889H23.5M6.5 22.7222H20.6667" stroke="#CACAFB" stroke-width="1.88889" stroke-linecap="round"/>
<rect x="7" y="10" width="16" height="16" rx="8" fill="#6A6AF4"/>
<rect x="7" y="10" width="16" height="16" rx="8" stroke="white" stroke-width="1.5"/>
<path d="M16.8 18L18 19.2V20.1H15.45V22.95L15 23.4L14.55 22.95V20.1H12V19.2L13.2 18V14.7H12.6V13.8H17.4V14.7H16.8V18Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 853 B

View File

@@ -0,0 +1,6 @@
<svg width="28" height="34" viewBox="0 0 28 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1.01394" y="0.236111" width="25.9722" height="33.5278" rx="3.54167" fill="white"/>
<rect x="1.01394" y="0.236111" width="25.9722" height="33.5278" rx="3.54167" stroke="#DCDCFC" stroke-width="0.472222"/>
<path d="M5.5 7.55554H14" stroke="#6A6AF4" stroke-width="1.88889" stroke-linecap="round"/>
<path d="M5.5 10.3889H22.5M5.5 13.2222H22.5M5.5 16.0556H22.5M5.5 18.8889H22.5M5.5 21.7222H22.5M5.5 24.5556H22.5M5.5 27.3889H22.5M5.5 30.2222H22.5M5.5 33.0556H22.5" stroke="#CACAFB" stroke-width="1.88889" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@@ -0,0 +1,60 @@
import { ReactNode } from 'react';
import styled, { css } from 'styled-components';
import { Box, Text } from '@/components';
import { Doc } from '@/features/docs';
import PinnedDocumentIcon from '@/features/docs/doc-management/assets/pinned-document.svg';
import SimpleFileIcon from '@/features/docs/doc-management/assets/simple-document.svg';
const ItemContainer = styled(Box)`
display: flex;
flex-direction: row;
align-items: center;
gap: var(--c--theme--spacings--100W);
border-radius: var(--c--theme--spacings--100V);
padding: var(--c--theme--spacings--150V);
cursor: pointer;
`;
const ItemTextCss = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: initial;
display: -webkit-box;
line-clamp: 1;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
`;
type Props = {
doc: Doc;
isPinned?: boolean;
subText?: ReactNode | string;
};
export const SimpleDocItem = ({ doc, isPinned = false, subText }: Props) => {
return (
<ItemContainer>
<Box
$css={`
background-color: transparent;
filter: drop-shadow(0px 2px 2px rgba(0, 0, 0, 0.05));
display: flex;
align-items: center;
`}
>
{isPinned ? <PinnedDocumentIcon /> : <SimpleFileIcon />}
</Box>
<div>
<Text $weight={500} $variation="1000" $size="sm" $css={ItemTextCss}>
{doc.title}
</Text>
<Text $variation="500" $size="xs" $css={ItemTextCss}>
{subText ??
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vel ante libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed imperdiet neque quam, sed euismod metus mollis ut. '}
</Text>
</div>
</ItemContainer>
);
};

View File

@@ -1,5 +1,6 @@
export * from './api';
export * from './components';
export * from './hooks';
export * from './stores';
export * from './types';
export * from './utils';

View File

@@ -0,0 +1 @@
export * from './useDocStore';

View File

@@ -4,9 +4,7 @@ import * as Y from 'yjs';
import { create } from 'zustand';
import { providerUrl } from '@/core';
import { Base64, Doc } from '@/features/docs/doc-management';
import { blocksToYDoc } from '../utils';
import { Base64, Doc, blocksToYDoc } from '@/features/docs/doc-management';
interface DocStore {
provider: HocuspocusProvider;

View File

@@ -1,3 +1,5 @@
import * as Y from 'yjs';
import { Doc, Role } from './types';
export const currentDocRole = (abilities: Doc['abilities']): Role => {
@@ -9,3 +11,20 @@ export const currentDocRole = (abilities: Doc['abilities']): Role => {
? Role.EDITOR
: Role.READER;
};
type BasicBlock = {
type: string;
content: string;
};
export const blocksToYDoc = (blocks: BasicBlock[], doc: Y.Doc) => {
const xmlFragment = doc.getXmlFragment('document-store');
blocks.forEach((block) => {
const xmlElement = new Y.XmlElement(block.type);
if (block.content) {
xmlElement.insert(0, [new Y.XmlText(block.content)]);
}
xmlFragment.push([xmlElement]);
});
};

View File

@@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, BoxButton, Text } from '@/components';
import { HeadingBlock, useDocStore } from '@/features/docs/doc-editor';
import { Doc } from '@/features/docs/doc-management';
import { HeadingBlock } from '@/features/docs/doc-editor';
import { Doc, useDocStore } from '@/features/docs/doc-management';
import { useResponsiveStore } from '@/stores';
import { Heading } from './Heading';
@@ -49,7 +49,7 @@ export const TableContent = ({ doc, headings }: TableContentProps) => {
}
};
window.addEventListener('scroll', () => {
document.getElementById('mainContent')?.addEventListener('scroll', () => {
setTimeout(() => {
handleScroll();
}, 300);

View File

@@ -11,8 +11,8 @@ import { useRouter } from 'next/navigation';
import * as Y from 'yjs';
import { Box, Text } from '@/components';
import { toBase64, useDocStore } from '@/features/docs/doc-editor';
import { Doc, useUpdateDoc } from '@/features/docs/doc-management';
import { toBase64 } from '@/features/docs/doc-editor';
import { Doc, useDocStore, useUpdateDoc } from '@/features/docs/doc-management';
import { KEY_LIST_DOC_VERSIONS } from '../api/useDocVersions';
import { Versions } from '../types';

View File

@@ -0,0 +1,14 @@
import { Doc } from '../../doc-management';
import { SimpleDocItem } from '../../doc-management/components/items/SimpleDocItem';
type Props = {
doc: Doc;
};
export const DocGridListItem = ({ doc }: Props) => {
return (
<div>
<SimpleDocItem doc={doc} />
</div>
);
};

View File

@@ -1,40 +0,0 @@
import { Button } from '@openfun/cunningham-react';
import { useRouter } from 'next/navigation';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Box } from '@/components';
import { useCreateDoc, useTrans } from '@/features/docs/doc-management/';
import { useResponsiveStore } from '@/stores';
import { DocsGrid } from './DocsGrid';
export const DocsGridContainer = () => {
const { t } = useTranslation();
const { untitledDocument } = useTrans();
const router = useRouter();
const { isMobile } = useResponsiveStore();
const { mutate: createDoc } = useCreateDoc({
onSuccess: (doc) => {
router.push(`/docs/${doc.id}`);
},
});
const handleCreateDoc = () => {
createDoc({ title: untitledDocument });
};
return (
<Box $overflow="auto">
<Box
$align="flex-end"
$justify="center"
$margin={isMobile ? 'small' : 'big'}
>
<Button onClick={handleCreateDoc}>{t('Create a new document')}</Button>
</Box>
<DocsGrid />
</Box>
);
};

View File

@@ -0,0 +1,75 @@
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, Card, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { useInfiniteDocs } from '@/features/docs/doc-management/api/useDocs';
import { LEFT_PANEL_WIDTH } from '@/features/left-pannel/conf';
import { useResponsiveStore } from '@/stores';
import { DocGridListItem } from './DocGridListItem';
export const DocsGridList = () => {
const { themeTokens, spacingsTokens, colorsTokens } = useCunninghamTheme();
const spacings = spacingsTokens();
const colors = colorsTokens();
const { t } = useTranslation();
const { isResponsive } = useResponsiveStore();
const { data, isFetching, isLoading, fetchNextPage, hasNextPage } =
useInfiniteDocs({
page: 1,
});
const loading = isFetching || isLoading;
const loadMore = (inView: boolean) => {
if (!inView) {
return;
}
void fetchNextPage();
};
return (
<Card
$css={`
width: 960px;
max-width: calc(100dvw - ${isResponsive ? 34 : LEFT_PANEL_WIDTH}px);
padding: ${spacings['300W']};
`}
>
<Text
$margin={{ bottom: `${spacings['100W']}` }}
$css="margin-block: 0"
as="h4"
>
{t('All docs')}
</Text>
<section>
<Box
as="header"
$css={css`
display: flex;
flex-direction: row;
margin-bottom: ${spacings['100W']};
font-size: ${themeTokens().font?.sizes.xs};
color: ${colors['greyscale-500']};
padding-bottom: ${spacings['150V']} ${spacings['100W']};
`}
>
<Box $flex={7}>{t('Name')}</Box>
{!isResponsive && <Box $flex={1}>{t('Update at')}</Box>}
<Box $flex={1} />
</Box>
</section>
<Box $gap={`${spacings['150V']}`}>
{data?.pages.map((currentPage) => {
return currentPage.results.map((doc) => (
<DocGridListItem doc={doc} key={doc.id} />
));
})}
</Box>
</Card>
);
};

View File

@@ -1 +0,0 @@
export * from './DocsGridContainer';

View File

@@ -1 +0,0 @@
export * from './components';

View File

@@ -5,11 +5,13 @@ import { User } from '@/core/auth';
import {
Access,
Doc,
KEY_DOC,
KEY_LIST_DOC,
Role,
} from '@/features/docs/doc-management';
import { KEY_LIST_DOC_ACCESSES } from '@/features/docs/members/members-list';
import { ContentLanguage } from '@/i18n/types';
import { useBroadcastStore } from '@/stores';
import { OptionType } from '../types';
@@ -53,9 +55,11 @@ export const createDocAccess = async ({
export function useCreateDocAccess() {
const queryClient = useQueryClient();
const { broadcast } = useBroadcastStore();
return useMutation<Access, APIError, CreateDocAccessParams>({
mutationFn: createDocAccess,
onSuccess: () => {
onSuccess: (_data, variable) => {
void queryClient.resetQueries({
queryKey: [KEY_LIST_DOC],
});
@@ -65,6 +69,9 @@ export function useCreateDocAccess() {
void queryClient.resetQueries({
queryKey: [KEY_LIST_DOC_ACCESSES],
});
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${variable.docId}`);
},
});
}

View File

@@ -7,6 +7,7 @@ import {
import { APIError, errorCauses, fetchAPI } from '@/api';
import { KEY_DOC, KEY_LIST_DOC } from '@/features/docs/doc-management';
import { KEY_LIST_USER } from '@/features/docs/members/members-add';
import { useBroadcastStore } from '@/stores';
import { KEY_LIST_DOC_ACCESSES } from './useDocAccesses';
@@ -39,6 +40,8 @@ type UseDeleteDocAccessOptions = UseMutationOptions<
export const useDeleteDocAccess = (options?: UseDeleteDocAccessOptions) => {
const queryClient = useQueryClient();
const { broadcast } = useBroadcastStore();
return useMutation<void, APIError, DeleteDocAccessProps>({
mutationFn: deleteDocAccess,
...options,
@@ -49,6 +52,10 @@ export const useDeleteDocAccess = (options?: UseDeleteDocAccessOptions) => {
void queryClient.invalidateQueries({
queryKey: [KEY_DOC],
});
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${variables.docId}`);
void queryClient.resetQueries({
queryKey: [KEY_LIST_DOC],
});

View File

@@ -11,6 +11,7 @@ import {
KEY_LIST_DOC,
Role,
} from '@/features/docs/doc-management';
import { useBroadcastStore } from '@/stores';
import { KEY_LIST_DOC_ACCESSES } from './useDocAccesses';
@@ -49,6 +50,8 @@ type UseUpdateDocAccessOptions = UseMutationOptions<
export const useUpdateDocAccess = (options?: UseUpdateDocAccessOptions) => {
const queryClient = useQueryClient();
const { broadcast } = useBroadcastStore();
return useMutation<Access, APIError, UpdateDocAccessProps>({
mutationFn: updateDocAccess,
...options,
@@ -59,6 +62,10 @@ export const useUpdateDocAccess = (options?: UseUpdateDocAccessOptions) => {
void queryClient.invalidateQueries({
queryKey: [KEY_DOC],
});
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${variables.docId}`);
void queryClient.invalidateQueries({
queryKey: [KEY_LIST_DOC],
});

View File

@@ -1,31 +1,4 @@
<svg viewBox="0 0 36 42" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5_830)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M26.5706 16.681V20.756H9.59985V16.681H26.5706ZM26.5706 23.0467V27.1215H9.59985V23.0467H26.5706ZM19.5375 29.2926V33.3674H9.59985V29.2926H19.5375Z"
fill="#E1000F"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M35.6982 16.7351V33.2911C35.6826 33.2845 35.667 33.2756 35.6492 33.269V37.4663C35.6492 39.8874 33.641 41.8683 31.1867 41.8683H4.461C2.00664 41.8683 -0.00146484 39.8874 -0.00146484 37.4663V4.45137C-0.00146484 2.03028 2.00664 0.0493774 4.461 0.0493774H18.723V4.45137H4.461V37.4663H31.1867V16.7351H35.6982Z"
fill="#000091"
/>
<path
d="M33.9524 0.0360107H23.626C22.6794 0.0360107 21.9049 0.799997 21.9049 1.73376V11.9202C21.9049 12.854 22.6794 13.618 23.626 13.618H33.9524C34.899 13.618 35.6735 12.854 35.6735 11.9202V1.73376C35.6735 0.799997 34.899 0.0360107 33.9524 0.0360107ZM26.6378 6.40257C26.6378 7.10713 26.0613 7.67588 25.347 7.67588H24.4865V8.73697C24.4865 9.08501 24.1939 9.37362 23.8411 9.37362C23.4883 9.37362 23.1957 9.08501 23.1957 8.73697V5.12925C23.1957 4.66237 23.5829 4.28038 24.0562 4.28038H25.347C26.0613 4.28038 26.6378 4.84913 26.6378 5.55369V6.40257ZM30.9405 8.10031C30.9405 8.80488 30.364 9.37362 29.6497 9.37362H27.9286C27.6877 9.37362 27.4984 9.18687 27.4984 8.94919V4.70482C27.4984 4.46713 27.6877 4.28038 27.9286 4.28038H29.6497C30.364 4.28038 30.9405 4.84913 30.9405 5.55369V8.10031ZM34.3827 4.91704C34.3827 5.26507 34.0901 5.55369 33.7373 5.55369H33.0919V6.40257H33.7373C34.0901 6.40257 34.3827 6.69118 34.3827 7.03922C34.3827 7.38726 34.0901 7.67588 33.7373 7.67588H33.0919V8.73697C33.0919 9.08501 32.7993 9.37362 32.4465 9.37362C32.0936 9.37362 31.8011 9.08501 31.8011 8.73697V5.12925C31.8011 4.66237 32.1883 4.28038 32.6616 4.28038H33.7373C34.0901 4.28038 34.3827 4.569 34.3827 4.91704ZM24.4865 6.40257H25.347V5.55369H24.4865V6.40257ZM28.7892 8.10031H29.6497V5.55369H28.7892V8.10031Z"
fill="#000091"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M35.6734 10.0666V13.6574H32.4942V10.0666H35.6734ZM25.0866 0.0441895V3.59171H21.9041V0.0441895H25.0866Z"
fill="#000091"
/>
</g>
<defs>
<clipPath id="clip0_5_830">
<rect width="36" height="42" fill="white" />
</clipPath>
</defs>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.6305 28.8312C22.7983 28.5038 23.9166 27.9062 24.6505 26.8503C25.3749 25.8163 25.5789 24.5047 25.5789 23.2425V4.75099C25.5789 4.42358 25.5611 4.09557 25.5216 3.77148C26.1016 3.99961 26.5486 4.37658 26.8626 4.90239C27.2331 5.50024 27.4184 6.28757 27.4184 7.26435V26.0464C27.4184 27.3684 27.0942 28.3578 26.4458 29.0146C25.7974 29.6714 24.8207 29.9998 23.5155 29.9998H16.4209C16.5889 29.9704 16.7574 29.9401 16.9262 29.909C18.4067 29.6444 19.9713 29.2854 21.6185 28.8346L21.6305 28.8312Z" fill="#C9191E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.58203 25.655V6.8477C4.58203 5.70251 4.88938 4.83519 5.50408 4.24575C6.1272 3.65631 6.95242 3.33212 7.97972 3.27318C9.49542 3.18055 10.9311 3.05425 12.2868 2.89425C13.6425 2.72584 14.9393 2.53217 16.1771 2.31324C17.4234 2.0943 18.6359 1.85011 19.8148 1.58065C21.0274 1.29435 21.9578 1.4375 22.6062 2.0101C23.2546 2.58269 23.5788 3.49632 23.5788 4.75099V23.2425C23.5788 24.3456 23.3893 25.1666 23.0104 25.7055C22.6315 26.2529 21.9915 26.6528 21.0905 26.9054C19.4906 27.3433 17.9833 27.6886 16.5687 27.9412C15.154 28.2022 13.7731 28.4001 12.4258 28.5348C11.0785 28.6696 9.69751 28.7748 8.28286 28.8506C7.11241 28.918 6.20299 28.6738 5.5546 28.118C4.90622 27.5707 4.58203 26.7497 4.58203 25.655ZM9.20865 10.2624C11.0635 10.1444 12.7632 9.96305 14.3075 9.71831C14.6822 9.65722 15.0564 9.5936 15.4291 9.52759C15.8192 9.45851 16.1013 9.11859 16.1013 8.72337C16.1013 8.21154 15.638 7.82609 15.135 7.91189C14.846 7.96118 14.5555 8.00909 14.2635 8.05562C12.7346 8.29923 11.0452 8.47998 9.19523 8.5977C8.91819 8.61558 8.69776 8.70188 8.55608 8.87391C8.42209 9.03661 8.35645 9.23229 8.35645 9.45535C8.35645 9.68212 8.43296 9.87951 8.58568 10.0418L8.58783 10.0439C8.75336 10.2095 8.96369 10.2811 9.20865 10.2624ZM9.20801 14.456C11.0631 14.338 12.763 14.1566 14.3075 13.9119C15.8588 13.6589 17.3936 13.3638 18.9112 13.0266C19.2191 12.9581 19.4498 12.8503 19.5652 12.683C19.6786 12.5221 19.7347 12.3376 19.7347 12.1332C19.7347 11.9026 19.6469 11.704 19.476 11.5426C19.2921 11.3689 19.0348 11.3284 18.7304 11.3911L18.7285 11.3915C17.2823 11.7194 15.794 12.0053 14.2635 12.2492C12.7346 12.4928 11.0452 12.6735 9.19523 12.7913C8.91819 12.8091 8.69776 12.8954 8.55608 13.0675C8.42276 13.2294 8.35645 13.4205 8.35645 13.6363C8.35645 13.8703 8.43209 14.0723 8.58558 14.2354L8.59 14.2396C8.75499 14.3949 8.96316 14.4655 9.20551 14.4562L9.20801 14.456ZM9.20847 18.6494C11.0634 18.5229 12.7631 18.3374 14.3075 18.0927C15.8589 17.8482 17.3934 17.5573 18.9112 17.22C19.2199 17.1514 19.4508 17.0391 19.566 16.8627C19.6783 16.7029 19.7347 16.5233 19.7347 16.3266C19.7347 16.0961 19.6469 15.8974 19.476 15.7361C19.2921 15.5623 19.0348 15.5218 18.7304 15.5845L18.729 15.5848C17.2827 15.9043 15.7942 16.1861 14.2635 16.43C12.7345 16.6736 11.045 16.8586 9.19495 16.9847C8.91804 17.0026 8.69771 17.0889 8.55608 17.2609C8.42276 17.4228 8.35645 17.6139 8.35645 17.8297C8.35645 18.0637 8.43209 18.2658 8.58558 18.4289L8.59 18.433C8.75499 18.5883 8.96316 18.6589 9.20551 18.6496L9.20847 18.6494ZM14.3075 22.257C12.7632 22.5018 11.0635 22.6831 9.20867 22.8012C8.9637 22.8198 8.75337 22.7482 8.58783 22.5826L8.58572 22.5805C8.433 22.4182 8.35645 22.2208 8.35645 21.9941C8.35645 21.771 8.42209 21.5753 8.55608 21.4126C8.69776 21.2406 8.91827 21.1543 9.19531 21.1364C11.0453 21.0187 12.7346 20.838 14.2635 20.5943C14.5555 20.5478 14.846 20.4999 15.135 20.4506C15.638 20.3648 16.1013 20.7503 16.1013 21.2621C16.1013 21.6573 15.8192 21.9972 15.4291 22.0663C15.0564 22.1323 14.6822 22.1959 14.3075 22.257Z" fill="#000091"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,90 +1,91 @@
import { Button } from '@openfun/cunningham-react';
import Image from 'next/image';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Box, StyledLink, Text } from '@/components/';
import { Box, Icon, StyledLink, Text } from '@/components/';
import { ButtonLogin } from '@/core/auth';
import { useCunninghamTheme } from '@/cunningham';
import { LanguagePicker } from '@/features/language';
import { useResponsiveStore } from '@/stores';
import { default as IconDocs } from '../assets/icon-docs.svg?url';
import { HEADER_HEIGHT } from '../conf';
import { DropdownMenu } from './DropdownMenu';
import { LaGaufre } from './LaGaufre';
export const Header = () => {
const { t } = useTranslation();
const { isSmallMobile } = useResponsiveStore();
const theme = useCunninghamTheme();
const tokens = theme.themeTokens();
const colors = theme.colorsTokens();
const { isResponsive, toggleMobileMenu } = useResponsiveStore();
return (
<Box
as="header"
$justify="center"
$width="100%"
$zIndex="100"
$padding={{ vertical: 'xtiny' }}
$css="box-shadow: 0 1px 4px #00000040;"
$css={`
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
height: ${HEADER_HEIGHT}px;
min-height: ${HEADER_HEIGHT}px;
padding: 0 ${tokens.spacings?.['300V'] ?? '1rem'};
background-color: ${colors?.['greyscale-000'] ?? '#FFFFFF'};
border-bottom: 1px solid ${(colors?.['greyscale-200'] as string) ?? '#E5E5E5'};
`}
>
<Box
$margin={{
left: 'big',
right: isSmallMobile ? 'none' : 'big',
}}
$align="center"
$justify="space-between"
$direction="row"
>
<Box>
<StyledLink href="/">
<Box
$align="center"
$gap="0.8rem"
$direction="row"
$position="relative"
$height="fit-content"
$margin={{ top: 'auto' }}
>
<Image priority src={IconDocs} alt={t('Docs Logo')} width={25} />
<Text
$padding="2px 3px"
$size="8px"
$background="#368bd6"
$color="white"
$position="absolute"
$radius="5px"
$css={`
bottom: 13px;
right: -17px;
`}
>
BETA
</Text>
<Text
$margin="none"
as="h2"
$color="#000091"
$zIndex={1}
$size="1.30rem"
$css="font-family: 'Marianne'"
>
{t('Docs')}
</Text>
</Box>
</StyledLink>
{isResponsive && (
<Button
size="medium"
onClick={toggleMobileMenu}
aria-label={t('Open the header menu')}
color="primary-text"
icon={<Icon iconName="menu" />}
/>
)}
<StyledLink href="/">
<Box
$align="center"
$gap={(tokens.spacings?.['100V'] as string) ?? '0.8rem'}
$direction="row"
$position="relative"
$height="fit-content"
$margin={{ top: 'auto' }}
>
<Image priority src={IconDocs} alt={t('Docs Logo')} width={25} />
<Text
$margin="none"
as="h2"
$color="#000091"
$zIndex={1}
$size="1.30rem"
$css="font-family: 'Marianne'"
>
{t('Docs')}
</Text>
</Box>
{isSmallMobile ? (
<Box $direction="row" $gap="2rem">
<LaGaufre />
<DropdownMenu />
</Box>
) : (
<Box $align="center" $gap="2vw" $direction="row">
<ButtonLogin />
<LanguagePicker />
<LaGaufre />
</Box>
)}
</Box>
</StyledLink>
{isResponsive ? (
<Box
$direction="row"
$gap={(tokens.spacings?.['300V'] as string) ?? '0.625rem'}
>
<LaGaufre />
</Box>
) : (
<Box
$align="center"
$gap={(tokens.spacings?.['300V'] as string) ?? '0.625rem'}
$direction="row"
>
<ButtonLogin />
<LanguagePicker />
<LaGaufre />
</Box>
)}
</Box>
);
};

View File

@@ -0,0 +1 @@
export const HEADER_HEIGHT = 52;

View File

@@ -0,0 +1,114 @@
import { Button } from '@openfun/cunningham-react';
import { useRouter } from 'next/navigation';
import { PropsWithChildren, ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Icon } from '@/components';
import { HorizontalSeparator } from '@/components/separators/HorizontalSeparator';
import { SeparatedSection } from '@/components/separators/SeparatedSection';
import { ButtonLogin } from '@/core';
import { useCunninghamTheme } from '@/cunningham';
import { useCreateDoc } from '@/features/docs';
import { HEADER_HEIGHT } from '@/features/header/conf';
import { LanguagePicker } from '@/features/language';
import { useResponsiveStore } from '@/stores';
export const LeftPanel = ({ children }: PropsWithChildren) => {
const { t } = useTranslation();
const router = useRouter();
const { isResponsive, isMobileMenuOpen, toggleMobileMenu } =
useResponsiveStore();
const theme = useCunninghamTheme();
const colors = theme.colorsTokens();
const { mutate: createDoc } = useCreateDoc({
onSuccess: (doc) => {
router.push(`/docs/${doc.id}`);
toggleMobileMenu();
},
});
const goToHome = () => {
router.push('/');
toggleMobileMenu();
};
const createNewDoc = () => {
createDoc({ title: t('Untitled document') });
};
const getContent = (): ReactNode => {
return (
<div>
<SeparatedSection>
<Box
$padding={{ horizontal: '300V' }}
$direction="row"
$justify="space-between"
$align="center"
>
<Box $direction="row" $gap="2px">
<Button
onClick={goToHome}
size="medium"
color="primary-text"
icon={<Icon iconName="house" />}
/>
</Box>
<Button onClick={createNewDoc}>{t('New doc')}</Button>
</Box>
</SeparatedSection>
{children}
</div>
);
};
return (
<>
{!isResponsive && (
<Box
data-testid="left-panel-desktop"
$css={`
height: calc(100vh - ${HEADER_HEIGHT}px);
width: 300px;
min-width: 300px;
border-right: 1px solid ${(colors?.['greyscale-200'] as string) ?? '#E5E5E5'};
`}
>
{getContent()}
</Box>
)}
{isResponsive && (
<Box
data-testid="left-panel-mobile"
$css={`
z-index: 1000;
width: 100dvw;
height: calc(100dvh - ${HEADER_HEIGHT}px);
position: fixed;
transition: 0.15s;
background-color: ${(colors?.['greyscale-000'] as string) ?? '#fff'};
left: ${isMobileMenuOpen ? '0' : '-100dvw'};
`}
>
{getContent()}
<Box
$css={`
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: var(--c--theme--spacings--200W);
`}
>
{children && <HorizontalSeparator />}
<ButtonLogin />
<LanguagePicker />
</Box>
</Box>
)}
</>
);
};

View File

@@ -0,0 +1 @@
export const LEFT_PANEL_WIDTH = 300;

View File

@@ -1,36 +1,62 @@
import { PropsWithChildren } from 'react';
import { PropsWithChildren, ReactNode } from 'react';
import { Box } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Footer } from '@/features/footer';
import { Header } from '@/features/header';
import { HEADER_HEIGHT } from '@/features/header/conf';
import { LeftPanel } from '@/features/left-pannel/components/LeftPanel';
import { useResponsiveStore } from '@/stores';
interface MainLayoutProps {
withoutFooter?: boolean;
export enum MainLayoutBackgroundColor {
WHITE = 'white',
GREY = 'grey',
}
type MainLayoutProps = {
backgroundColor?: MainLayoutBackgroundColor;
leftPanelContent?: ReactNode;
};
export function MainLayout({
children,
withoutFooter,
backgroundColor = MainLayoutBackgroundColor.WHITE,
leftPanelContent,
}: PropsWithChildren<MainLayoutProps>) {
const { colorsTokens } = useCunninghamTheme();
const { isResponsive } = useResponsiveStore();
const { themeTokens, colorsTokens } = useCunninghamTheme();
const tokens = themeTokens();
const colors = colorsTokens();
return (
<Box>
<Box $minHeight="100vh">
<Header />
<Box $css="flex: 1;" $direction="row">
<Box
as="main"
$minHeight="100vh"
$width="100%"
$background={colorsTokens()['primary-bg']}
>
{children}
</Box>
<div>
<Header />
<Box $direction="row" $width="100%">
<LeftPanel>{leftPanelContent}</LeftPanel>
<Box
as="main"
id="mainContent"
$padding={{
vertical: !isResponsive
? ((tokens.spacings?.['200W'] as string) ?? '1.12rem')
: ((tokens.spacings?.['100V'] as string) ?? '0.5rem'),
horizontal: !isResponsive
? ((tokens.spacings?.['1200W'] as string) ?? '5.62rem')
: ((tokens.spacings?.['100V'] as string) ?? '0.5rem'),
}}
$css={`
display: flex;
width: 100%;
flex-direction: column;
align-items: center;
flex: 1;
height: calc(100dvh - ${HEADER_HEIGHT}px);
overflow-y: scroll;
background-color: ${backgroundColor === MainLayoutBackgroundColor.WHITE ? colors['greyscale-000'] : colors['greyscale-050']};
`}
>
{children}
</Box>
</Box>
{!withoutFooter && <Footer />}
</Box>
</div>
);
}

View File

@@ -1,4 +1,5 @@
import { Loader } from '@openfun/cunningham-react';
import { useQueryClient } from '@tanstack/react-query';
import Head from 'next/head';
import { useRouter as useNavigate } from 'next/navigation';
import { useRouter } from 'next/router';
@@ -7,9 +8,10 @@ import { useEffect, useState } from 'react';
import { Box, Text } from '@/components';
import { TextErrors } from '@/components/TextErrors';
import { useAuthStore } from '@/core/auth';
import { DocEditor, useDocStore } from '@/features/docs';
import { useDoc } from '@/features/docs/doc-management';
import { DocEditor } from '@/features/docs/doc-editor';
import { KEY_DOC, useDoc, useDocStore } from '@/features/docs/doc-management';
import { MainLayout } from '@/layouts';
import { useBroadcastStore } from '@/stores';
import { NextPageWithLayout } from '@/types/next';
export function DocLayout() {
@@ -26,7 +28,7 @@ export function DocLayout() {
<Head>
<meta name="robots" content="noindex" />
</Head>
<MainLayout withoutFooter>
<MainLayout>
<DocPage id={id} />
</MainLayout>
</>
@@ -41,9 +43,11 @@ const DocPage = ({ id }: DocProps) => {
const { login } = useAuthStore();
const { data: docQuery, isError, error } = useDoc({ id });
const [doc, setDoc] = useState(docQuery);
const { setCurrentDoc } = useDocStore();
const { setCurrentDoc, createProvider, docsStore } = useDocStore();
const { setBroadcastProvider, addTask } = useBroadcastStore();
const queryClient = useQueryClient();
const navigate = useNavigate();
const provider = docsStore?.[id]?.provider;
useEffect(() => {
if (doc?.title) {
@@ -66,6 +70,35 @@ const DocPage = ({ id }: DocProps) => {
};
}, [docQuery, setCurrentDoc]);
useEffect(() => {
if (!doc?.id) {
return;
}
let newProvider = provider;
if (!provider || provider.document.guid !== doc.id) {
newProvider = createProvider(doc.id, doc.content);
}
setBroadcastProvider(newProvider);
}, [createProvider, doc, provider, setBroadcastProvider]);
/**
* We add a broadcast task to reset the query cache
* when the document visibility changes.
*/
useEffect(() => {
if (!doc?.id) {
return;
}
addTask(`${KEY_DOC}-${doc.id}`, () => {
void queryClient.resetQueries({
queryKey: [KEY_DOC, { id: doc.id }],
});
});
}, [addTask, doc?.id, queryClient]);
if (isError && error) {
if (error.status === 404) {
navigate.replace(`/404`);

View File

@@ -1,15 +1,19 @@
import type { ReactElement } from 'react';
import { DocsGridContainer } from '@/features/docs/docs-grid';
import { MainLayout } from '@/layouts';
import { DocsGridList } from '@/features/docs/docs-grid/components/DocsGridList';
import { MainLayout, MainLayoutBackgroundColor } from '@/layouts';
import { NextPageWithLayout } from '@/types/next';
const Page: NextPageWithLayout = () => {
return <DocsGridContainer />;
return <DocsGridList />;
};
Page.getLayout = function getLayout(page: ReactElement) {
return <MainLayout>{page}</MainLayout>;
return (
<MainLayout backgroundColor={MainLayoutBackgroundColor.GREY}>
{page}
</MainLayout>
);
};
export default Page;

View File

@@ -1 +1,2 @@
export * from './useBroadcastStore';
export * from './useResponsiveStore';

View File

@@ -0,0 +1,54 @@
import { HocuspocusProvider } from '@hocuspocus/provider';
import * as Y from 'yjs';
import { create } from 'zustand';
interface BroadcastState {
addTask: (taskLabel: string, action: () => void) => void;
broadcast: (taskLabel: string) => void;
getBroadcastProvider: () => HocuspocusProvider | undefined;
provider?: HocuspocusProvider;
setBroadcastProvider: (provider: HocuspocusProvider) => void;
tasks: { [taskLabel: string]: Y.Array<string> };
}
export const useBroadcastStore = create<BroadcastState>((set, get) => ({
provider: undefined,
tasks: {},
setBroadcastProvider: (provider) => set({ provider }),
getBroadcastProvider: () => {
const provider = get().provider;
if (!provider) {
console.warn('Provider is not defined');
return;
}
return provider;
},
addTask: (taskLabel, action) => {
const taskExistAlready = get().tasks[taskLabel];
const provider = get().getBroadcastProvider();
if (taskExistAlready || !provider) {
return;
}
const task = provider.document.getArray<string>(taskLabel);
task.observe(() => {
action();
});
set((state) => ({
tasks: {
...state.tasks,
[taskLabel]: task,
},
}));
},
broadcast: (taskLabel) => {
const task = get().tasks[taskLabel];
if (!task) {
console.warn(`Task ${taskLabel} is not defined`);
return;
}
task.push([`broadcast: ${taskLabel}`]);
},
}));

View File

@@ -4,41 +4,74 @@ export type ScreenSize = 'small-mobile' | 'mobile' | 'tablet' | 'desktop';
export interface UseResponsiveStore {
isMobile: boolean;
isTablet: boolean;
isMobileMenuOpen: boolean;
isSmallMobile: boolean;
screenSize: ScreenSize;
screenWidth: number;
setScreenSize: (size: ScreenSize) => void;
toggleMobileMenu: () => void;
isResponsive: boolean;
initializeResizeListener: () => () => void;
}
const initialState = {
isMobile: false,
isTablet: false,
isSmallMobile: false,
isResponsive: false,
isMobileMenuOpen: false,
screenSize: 'desktop' as ScreenSize,
screenWidth: 0,
};
export const useResponsiveStore = create<UseResponsiveStore>((set) => ({
isMobile: initialState.isMobile,
isTablet: initialState.isTablet,
isSmallMobile: initialState.isSmallMobile,
screenSize: initialState.screenSize,
isMobileMenuOpen: initialState.isMobileMenuOpen,
screenWidth: initialState.screenWidth,
setScreenSize: (size: ScreenSize) => set(() => ({ screenSize: size })),
isResponsive: initialState.isResponsive,
toggleMobileMenu: () => {
set((old) => ({ isMobileMenuOpen: !old.isMobileMenuOpen }));
},
initializeResizeListener: () => {
const resizeHandler = () => {
const width = window.innerWidth;
if (width < 560) {
set({
isResponsive: true,
screenSize: 'small-mobile',
isMobile: true,
isTablet: false,
isSmallMobile: true,
});
} else if (width < 768) {
set({ screenSize: 'mobile', isMobile: true, isSmallMobile: false });
set({
isResponsive: true,
screenSize: 'mobile',
isTablet: false,
isMobile: true,
isSmallMobile: false,
});
} else if (width >= 768 && width < 1024) {
set({ screenSize: 'tablet', isMobile: false, isSmallMobile: false });
set({
isResponsive: true,
screenSize: 'tablet',
isTablet: true,
isMobile: false,
isSmallMobile: false,
});
} else {
set({ screenSize: 'desktop', isMobile: false, isSmallMobile: false });
set({
isResponsive: false,
screenSize: 'desktop',
isTablet: false,
isMobile: false,
isSmallMobile: false,
});
}
set({ screenWidth: width });

View File

@@ -9892,6 +9892,11 @@ react-icons@^5.2.1:
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.3.0.tgz#ccad07a30aebd40a89f8cfa7d82e466019203f1c"
integrity sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==
react-intersection-observer@9.13.1:
version "9.13.1"
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz#6c61a75801162491c6348bad09967f2caf445584"
integrity sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==
react-is@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"

View File

@@ -1,62 +0,0 @@
djangoSuperUserEmail: ENC[AES256_GCM,data:7b1xfYmr1g0RlBmsHBRA39ZPV/6+1DrtHQ==,iv:/GW7oLxPTZYmRWVPvyAQMoZl1owHM4Fo0XAOtyEh2rA=,tag:DaqoW+dglyAOXMm5+mrDfA==,type:str]
djangoSuperUserPass: ENC[AES256_GCM,data:RQgX,iv:q3CdfmwGfHSTjLXTimDk/1MyoFLviRuwmZa2E7GUzhY=,tag:HCtdtqgSxdJIHFhI8xpegQ==,type:str]
djangoSecretKey: ENC[AES256_GCM,data:mtJCf6mKfj/fJkg4wmfIvvU1vkUEF77BI8TUFikp/M3nPveDXhKmy3Cw3cXFpOYiFZ0=,iv:qwPRKsPS1Jhylj5asbmknXm1xOX3nfp9iccuorUrcj0=,tag:ENVfAt4i3PttoqD8+Kc4wQ==,type:str]
oidc:
clientId: ENC[AES256_GCM,data:wndPCbysbWDybdHglcG+wkMWk1rrD40hKqFxct9T3TLEGOk/,iv:RH1OdBX1GYIT90sSq0AGz49fFi6dL0m49Pegs6Ko9tQ=,tag:/tKytQwoZkBX1Tf96gAjIA==,type:str]
clientSecret: ENC[AES256_GCM,data:MUJ0wsg+LC2QZ1jZ0Twd3FS3dQevmJq9/97qVI3ARHuJIVlQz0Qah4vE7/iR+sn7ME2o1s1AzV4c1Yx/F3nHBg==,iv:LvinICSzF/8EvrHZD4Jp6lt7g3yxSOEgVHPrc3SShjo=,tag:yvkyyBXmhEkmGL7jZevUCA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age15fyxdwmg5mvldtqqus87xspuws2u0cpvwheehrtvkexj4tnsqqysw6re2x
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMMjFCeWhkUmRWTnlIM1JM
dVFock1DWmtXQnpQZWZMWW1YdndhSS93MlVFCmxKVDUwOUt0NjJIZiswSm5aRi9U
VEllelBZVmFKdVFzcVJPUm50VHo5RTgKLS0tIDlkU3htTEdSREFOSUxlTGVtUm1n
RzJZbzhFcDNZKzdxMWFHTWx6Uy9GVFkKTw8LbhzAACp0NUHDfNcXpZyr2pJyNxxw
C7j/UB0cAejlSJHaUUiZ6TEcslXRpqnNagwUw4z/uzo7m4temay22A==
-----END AGE ENCRYPTED FILE-----
- recipient: age16hnlml8yv4ynwy0seer57g8qww075crd0g7nsundz3pj4wk7m3vqftszg7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQQjBNMnVlNURQVWdjSyty
RGozcmN5eTUwRHJIWnhhc1E3U1NXQ3AwTWxBCnFjbmJNZnFiRVJ6VHhmQmt1Vk5n
OTVXWVh3RzhoMWNrbUl6OHphTjFLQVUKLS0tIGJjUlNhK0dHQ2R3SCtrbTRnaFJT
Q1pyRXhSVm8xQWk2NG1MK0srVU1pL2sKkoxGCM00UM2leTNCn5H8499uwJw1NIXs
PoRNgplehrHFptrAwGEpSYMXbxu88N7EWa/rtOp+sHWK5zpxscMkjA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1plkp8td6zzfcavjusmsfrlk54t9vn8jjxm8zaz7cmnr7kzl2nfnsd54hwg
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzYnpkYnJnYnJjVFRHRzRa
N09JOXVnQkVrcVcwdk9kR1k1azNib2lkMVZFCmhvOHlpVnJ0RlRpYWZ1TkVoaklV
NmNzY3BEeWN1MUtKWmZFT2RaMUxBRW8KLS0tIG92ZmhsZ29LSkRSREhiaG9kWXhH
akREb0ttYVpNWTJHb1pjaWRFbWpxUjgKgZp3cN2rZw4ktbpb5cUnDEtsT/KWszGi
pmpJHgsMADigyUc+Pjw+1pwpn0FtXVEXGedbf8bBuJavvbS2PuJBsg==
-----END AGE ENCRYPTED FILE-----
- recipient: age12g6f5fse25tgrwweleh4jls3qs52hey2edh759smulwmk5lnzadslu2cp3
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxaHZJeStiVnBzTGNTNzdo
UDFVTU51ZWp0WWorUnBlSzVBSU9IU2JnbUNNCkpMZGdNV3FUYkZOcWNLK0JWci81
WGNwYi9Jb0QrV0lkUzNJWTcrUjIzUmMKLS0tIHlTKzNsVzNsSGFuYjJ0RFp0Y1Nr
a1VOcDBPTTYvNjkxN092N1UrYk1CM2cKNifC3ZLOrFTFKA9iKg8nPpZb+3DxnTwq
grsrxQa40b/Vv/aPoiPBMeSENDcH48X/EhMFNKX7dvl+7HEaY+QPlA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1hnhuzj96ktkhpyygvmz0x9h8mfvssz7ss6emmukags644mdhf4msajk93r
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoZ2ZlcllJeGlKUDNxUk1w
ekZ3TSttaXREV1FBRWwzNW54cjlYbHpLdWpRCnhSL2hEVVBEWEJKQWF0YTk1YzhJ
RTBGN25sT0hBM3V4QndiTVkveDBwQ2cKLS0tIEdoZGRLRXdCME1wcUJHQXhtSHBQ
UVEyNUVIanF6Z3ZSUjU1aTk0NFRBR0EKGuH5vzOV9lP/qRew0maECapKtLILaf/4
XoSgPnjh8pIbJG7i9VKnFORlzkNJ6OPhZlX3ax15hd1qQv0PSCMBDA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-07-02T10:03:17Z"
mac: ENC[AES256_GCM,data:qx236E1cFtBmbYyUf6B95/Fwu2hoi9ZAhUcYiY/tsG9h1+kwXntfkvbH3ekyI7A5ZrpJXMeQZ7gLc+ohci4m5Ju+/G39MjMt+ww0Y6gBMqe59YlHfeFD2mYsnn9j1pqtbrIJ6+8fLDmhaXtGtXP3qRmFTc9LwL6Rm+5gn8cjcnA=,iv:TC7zBnQ0hRz0JSytrYVnyJiI1eMWRTBqctLajZYUhvU=,tag:wCBeo2xD5UpdRqGjkZxbXA==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1

View File

@@ -1,125 +0,0 @@
image:
repository: localhost:5001/impress-backend
pullPolicy: Always
tag: "latest"
backend:
replicas: 1
envVars:
AI_API_KEY: {{ .Values.aiApiKey }}
AI_BASE_URL: {{ .Values.aiBaseUrl }}
AI_MODEL: meta-llama/Meta-Llama-3.1-70B-Instruct
DJANGO_CSRF_TRUSTED_ORIGINS: https://impress.127.0.0.1.nip.io,http://impress.127.0.0.1.nip.io
DJANGO_CONFIGURATION: Production
DJANGO_ALLOWED_HOSTS: "*"
DJANGO_SECRET_KEY: {{ .Values.djangoSecretKey }}
DJANGO_SETTINGS_MODULE: impress.settings
DJANGO_SUPERUSER_PASSWORD: admin
DJANGO_EMAIL_HOST: "mailcatcher"
DJANGO_EMAIL_PORT: 1025
DJANGO_EMAIL_USE_SSL: False
OIDC_OP_JWKS_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/jwks
OIDC_OP_AUTHORIZATION_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/authorize
OIDC_OP_TOKEN_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/token
OIDC_OP_USER_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/userinfo
OIDC_OP_LOGOUT_ENDPOINT: https://fca.integ01.dev-agentconnect.fr/api/v2/session/end
OIDC_RP_CLIENT_ID: {{ .Values.oidc.clientId }}
OIDC_RP_CLIENT_SECRET: {{ .Values.oidc.clientSecret }}
OIDC_RP_SIGN_ALGO: RS256
OIDC_RP_SCOPES: "openid email given_name usual_name"
USER_OIDC_FIELD_TO_SHORTNAME: "given_name"
USER_OIDC_FIELDS_TO_FULLNAME: "given_name,usual_name"
OIDC_REDIRECT_ALLOWED_HOSTS: https://impress.127.0.0.1.nip.io
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
LOGIN_REDIRECT_URL: https://impress.127.0.0.1.nip.io
LOGIN_REDIRECT_URL_FAILURE: https://impress.127.0.0.1.nip.io
LOGOUT_REDIRECT_URL: https://impress.127.0.0.1.nip.io
DB_HOST: postgres-postgresql
DB_NAME: impress
DB_USER: dinum
DB_PASSWORD: pass
DB_PORT: 5432
POSTGRES_DB: impress
POSTGRES_USER: dinum
POSTGRES_PASSWORD: pass
REDIS_URL: redis://default:pass@redis-master:6379/1
AWS_S3_ENDPOINT_URL: http://minio.impress.svc.cluster.local:9000
AWS_S3_ACCESS_KEY_ID: impress
AWS_S3_SECRET_ACCESS_KEY: password
AWS_STORAGE_BUCKET_NAME: impress-media-storage
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
migrate:
command:
- "/bin/sh"
- "-c"
- |
python manage.py migrate --no-input &&
python manage.py create_demo --force
restartPolicy: Never
command:
- "gunicorn"
- "-c"
- "/usr/local/etc/gunicorn/impress.py"
- "impress.wsgi:application"
- "--reload"
createsuperuser:
command:
- "/bin/sh"
- "-c"
- |
python manage.py createsuperuser --email admin@example.com --password admin
restartPolicy: Never
frontend:
envVars:
PORT: 8080
NEXT_PUBLIC_API_ORIGIN: https://impress.127.0.0.1.nip.io
NEXT_PUBLIC_Y_PROVIDER_URL: wss://impress.127.0.0.1.nip.io/ws
NEXT_PUBLIC_MEDIA_URL: https://impress.127.0.0.1.nip.io
replicas: 1
command:
- yarn
- dev
image:
repository: localhost:5001/impress-frontend
pullPolicy: Always
tag: "latest"
yProvider:
replicas: 1
image:
repository: localhost:5001/impress-y-provider
pullPolicy: Always
tag: "latest"
ingress:
enabled: true
host: impress.127.0.0.1.nip.io
ingressWS:
enabled: true
host: impress.127.0.0.1.nip.io
ingressAdmin:
enabled: true
host: impress.127.0.0.1.nip.io
ingressMedia:
enabled: true
host: impress.127.0.0.1.nip.io
annotations:
nginx.ingress.kubernetes.io/auth-url: https://impress.127.0.0.1.nip.io/api/v1.0/documents/retrieve-auth/
nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256"
nginx.ingress.kubernetes.io/upstream-vhost: minio.impress.svc.cluster.local:9000
nginx.ingress.kubernetes.io/rewrite-target: /impress-media-storage/$1
serviceMedia:
host: minio.impress.svc.cluster.local
port: 9000

View File

@@ -1,5 +0,0 @@
apiVersion: v2
name: extra
description: A Helm chart to add some manifests to impress
type: application
version: 0.1.0

View File

@@ -1,7 +0,0 @@
apiVersion: core.libre.sh/v1alpha1
kind: Redis
metadata:
name: redis
namespace: {{ .Release.Namespace | quote }}
spec:
disableAuth: false

View File

@@ -1,7 +0,0 @@
apiVersion: core.libre.sh/v1alpha1
kind: Postgres
metadata:
name: postgresql
namespace: {{ .Release.Namespace | quote }}
spec:
database: impress

View File

@@ -1,8 +0,0 @@
apiVersion: core.libre.sh/v1alpha1
kind: Bucket
metadata:
name: impress-media-storage
namespace: {{ .Release.Namespace | quote }}
spec:
provider: data
versioned: true

View File

@@ -1,82 +0,0 @@
repositories:
- name: bitnami
url: registry-1.docker.io/bitnamicharts
oci: true
releases:
- name: postgres
installed: {{ eq .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: bitnami/postgresql
version: 13.1.5
values:
- auth:
username: dinum
password: pass
database: impress
- tls:
enabled: true
autoGenerated: true
- name: minio
installed: {{ eq .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: bitnami/minio
version: 12.10.10
values:
- auth:
rootUser: impress
rootPassword: password
- provisioning:
enabled: true
buckets:
- name: impress-media-storage
versioning: true
- name: redis
installed: {{ eq .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: bitnami/redis
version: 18.19.2
values:
- auth:
password: pass
architecture: standalone
- name: extra
installed: {{ ne .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: ./extra
secrets:
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
- name: impress
version: {{ .Values.version }}
namespace: {{ .Namespace }}
chart: ./impress
values:
- env.d/{{ .Environment.Name }}/values.impress.yaml.gotmpl
secrets:
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
environments:
dev:
values:
- version: 0.0.1
secrets:
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
staging:
values:
- version: 0.0.1
secrets:
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
preprod:
values:
- version: 0.0.1
secrets:
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
production:
values:
- version: 0.0.1
secrets:
- env.d/{{ .Environment.Name }}/secrets.enc.yaml

View File

@@ -1,4 +0,0 @@
apiVersion: v2
type: application
name: impress
version: 0.0.1

View File

@@ -1,128 +0,0 @@
# Impress helm chart
## Parameters
### General configuration
| Name | Description | Value |
| ------------------------------------------ | ---------------------------------------------------- | ------------------------ |
| `image.repository` | Repository to use to pull impress's container image | `lasuite/impress-backend` |
| `image.tag` | impress's container tag | `latest` |
| `image.pullPolicy` | Container image pull policy | `IfNotPresent` |
| `image.credentials.username` | Username for container registry authentication | |
| `image.credentials.password` | Password for container registry authentication | |
| `image.credentials.registry` | Registry url for which the credentials are specified | |
| `image.credentials.name` | Name of the generated secret for imagePullSecrets | |
| `nameOverride` | Override the chart name | `""` |
| `fullnameOverride` | Override the full application name | `""` |
| `ingress.enabled` | whether to enable the Ingress or not | `false` |
| `ingress.className` | IngressClass to use for the Ingress | `nil` |
| `ingress.host` | Host for the Ingress | `impress.example.com` |
| `ingress.path` | Path to use for the Ingress | `/` |
| `ingress.hosts` | Additional host to configure for the Ingress | `[]` |
| `ingress.tls.enabled` | Weather to enable TLS for the Ingress | `true` |
| `ingress.tls.additional[].secretName` | Secret name for additional TLS config | |
| `ingress.tls.additional[].hosts[]` | Hosts for additional TLS config | |
| `ingress.customBackends` | Add custom backends to ingress | `[]` |
| `ingressAdmin.enabled` | whether to enable the Ingress or not | `false` |
| `ingressAdmin.className` | IngressClass to use for the Ingress | `nil` |
| `ingressAdmin.host` | Host for the Ingress | `impress.example.com` |
| `ingressAdmin.path` | Path to use for the Ingress | `/admin` |
| `ingressAdmin.hosts` | Additional host to configure for the Ingress | `[]` |
| `ingressAdmin.tls.enabled` | Weather to enable TLS for the Ingress | `true` |
| `ingressAdmin.tls.additional[].secretName` | Secret name for additional TLS config | |
| `ingressAdmin.tls.additional[].hosts[]` | Hosts for additional TLS config | |
### backend
| Name | Description | Value |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------- |
| `backend.command` | Override the backend container command | `[]` |
| `backend.args` | Override the backend container args | `[]` |
| `backend.replicas` | Amount of backend replicas | `3` |
| `backend.shareProcessNamespace` | Enable share process namespace between containers | `false` |
| `backend.sidecars` | Add sidecars containers to backend deployment | `[]` |
| `backend.securityContext` | Configure backend Pod security context | `nil` |
| `backend.envVars` | Configure backend container environment variables | `undefined` |
| `backend.envVars.BY_VALUE` | Example environment variable by setting value directly | |
| `backend.envVars.FROM_CONFIGMAP.configMapKeyRef.name` | Name of a ConfigMap when configuring env vars from a ConfigMap | |
| `backend.envVars.FROM_CONFIGMAP.configMapKeyRef.key` | Key within a ConfigMap when configuring env vars from a ConfigMap | |
| `backend.envVars.FROM_SECRET.secretKeyRef.name` | Name of a Secret when configuring env vars from a Secret | |
| `backend.envVars.FROM_SECRET.secretKeyRef.key` | Key within a Secret when configuring env vars from a Secret | |
| `backend.podAnnotations` | Annotations to add to the backend Pod | `{}` |
| `backend.service.type` | backend Service type | `ClusterIP` |
| `backend.service.port` | backend Service listening port | `80` |
| `backend.service.targetPort` | backend container listening port | `8000` |
| `backend.service.annotations` | Annotations to add to the backend Service | `{}` |
| `backend.migrate.command` | backend migrate command | `["python","manage.py","migrate","--no-input"]` |
| `backend.migrate.restartPolicy` | backend migrate job restart policy | `Never` |
| `backend.probes.liveness.path` | Configure path for backend HTTP liveness probe | `/__heartbeat__` |
| `backend.probes.liveness.targetPort` | Configure port for backend HTTP liveness probe | `undefined` |
| `backend.probes.liveness.initialDelaySeconds` | Configure initial delay for backend liveness probe | `10` |
| `backend.probes.liveness.initialDelaySeconds` | Configure timeout for backend liveness probe | `10` |
| `backend.probes.startup.path` | Configure path for backend HTTP startup probe | `undefined` |
| `backend.probes.startup.targetPort` | Configure port for backend HTTP startup probe | `undefined` |
| `backend.probes.startup.initialDelaySeconds` | Configure initial delay for backend startup probe | `undefined` |
| `backend.probes.startup.initialDelaySeconds` | Configure timeout for backend startup probe | `undefined` |
| `backend.probes.readiness.path` | Configure path for backend HTTP readiness probe | `/__lbheartbeat__` |
| `backend.probes.readiness.targetPort` | Configure port for backend HTTP readiness probe | `undefined` |
| `backend.probes.readiness.initialDelaySeconds` | Configure initial delay for backend readiness probe | `10` |
| `backend.probes.readiness.initialDelaySeconds` | Configure timeout for backend readiness probe | `10` |
| `backend.resources` | Resource requirements for the backend container | `{}` |
| `backend.nodeSelector` | Node selector for the backend Pod | `{}` |
| `backend.tolerations` | Tolerations for the backend Pod | `[]` |
| `backend.affinity` | Affinity for the backend Pod | `{}` |
| `backend.persistence` | Additional volumes to create and mount on the backend. Used for debugging purposes | `{}` |
| `backend.persistence.volume-name.size` | Size of the additional volume | |
| `backend.persistence.volume-name.type` | Type of the additional volume, persistentVolumeClaim or emptyDir | |
| `backend.persistence.volume-name.mountPath` | Path where the volume should be mounted to | |
| `backend.extraVolumeMounts` | Additional volumes to mount on the backend. | `[]` |
| `backend.extraVolumes` | Additional volumes to mount on the backend. | `[]` |
### frontend
| Name | Description | Value |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------- | ------------------------- |
| `frontend.image.repository` | Repository to use to pull impress's frontend container image | `lasuite/impress-frontend` |
| `frontend.image.tag` | impress's frontend container tag | `latest` |
| `frontend.image.pullPolicy` | frontend container image pull policy | `IfNotPresent` |
| `frontend.command` | Override the frontend container command | `[]` |
| `frontend.args` | Override the frontend container args | `[]` |
| `frontend.replicas` | Amount of frontend replicas | `3` |
| `frontend.shareProcessNamespace` | Enable share process namefrontend between containers | `false` |
| `frontend.sidecars` | Add sidecars containers to frontend deployment | `[]` |
| `frontend.securityContext` | Configure frontend Pod security context | `nil` |
| `frontend.envVars` | Configure frontend container environment variables | `undefined` |
| `frontend.envVars.BY_VALUE` | Example environment variable by setting value directly | |
| `frontend.envVars.FROM_CONFIGMAP.configMapKeyRef.name` | Name of a ConfigMap when configuring env vars from a ConfigMap | |
| `frontend.envVars.FROM_CONFIGMAP.configMapKeyRef.key` | Key within a ConfigMap when configuring env vars from a ConfigMap | |
| `frontend.envVars.FROM_SECRET.secretKeyRef.name` | Name of a Secret when configuring env vars from a Secret | |
| `frontend.envVars.FROM_SECRET.secretKeyRef.key` | Key within a Secret when configuring env vars from a Secret | |
| `frontend.podAnnotations` | Annotations to add to the frontend Pod | `{}` |
| `frontend.service.type` | frontend Service type | `ClusterIP` |
| `frontend.service.port` | frontend Service listening port | `80` |
| `frontend.service.targetPort` | frontend container listening port | `8080` |
| `frontend.service.annotations` | Annotations to add to the frontend Service | `{}` |
| `frontend.probes` | Configure probe for frontend | `{}` |
| `frontend.probes.liveness.path` | Configure path for frontend HTTP liveness probe | |
| `frontend.probes.liveness.targetPort` | Configure port for frontend HTTP liveness probe | |
| `frontend.probes.liveness.initialDelaySeconds` | Configure initial delay for frontend liveness probe | |
| `frontend.probes.liveness.initialDelaySeconds` | Configure timeout for frontend liveness probe | |
| `frontend.probes.startup.path` | Configure path for frontend HTTP startup probe | |
| `frontend.probes.startup.targetPort` | Configure port for frontend HTTP startup probe | |
| `frontend.probes.startup.initialDelaySeconds` | Configure initial delay for frontend startup probe | |
| `frontend.probes.startup.initialDelaySeconds` | Configure timeout for frontend startup probe | |
| `frontend.probes.readiness.path` | Configure path for frontend HTTP readiness probe | |
| `frontend.probes.readiness.targetPort` | Configure port for frontend HTTP readiness probe | |
| `frontend.probes.readiness.initialDelaySeconds` | Configure initial delay for frontend readiness probe | |
| `frontend.probes.readiness.initialDelaySeconds` | Configure timeout for frontend readiness probe | |
| `frontend.resources` | Resource requirements for the frontend container | `{}` |
| `frontend.nodeSelector` | Node selector for the frontend Pod | `{}` |
| `frontend.tolerations` | Tolerations for the frontend Pod | `[]` |
| `frontend.affinity` | Affinity for the frontend Pod | `{}` |
| `frontend.persistence` | Additional volumes to create and mount on the frontend. Used for debugging purposes | `{}` |
| `frontend.persistence.volume-name.size` | Size of the additional volume | |
| `frontend.persistence.volume-name.type` | Type of the additional volume, persistentVolumeClaim or emptyDir | |
| `frontend.persistence.volume-name.mountPath` | Path where the volume should be mounted to | |
| `frontend.extraVolumeMounts` | Additional volumes to mount on the frontend. | `[]` |
| `frontend.extraVolumes` | Additional volumes to mount on the frontend. | `[]` |

View File

@@ -1,10 +0,0 @@
#!/bin/bash
docker image ls | grep readme-generator-for-helm
if [ "$?" -ne "0" ]; then
git clone https://github.com/bitnami/readme-generator-for-helm.git /tmp/readme-generator-for-helm
cd /tmp/readme-generator-for-helm
docker build -t readme-generator-for-helm:latest .
cd $(dirname -- "${BASH_SOURCE[0]}")
fi
docker run --rm -it -v ./values.yaml:/app/values.yaml -v ./README.md:/app/README.md readme-generator-for-helm:latest readme-generator -v values.yaml -r README.md

View File

@@ -1,184 +0,0 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "impress.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "impress.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "impress.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
impress.labels
*/}}
{{- define "impress.labels" -}}
helm.sh/chart: {{ include "impress.chart" . }}
{{ include "impress.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "impress.selectorLabels" -}}
app.kubernetes.io/name: {{ include "impress.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
transform dictionnary of environment variables
Usage : {{ include "impress.env.transformDict" .Values.envVars }}
Example:
envVars:
# Using simple strings as env vars
ENV_VAR_NAME: "envVar value"
# Using a value from a configMap
ENV_VAR_FROM_CM:
configMapKeyRef:
name: cm-name
key: "key_in_cm"
# Using a value from a secret
ENV_VAR_FROM_SECRET:
secretKeyRef:
name: secret-name
key: "key_in_secret"
*/}}
{{- define "impress.env.transformDict" -}}
{{- range $key, $value := . }}
- name: {{ $key | quote }}
{{- if $value | kindIs "map" }}
valueFrom: {{ $value | toYaml | nindent 4 }}
{{- else }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- end }}
{{/*
impress env vars
*/}}
{{- define "impress.common.env" -}}
{{- $topLevelScope := index . 0 -}}
{{- $workerScope := index . 1 -}}
{{- include "impress.env.transformDict" $workerScope.envVars -}}
{{- end }}
{{/*
Common labels
Requires array with top level scope and component name
*/}}
{{- define "impress.common.labels" -}}
{{- $topLevelScope := index . 0 -}}
{{- $component := index . 1 -}}
{{- include "impress.labels" $topLevelScope }}
app.kubernetes.io/component: {{ $component }}
{{- end }}
{{/*
Common selector labels
Requires array with top level scope and component name
*/}}
{{- define "impress.common.selectorLabels" -}}
{{- $topLevelScope := index . 0 -}}
{{- $component := index . 1 -}}
{{- include "impress.selectorLabels" $topLevelScope }}
app.kubernetes.io/component: {{ $component }}
{{- end }}
{{- define "impress.probes.abstract" -}}
{{- if .exec -}}
exec:
{{- toYaml .exec | nindent 2 }}
{{- else if .tcpSocket -}}
tcpSocket:
{{- toYaml .tcpSocket | nindent 2 }}
{{- else -}}
httpGet:
path: {{ .path }}
port: {{ .targetPort }}
{{- end }}
initialDelaySeconds: {{ .initialDelaySeconds | eq nil | ternary 0 .initialDelaySeconds }}
timeoutSeconds: {{ .timeoutSeconds | eq nil | ternary 1 .timeoutSeconds }}
{{- end }}
{{/*
Full name for the backend
Requires top level scope
*/}}
{{- define "impress.backend.fullname" -}}
{{ include "impress.fullname" . }}-backend
{{- end }}
{{/*
Full name for the frontend
Requires top level scope
*/}}
{{- define "impress.frontend.fullname" -}}
{{ include "impress.fullname" . }}-frontend
{{- end }}
{{/*
Full name for the yProvider
Requires top level scope
*/}}
{{- define "impress.yProvider.fullname" -}}
{{ include "impress.fullname" . }}-y-provider
{{- end }}
{{/*
Usage : {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" .Values.path.to.the.image1) }}
*/}}
{{- define "impress.secret.dockerconfigjson.name" }}
{{- if (default (dict) .imageCredentials).name }}{{ .imageCredentials.name }}{{ else }}{{ .fullname | trunc 63 | trimSuffix "-" }}-dockerconfig{{ end -}}
{{- end }}
{{/*
Usage : {{ include "impress.secret.dockerconfigjson" (dict "fullname" (include "impress.fullname" .) "imageCredentials" .Values.path.to.the.image1) }}
*/}}
{{- define "impress.secret.dockerconfigjson" }}
{{- if .imageCredentials -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "impress.secret.dockerconfigjson.name" (dict "fullname" .fullname "imageCredentials" .imageCredentials) }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "impress.secret.dockerconfigjson.data" .imageCredentials }}
{{- end -}}
{{- end }}

View File

@@ -1,136 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.backend) -}}
{{- $fullName := include "impress.backend.fullname" . -}}
{{- $component := "backend" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
replicas: {{ .Values.backend.replicas }}
selector:
matchLabels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
template:
metadata:
annotations:
{{- with .Values.backend.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
spec:
{{- if $.Values.image.credentials }}
imagePullSecrets:
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
{{- end}}
shareProcessNamespace: {{ .Values.backend.shareProcessNamespace }}
containers:
{{- with .Values.backend.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ (.Values.backend.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.backend.image | default dict).tag | default .Values.image.tag }}"
imagePullPolicy: {{ (.Values.backend.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
{{- with .Values.backend.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.backend.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if $envVars}}
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.backend.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.backend.service.targetPort }}
protocol: TCP
{{- if .Values.backend.probes.liveness }}
livenessProbe:
{{- include "impress.probes.abstract" (merge .Values.backend.probes.liveness (dict "targetPort" .Values.backend.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.backend.probes.readiness }}
readinessProbe:
{{- include "impress.probes.abstract" (merge .Values.backend.probes.readiness (dict "targetPort" .Values.backend.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.backend.probes.startup }}
startupProbe:
{{- include "impress.probes.abstract" (merge .Values.backend.probes.startup (dict "targetPort" .Values.backend.service.targetPort )) | nindent 12 }}
{{- end }}
{{- with .Values.backend.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
mountPath: {{ $value.path }}
subPath: content
{{- end }}
{{- range $name, $volume := .Values.backend.persistence }}
- name: "{{ $name }}"
mountPath: "{{ $volume.mountPath }}"
{{- end }}
{{- range .Values.backend.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- with .Values.backend.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.backend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.backend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
configMap:
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
{{- end }}
{{- range $name, $volume := .Values.backend.persistence }}
- name: "{{ $name }}"
{{- if eq $volume.type "emptyDir" }}
emptyDir: {}
{{- else }}
persistentVolumeClaim:
claimName: "{{ $fullName }}-{{ $name }}"
{{- end }}
{{- end }}
{{- range .Values.backend.extraVolumes }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
hostPath:
{{ toYaml .hostPath | nindent 12 }}
{{- else if .csi }}
csi:
{{- toYaml .csi | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}

View File

@@ -1,122 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.backend) -}}
{{- $fullName := include "impress.backend.fullname" . -}}
{{- $component := "backend" -}}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ $fullName }}-migrate
namespace: {{ .Release.Namespace | quote }}
annotations:
argocd.argoproj.io/sync-options: Replace=true,Force=true
{{- with .Values.backend.migrateJobAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
template:
metadata:
annotations:
{{- with .Values.backend.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
spec:
{{- if $.Values.image.credentials }}
imagePullSecrets:
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
{{- end}}
shareProcessNamespace: {{ .Values.backend.shareProcessNamespace }}
containers:
{{- with .Values.backend.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ (.Values.backend.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.backend.image | default dict).tag | default .Values.image.tag }}"
imagePullPolicy: {{ (.Values.backend.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
{{- with .Values.backend.migrate.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.backend.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if $envVars}}
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.backend.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.backend.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
mountPath: {{ $value.path }}
subPath: content
{{- end }}
{{- range $name, $volume := .Values.backend.persistence }}
- name: "{{ $name }}"
mountPath: "{{ $volume.mountPath }}"
{{- end }}
{{- range .Values.backend.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- with .Values.backend.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.backend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.backend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
restartPolicy: {{ .Values.backend.migrate.restartPolicy }}
volumes:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
configMap:
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
{{- end }}
{{- range $name, $volume := .Values.backend.persistence }}
- name: "{{ $name }}"
{{- if eq $volume.type "emptyDir" }}
emptyDir: {}
{{- else }}
persistentVolumeClaim:
claimName: "{{ $fullName }}-{{ $name }}"
{{- end }}
{{- end }}
{{- range .Values.backend.extraVolumes }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
hostPath:
{{ toYaml .hostPath | nindent 12 }}
{{- else if .csi }}
csi:
{{- toYaml .csi | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}

View File

@@ -1,122 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.backend) -}}
{{- $fullName := include "impress.backend.fullname" . -}}
{{- $component := "backend" -}}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ $fullName }}-createsuperuser
namespace: {{ .Release.Namespace | quote }}
annotations:
argocd.argoproj.io/sync-options: Replace=true,Force=true
{{- with .Values.backend.migrateJobAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
template:
metadata:
annotations:
{{- with .Values.backend.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
spec:
{{- if $.Values.image.credentials }}
imagePullSecrets:
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
{{- end}}
shareProcessNamespace: {{ .Values.backend.shareProcessNamespace }}
containers:
{{- with .Values.backend.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ (.Values.backend.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.backend.image | default dict).tag | default .Values.image.tag }}"
imagePullPolicy: {{ (.Values.backend.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
{{- with .Values.backend.createsuperuser.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.backend.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if $envVars}}
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.backend.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.backend.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
mountPath: {{ $value.path }}
subPath: content
{{- end }}
{{- range $name, $volume := .Values.backend.persistence }}
- name: "{{ $name }}"
mountPath: "{{ $volume.mountPath }}"
{{- end }}
{{- range .Values.backend.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- with .Values.backend.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.backend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.backend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
restartPolicy: {{ .Values.backend.createsuperuser.restartPolicy }}
volumes:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
configMap:
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
{{- end }}
{{- range $name, $volume := .Values.backend.persistence }}
- name: "{{ $name }}"
{{- if eq $volume.type "emptyDir" }}
emptyDir: {}
{{- else }}
persistentVolumeClaim:
claimName: "{{ $fullName }}-{{ $name }}"
{{- end }}
{{- end }}
{{- range .Values.backend.extraVolumes }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
hostPath:
{{ toYaml .hostPath | nindent 12 }}
{{- else if .csi }}
csi:
{{- toYaml .csi | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}

View File

@@ -1,21 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.backend) -}}
{{- $fullName := include "impress.backend.fullname" . -}}
{{- $component := "backend" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
annotations:
{{- toYaml $.Values.backend.service.annotations | nindent 4 }}
spec:
type: {{ .Values.backend.service.type }}
ports:
- port: {{ .Values.backend.service.port }}
targetPort: {{ .Values.backend.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}

View File

@@ -1,136 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.frontend) -}}
{{- $fullName := include "impress.frontend.fullname" . -}}
{{- $component := "frontend" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
replicas: {{ .Values.frontend.replicas }}
selector:
matchLabels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
template:
metadata:
annotations:
{{- with .Values.frontend.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
spec:
{{- if $.Values.image.credentials }}
imagePullSecrets:
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
{{- end}}
shareProcessNamespace: {{ .Values.frontend.shareProcessNamespace }}
containers:
{{- with .Values.frontend.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ (.Values.frontend.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.frontend.image | default dict).tag | default .Values.image.tag }}"
imagePullPolicy: {{ (.Values.frontend.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
{{- with .Values.frontend.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.frontend.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if $envVars}}
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.frontend.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.frontend.service.targetPort }}
protocol: TCP
{{- if .Values.frontend.probes.liveness }}
livenessProbe:
{{- include "impress.probes.abstract" (merge .Values.frontend.probes.liveness (dict "targetPort" .Values.frontend.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.frontend.probes.readiness }}
readinessProbe:
{{- include "impress.probes.abstract" (merge .Values.frontend.probes.readiness (dict "targetPort" .Values.frontend.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.frontend.probes.startup }}
startupProbe:
{{- include "impress.probes.abstract" (merge .Values.frontend.probes.startup (dict "targetPort" .Values.frontend.service.targetPort )) | nindent 12 }}
{{- end }}
{{- with .Values.frontend.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
mountPath: {{ $value.path }}
subPath: content
{{- end }}
{{- range $name, $volume := .Values.frontend.persistence }}
- name: "{{ $name }}"
mountPath: "{{ $volume.mountPath }}"
{{- end }}
{{- range .Values.frontend.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- with .Values.frontend.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.frontend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.frontend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
configMap:
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
{{- end }}
{{- range $name, $volume := .Values.frontend.persistence }}
- name: "{{ $name }}"
{{- if eq $volume.type "emptyDir" }}
emptyDir: {}
{{- else }}
persistentVolumeClaim:
claimName: "{{ $fullName }}-{{ $name }}"
{{- end }}
{{- end }}
{{- range .Values.frontend.extraVolumes }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
hostPath:
{{ toYaml .hostPath | nindent 12 }}
{{- else if .csi }}
csi:
{{- toYaml .csi | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}

View File

@@ -1,21 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.frontend) -}}
{{- $fullName := include "impress.frontend.fullname" . -}}
{{- $component := "frontend" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
annotations:
{{- toYaml $.Values.frontend.service.annotations | nindent 4 }}
spec:
type: {{ .Values.frontend.service.type }}
ports:
- port: {{ .Values.frontend.service.port }}
targetPort: {{ .Values.frontend.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}

View File

@@ -1,118 +0,0 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "impress.fullname" . -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls.enabled }}
tls:
{{- if .Values.ingress.host }}
- secretName: {{ $fullName }}-tls
hosts:
- {{ .Values.ingress.host | quote }}
{{- end }}
{{- range .Values.ingress.tls.additional }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- if .Values.ingress.host }}
- host: {{ .Values.ingress.host | quote }}
http:
paths:
- path: {{ .Values.ingress.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.frontend.fullname" . }}
port:
number: {{ .Values.frontend.service.port }}
{{- else }}
serviceName: {{ include "impress.frontend.fullname" . }}
servicePort: {{ .Values.frontend.service.port }}
{{- end }}
- path: /api
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.backend.fullname" . }}
port:
number: {{ .Values.backend.service.port }}
{{- else }}
serviceName: {{ include "impress.backend.fullname" . }}
servicePort: {{ .Values.backend.service.port }}
{{- end }}
{{- with .Values.ingress.customBackends }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}
{{- range .Values.ingress.hosts }}
- host: {{ . | quote }}
http:
paths:
- path: {{ $.Values.ingress.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.frontend.fullname" $ }}
port:
number: {{ $.Values.frontend.service.port }}
{{- else }}
serviceName: {{ include "impress.frontend.fullname" $ }}
servicePort: {{ $.Values.frontend.service.port }}
{{- end }}
- path: /api
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.backend.fullname" $ }}
port:
number: {{ $.Values.backend.service.port }}
{{- else }}
serviceName: {{ include "impress.backend.fullname" $ }}
servicePort: {{ $.Values.backend.service.port }}
{{- end }}
{{- with $.Values.ingress.customBackends }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -1,98 +0,0 @@
{{- if .Values.ingressAdmin.enabled -}}
{{- $fullName := include "impress.fullname" . -}}
{{- if and .Values.ingressAdmin.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingressAdmin.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingressAdmin.annotations "kubernetes.io/ingress.class" .Values.ingressAdmin.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}-admin
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.labels" . | nindent 4 }}
{{- with .Values.ingressAdmin.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingressAdmin.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingressAdmin.className }}
{{- end }}
{{- if .Values.ingressAdmin.tls.enabled }}
tls:
{{- if .Values.ingressAdmin.host }}
- secretName: {{ $fullName }}-tls
hosts:
- {{ .Values.ingressAdmin.host | quote }}
{{- end }}
{{- range .Values.ingressAdmin.tls.additional }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- if .Values.ingressAdmin.host }}
- host: {{ .Values.ingressAdmin.host | quote }}
http:
paths:
- path: {{ .Values.ingressAdmin.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.backend.fullname" . }}
port:
number: {{ .Values.backend.service.port }}
{{- else }}
serviceName: {{ include "impress.backend.fullname" . }}
servicePort: {{ .Values.backend.service.port }}
{{- end }}
- path: /static
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.backend.fullname" . }}
port:
number: {{ .Values.backend.service.port }}
{{- else }}
serviceName: {{ include "impress.backend.fullname" . }}
servicePort: {{ .Values.backend.service.port }}
{{- end }}
{{- end }}
{{- range .Values.ingressAdmin.hosts }}
- host: {{ . | quote }}
http:
paths:
- path: {{ $.Values.ingressAdmin.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.backend.fullname" $ }}
port:
number: {{ $.Values.backend.service.port }}
{{- else }}
serviceName: {{ include "impress.backend.fullname" $ }}
servicePort: {{ $.Values.backend.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -1,83 +0,0 @@
{{- if .Values.ingressMedia.enabled -}}
{{- $fullName := include "impress.fullname" . -}}
{{- if and .Values.ingressMedia.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingressMedia.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingressMedia.annotations "kubernetes.io/ingress.class" .Values.ingressMedia.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}-media
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.labels" . | nindent 4 }}
{{- with .Values.ingressMedia.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingressMedia.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingressMedia.className }}
{{- end }}
{{- if .Values.ingressMedia.tls.enabled }}
tls:
{{- if .Values.ingressMedia.host }}
- secretName: {{ $fullName }}-tls
hosts:
- {{ .Values.ingressMedia.host | quote }}
{{- end }}
{{- range .Values.ingressMedia.tls.additional }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- if .Values.ingressMedia.host }}
- host: {{ .Values.ingressMedia.host | quote }}
http:
paths:
- path: {{ .Values.ingressMedia.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}-media
port:
number: {{ .Values.serviceMedia.port }}
{{- else }}
serviceName: {{ $fullName }}-media
servicePort: {{ .Values.serviceMedia.port }}
{{- end }}
{{- end }}
{{- range .Values.ingressMedia.hosts }}
- host: {{ . | quote }}
http:
paths:
- path: {{ $.Values.ingressMedia.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}-media
port:
number: {{ .Values.serviceMedia.port }}
{{- else }}
serviceName: {{ $fullName }}-media
servicePort: {{ .Values.serviceMedia.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -1,72 +0,0 @@
{{- if .Values.ingressWS.enabled -}}
{{- $fullName := include "impress.fullname" . -}}
{{- if and .Values.ingressWS.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingressWS.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingressWS.annotations "kubernetes.io/ingress.class" .Values.ingressWS.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}-ws
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.labels" . | nindent 4 }}
{{- with .Values.ingressWS.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingressWS.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingressWS.className }}
{{- end }}
{{- if .Values.ingressWS.tls.enabled }}
tls:
{{- if .Values.ingressWS.host }}
- secretName: {{ $fullName }}-tls
hosts:
- {{ .Values.ingressWS.host | quote }}
{{- end }}
{{- range .Values.ingressWS.tls.additional }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- if .Values.ingressWS.host }}
- host: {{ .Values.ingressWS.host | quote }}
http:
paths:
- path: {{ .Values.ingressWS.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: ImplementationSpecific
{{- end }}
backend:
service:
name: {{ include "impress.yProvider.fullname" . }}
port:
number: {{ .Values.yProvider.service.port }}
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.yProvider.fullname" . }}
port:
number: {{ .Values.yProvider.service.port }}
{{- else }}
serviceName: {{ include "impress.yProvider.fullname" . }}
servicePort: {{ .Values.yProvider.service.port }}
{{- end }}
{{- with .Values.ingressWS.customBackends }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -1,14 +0,0 @@
{{- $fullName := include "impress.fullname" . -}}
{{- $component := "media" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $fullName }}-media
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
annotations:
{{- toYaml $.Values.serviceMedia.annotations | nindent 4 }}
spec:
type: ExternalName
externalName: {{ $.Values.serviceMedia.host }}

View File

@@ -1,23 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: backend
namespace: {{ .Release.Namespace | quote }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
stringData:
DJANGO_SUPERUSER_EMAIL: {{ .Values.djangoSuperUserEmail }}
DJANGO_SUPERUSER_PASSWORD: {{ .Values.djangoSuperUserPass }}
DJANGO_SECRET_KEY: {{ .Values.djangoSecretKey }}
{{- if .Values.djangoEmailHostUser }}
DJANGO_EMAIL_HOST_USER: {{ .Values.djangoEmailHostUser }}
{{- end }}
{{- if .Values.djangoEmailHostPassword }}
DJANGO_EMAIL_HOST_PASSWORD: {{ .Values.djangoEmailHostPassword }}
{{- end }}
OIDC_RP_CLIENT_ID: {{ .Values.oidc.clientId }}
OIDC_RP_CLIENT_SECRET: {{ .Values.oidc.clientSecret }}
AI_API_KEY: {{ .Values.aiApiKey }}
AI_BASE_URL: {{ .Values.aiBaseUrl }}

View File

@@ -1,136 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.yProvider) -}}
{{- $fullName := include "impress.yProvider.fullname" . -}}
{{- $component := "yProvider" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
replicas: {{ .Values.yProvider.replicas }}
selector:
matchLabels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
template:
metadata:
annotations:
{{- with .Values.yProvider.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
spec:
{{- if $.Values.image.credentials }}
imagePullSecrets:
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
{{- end}}
shareProcessNamespace: {{ .Values.yProvider.shareProcessNamespace }}
containers:
{{- with .Values.yProvider.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ (.Values.yProvider.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.yProvider.image | default dict).tag | default .Values.image.tag }}"
imagePullPolicy: {{ (.Values.yProvider.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
{{- with .Values.yProvider.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.yProvider.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if $envVars}}
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.yProvider.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.yProvider.service.targetPort }}
protocol: TCP
{{- if .Values.yProvider.probes.liveness }}
livenessProbe:
{{- include "impress.probes.abstract" (merge .Values.yProvider.probes.liveness (dict "targetPort" .Values.yProvider.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.yProvider.probes.readiness }}
readinessProbe:
{{- include "impress.probes.abstract" (merge .Values.yProvider.probes.readiness (dict "targetPort" .Values.yProvider.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.yProvider.probes.startup }}
startupProbe:
{{- include "impress.probes.abstract" (merge .Values.yProvider.probes.startup (dict "targetPort" .Values.yProvider.service.targetPort )) | nindent 12 }}
{{- end }}
{{- with .Values.yProvider.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
mountPath: {{ $value.path }}
subPath: content
{{- end }}
{{- range $name, $volume := .Values.yProvider.persistence }}
- name: "{{ $name }}"
mountPath: "{{ $volume.mountPath }}"
{{- end }}
{{- range .Values.yProvider.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- with .Values.yProvider.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.yProvider.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.yProvider.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
configMap:
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
{{- end }}
{{- range $name, $volume := .Values.yProvider.persistence }}
- name: "{{ $name }}"
{{- if eq $volume.type "emptyDir" }}
emptyDir: {}
{{- else }}
persistentVolumeClaim:
claimName: "{{ $fullName }}-{{ $name }}"
{{- end }}
{{- end }}
{{- range .Values.yProvider.extraVolumes }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
hostPath:
{{ toYaml .hostPath | nindent 12 }}
{{- else if .csi }}
csi:
{{- toYaml .csi | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}

View File

@@ -1,21 +0,0 @@
{{- $envVars := include "impress.common.env" (list . .Values.yProvider) -}}
{{- $fullName := include "impress.yProvider.fullname" . -}}
{{- $component := "yProvider" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
annotations:
{{- toYaml $.Values.yProvider.service.annotations | nindent 4 }}
spec:
type: {{ .Values.yProvider.service.type }}
ports:
- port: {{ .Values.yProvider.service.port }}
targetPort: {{ .Values.yProvider.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}

View File

@@ -1,415 +0,0 @@
# Default values for impress.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
## @section General configuration
## @param image.repository Repository to use to pull impress's container image
## @param image.tag impress's container tag
## @param image.pullPolicy Container image pull policy
## @extra image.credentials.username Username for container registry authentication
## @extra image.credentials.password Password for container registry authentication
## @extra image.credentials.registry Registry url for which the credentials are specified
## @extra image.credentials.name Name of the generated secret for imagePullSecrets
image:
repository: lasuite/impress-backend
pullPolicy: IfNotPresent
tag: "latest"
## @param nameOverride Override the chart name
## @param fullnameOverride Override the full application name
nameOverride: ""
fullnameOverride: ""
## @skip commonEnvVars
commonEnvVars: &commonEnvVars
<<: []
## @param ingress.enabled whether to enable the Ingress or not
## @param ingress.className IngressClass to use for the Ingress
## @param ingress.host Host for the Ingress
## @param ingress.path Path to use for the Ingress
ingress:
enabled: false
className: null
host: impress.example.com
path: /
## @param ingress.hosts Additional host to configure for the Ingress
hosts: []
# - chart-example.local
## @param ingress.tls.enabled Wether to enable TLS for the Ingress
## @skip ingress.tls.additional
## @extra ingress.tls.additional[].secretName Secret name for additional TLS config
## @extra ingress.tls.additional[].hosts[] Hosts for additional TLS config
tls:
enabled: true
additional: []
## @param ingress.customBackends Add custom backends to ingress
customBackends: []
## @param ingressWS.enabled whether to enable the Ingress or not
## @param ingressWS.className IngressClass to use for the Ingress
## @param ingressWS.host Host for the Ingress
## @param ingressWS.path Path to use for the Ingress
ingressWS:
enabled: false
className: null
host: impress.example.com
path: /ws
## @param ingress.hosts Additional host to configure for the Ingress
hosts: []
# - chart-example.local
## @param ingressWS.tls.enabled Wether to enable TLS for the Ingress
## @skip ingressWS.tls.additional
## @extra ingressWS.tls.additional[].secretName Secret name for additional TLS config
## @extra ingressWS.tls.additional[].hosts[] Hosts for additional TLS config
tls:
enabled: true
additional: []
## @param ingressWS.customBackends Add custom backends to ingress
customBackends: []
annotations:
nginx.ingress.kubernetes.io/enable-websocket: "true"
nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"
## @param ingressAdmin.enabled whether to enable the Ingress or not
## @param ingressAdmin.className IngressClass to use for the Ingress
## @param ingressAdmin.host Host for the Ingress
## @param ingressAdmin.path Path to use for the Ingress
ingressAdmin:
enabled: false
className: null
host: impress.example.com
path: /admin
## @param ingressAdmin.hosts Additional host to configure for the Ingress
hosts: [ ]
# - chart-example.local
## @param ingressAdmin.tls.enabled Wether to enable TLS for the Ingress
## @skip ingressAdmin.tls.additional
## @extra ingressAdmin.tls.additional[].secretName Secret name for additional TLS config
## @extra ingressAdmin.tls.additional[].hosts[] Hosts for additional TLS config
tls:
enabled: true
additional: []
## @param ingressMedia.enabled whether to enable the Ingress or not
## @param ingressMedia.className IngressClass to use for the Ingress
## @param ingressMedia.host Host for the Ingress
## @param ingressMedia.path Path to use for the Ingress
ingressMedia:
enabled: false
className: null
host: impress.example.com
path: /media/(.*)
## @param ingressMedia.hosts Additional host to configure for the Ingress
hosts: [ ]
# - chart-example.local
## @param ingressMedia.tls.enabled Wether to enable TLS for the Ingress
## @skip ingressMedia.tls.additional
## @extra ingressMedia.tls.additional[].secretName Secret name for additional TLS config
## @extra ingressMedia.tls.additional[].hosts[] Hosts for additional TLS config
tls:
enabled: true
additional: []
annotations:
nginx.ingress.kubernetes.io/auth-url: https://impress.example.com/api/v1.0/documents/retrieve-auth/
nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256"
nginx.ingress.kubernetes.io/upstream-vhost: minio.impress.svc.cluster.local:9000
serviceMedia:
host: minio.impress.svc.cluster.local
port: 9000
annotations: {}
## @section backend
backend:
## @param backend.command Override the backend container command
command: []
## @param backend.args Override the backend container args
args: []
## @param backend.replicas Amount of backend replicas
replicas: 3
## @param backend.shareProcessNamespace Enable share process namespace between containers
shareProcessNamespace: false
## @param backend.sidecars Add sidecars containers to backend deployment
sidecars: []
## @param backend.migrateJobAnnotations Annotations for the migrate job
migrateJobAnnotations: {}
## @param backend.securityContext Configure backend Pod security context
securityContext: null
## @param backend.envVars Configure backend container environment variables
## @extra backend.envVars.BY_VALUE Example environment variable by setting value directly
## @extra backend.envVars.FROM_CONFIGMAP.configMapKeyRef.name Name of a ConfigMap when configuring env vars from a ConfigMap
## @extra backend.envVars.FROM_CONFIGMAP.configMapKeyRef.key Key within a ConfigMap when configuring env vars from a ConfigMap
## @extra backend.envVars.FROM_SECRET.secretKeyRef.name Name of a Secret when configuring env vars from a Secret
## @extra backend.envVars.FROM_SECRET.secretKeyRef.key Key within a Secret when configuring env vars from a Secret
## @skip backend.envVars
envVars:
<<: *commonEnvVars
## @param backend.podAnnotations Annotations to add to the backend Pod
podAnnotations: {}
## @param backend.service.type backend Service type
## @param backend.service.port backend Service listening port
## @param backend.service.targetPort backend container listening port
## @param backend.service.annotations Annotations to add to the backend Service
service:
type: ClusterIP
port: 80
targetPort: 8000
annotations: {}
## @param backend.migrate.command backend migrate command
## @param backend.migrate.restartPolicy backend migrate job restart policy
migrate:
command:
- "python"
- "manage.py"
- "migrate"
- "--no-input"
restartPolicy: Never
## @param backend.probes.liveness.path [nullable] Configure path for backend HTTP liveness probe
## @param backend.probes.liveness.targetPort [nullable] Configure port for backend HTTP liveness probe
## @param backend.probes.liveness.initialDelaySeconds [nullable] Configure initial delay for backend liveness probe
## @param backend.probes.liveness.initialDelaySeconds [nullable] Configure timeout for backend liveness probe
## @param backend.probes.startup.path [nullable] Configure path for backend HTTP startup probe
## @param backend.probes.startup.targetPort [nullable] Configure port for backend HTTP startup probe
## @param backend.probes.startup.initialDelaySeconds [nullable] Configure initial delay for backend startup probe
## @param backend.probes.startup.initialDelaySeconds [nullable] Configure timeout for backend startup probe
## @param backend.probes.readiness.path [nullable] Configure path for backend HTTP readiness probe
## @param backend.probes.readiness.targetPort [nullable] Configure port for backend HTTP readiness probe
## @param backend.probes.readiness.initialDelaySeconds [nullable] Configure initial delay for backend readiness probe
## @param backend.probes.readiness.initialDelaySeconds [nullable] Configure timeout for backend readiness probe
probes:
liveness:
path: /__heartbeat__
initialDelaySeconds: 10
readiness:
path: /__lbheartbeat__
initialDelaySeconds: 10
## @param backend.resources Resource requirements for the backend container
resources: {}
## @param backend.nodeSelector Node selector for the backend Pod
nodeSelector: {}
## @param backend.tolerations Tolerations for the backend Pod
tolerations: []
## @param backend.affinity Affinity for the backend Pod
affinity: {}
## @param backend.persistence Additional volumes to create and mount on the backend. Used for debugging purposes
## @extra backend.persistence.volume-name.size Size of the additional volume
## @extra backend.persistence.volume-name.type Type of the additional volume, persistentVolumeClaim or emptyDir
## @extra backend.persistence.volume-name.mountPath Path where the volume should be mounted to
persistence: {}
## @param backend.extraVolumeMounts Additional volumes to mount on the backend.
extraVolumeMounts: []
## @param backend.extraVolumes Additional volumes to mount on the backend.
extraVolumes: []
## @section frontend
frontend:
## @param frontend.image.repository Repository to use to pull impress's frontend container image
## @param frontend.image.tag impress's frontend container tag
## @param frontend.image.pullPolicy frontend container image pull policy
image:
repository: lasuite/impress-frontend
pullPolicy: IfNotPresent
tag: "latest"
## @param frontend.command Override the frontend container command
command: []
## @param frontend.args Override the frontend container args
args: []
## @param frontend.replicas Amount of frontend replicas
replicas: 3
## @param frontend.shareProcessNamespace Enable share process namefrontend between containers
shareProcessNamespace: false
## @param frontend.sidecars Add sidecars containers to frontend deployment
sidecars: []
## @param frontend.securityContext Configure frontend Pod security context
securityContext: null
## @param frontend.envVars Configure frontend container environment variables
## @extra frontend.envVars.BY_VALUE Example environment variable by setting value directly
## @extra frontend.envVars.FROM_CONFIGMAP.configMapKeyRef.name Name of a ConfigMap when configuring env vars from a ConfigMap
## @extra frontend.envVars.FROM_CONFIGMAP.configMapKeyRef.key Key within a ConfigMap when configuring env vars from a ConfigMap
## @extra frontend.envVars.FROM_SECRET.secretKeyRef.name Name of a Secret when configuring env vars from a Secret
## @extra frontend.envVars.FROM_SECRET.secretKeyRef.key Key within a Secret when configuring env vars from a Secret
## @skip frontend.envVars
envVars:
<<: *commonEnvVars
## @param frontend.podAnnotations Annotations to add to the frontend Pod
podAnnotations: {}
## @param frontend.service.type frontend Service type
## @param frontend.service.port frontend Service listening port
## @param frontend.service.targetPort frontend container listening port
## @param frontend.service.annotations Annotations to add to the frontend Service
service:
type: ClusterIP
port: 80
targetPort: 8080
annotations: {}
## @param frontend.probes Configure probe for frontend
## @extra frontend.probes.liveness.path Configure path for frontend HTTP liveness probe
## @extra frontend.probes.liveness.targetPort Configure port for frontend HTTP liveness probe
## @extra frontend.probes.liveness.initialDelaySeconds Configure initial delay for frontend liveness probe
## @extra frontend.probes.liveness.initialDelaySeconds Configure timeout for frontend liveness probe
## @extra frontend.probes.startup.path Configure path for frontend HTTP startup probe
## @extra frontend.probes.startup.targetPort Configure port for frontend HTTP startup probe
## @extra frontend.probes.startup.initialDelaySeconds Configure initial delay for frontend startup probe
## @extra frontend.probes.startup.initialDelaySeconds Configure timeout for frontend startup probe
## @extra frontend.probes.readiness.path Configure path for frontend HTTP readiness probe
## @extra frontend.probes.readiness.targetPort Configure port for frontend HTTP readiness probe
## @extra frontend.probes.readiness.initialDelaySeconds Configure initial delay for frontend readiness probe
## @extra frontend.probes.readiness.initialDelaySeconds Configure timeout for frontend readiness probe
probes: {}
## @param frontend.resources Resource requirements for the frontend container
resources: {}
## @param frontend.nodeSelector Node selector for the frontend Pod
nodeSelector: {}
## @param frontend.tolerations Tolerations for the frontend Pod
tolerations: []
## @param frontend.affinity Affinity for the frontend Pod
affinity: {}
## @param frontend.persistence Additional volumes to create and mount on the frontend. Used for debugging purposes
## @extra frontend.persistence.volume-name.size Size of the additional volume
## @extra frontend.persistence.volume-name.type Type of the additional volume, persistentVolumeClaim or emptyDir
## @extra frontend.persistence.volume-name.mountPath Path where the volume should be mounted to
persistence: {}
## @param frontend.extraVolumeMounts Additional volumes to mount on the frontend.
extraVolumeMounts: []
## @param frontend.extraVolumes Additional volumes to mount on the frontend.
extraVolumes: []
## @section yProvider
yProvider:
## @param yProvider.image.repository Repository to use to pull impress's yProvider container image
## @param yProvider.image.tag impress's yProvider container tag
## @param yProvider.image.pullPolicy yProvider container image pull policy
image:
repository: lasuite/impress-y-provider
pullPolicy: IfNotPresent
tag: "latest"
## @param yProvider.command Override the yProvider container command
command: []
## @param yProvider.args Override the yProvider container args
args: []
## @param yProvider.replicas Amount of yProvider replicas
replicas: 3
## @param yProvider.shareProcessNamespace Enable share process nameyProvider between containers
shareProcessNamespace: false
## @param yProvider.sidecars Add sidecars containers to yProvider deployment
sidecars: []
## @param yProvider.securityContext Configure yProvider Pod security context
securityContext: null
## @param yProvider.envVars Configure yProvider container environment variables
## @extra yProvider.envVars.BY_VALUE Example environment variable by setting value directly
## @extra yProvider.envVars.FROM_CONFIGMAP.configMapKeyRef.name Name of a ConfigMap when configuring env vars from a ConfigMap
## @extra yProvider.envVars.FROM_CONFIGMAP.configMapKeyRef.key Key within a ConfigMap when configuring env vars from a ConfigMap
## @extra yProvider.envVars.FROM_SECRET.secretKeyRef.name Name of a Secret when configuring env vars from a Secret
## @extra yProvider.envVars.FROM_SECRET.secretKeyRef.key Key within a Secret when configuring env vars from a Secret
## @skip yProvider.envVars
envVars:
<<: *commonEnvVars
## @param yProvider.podAnnotations Annotations to add to the yProvider Pod
podAnnotations: {}
## @param yProvider.service.type yProvider Service type
## @param yProvider.service.port yProvider Service listening port
## @param yProvider.service.targetPort yProvider container listening port
## @param yProvider.service.annotations Annotations to add to the yProvider Service
service:
type: ClusterIP
port: 443
targetPort: 4444
annotations: {}
## @param yProvider.probes Configure probe for yProvider
## @extra yProvider.probes.liveness.path Configure path for yProvider HTTP liveness probe
## @extra yProvider.probes.liveness.targetPort Configure port for yProvider HTTP liveness probe
## @extra yProvider.probes.liveness.initialDelaySeconds Configure initial delay for yProvider liveness probe
## @extra yProvider.probes.liveness.initialDelaySeconds Configure timeout for yProvider liveness probe
## @extra yProvider.probes.startup.path Configure path for yProvider HTTP startup probe
## @extra yProvider.probes.startup.targetPort Configure port for yProvider HTTP startup probe
## @extra yProvider.probes.startup.initialDelaySeconds Configure initial delay for yProvider startup probe
## @extra yProvider.probes.startup.initialDelaySeconds Configure timeout for yProvider startup probe
## @extra yProvider.probes.readiness.path Configure path for yProvider HTTP readiness probe
## @extra yProvider.probes.readiness.targetPort Configure port for yProvider HTTP readiness probe
## @extra yProvider.probes.readiness.initialDelaySeconds Configure initial delay for yProvider readiness probe
## @extra yProvider.probes.readiness.initialDelaySeconds Configure timeout for yProvider readiness probe
probes:
liveness:
path: /ping
initialDelaySeconds: 10
## @param yProvider.resources Resource requirements for the yProvider container
resources: {}
## @param yProvider.nodeSelector Node selector for the yProvider Pod
nodeSelector: {}
## @param yProvider.tolerations Tolerations for the yProvider Pod
tolerations: []
## @param yProvider.affinity Affinity for the yProvider Pod
affinity: {}
## @param yProvider.persistence Additional volumes to create and mount on the yProvider. Used for debugging purposes
## @extra yProvider.persistence.volume-name.size Size of the additional volume
## @extra yProvider.persistence.volume-name.type Type of the additional volume, persistentVolumeClaim or emptyDir
## @extra yProvider.persistence.volume-name.mountPath Path where the volume should be mounted to
persistence: {}
## @param yProvider.extraVolumeMounts Additional volumes to mount on the yProvider.
extraVolumeMounts: []
## @param yProvider.extraVolumes Additional volumes to mount on the yProvider.
extraVolumes: []