[#106] added prettier check to jenkins and prettified files (#109)

Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
Camille Moussu
2025-09-12 11:05:52 +02:00
committed by GitHub
parent 3b87965bed
commit d76775c7d2
16 changed files with 108 additions and 84 deletions
Vendored
+5
View File
@@ -26,6 +26,11 @@ pipeline {
sh 'npm run test' sh 'npm run test'
} }
} }
stage('Check Formatting') {
steps {
sh 'npx prettier --check .'
}
}
stage('Deploy docker images') { stage('Deploy docker images') {
when { when {
anyOf { anyOf {
+16 -3
View File
@@ -8,11 +8,20 @@ This project aims at service a Single Page Application allowing a user to intera
This frontend-only application will interact with: This frontend-only application will interact with:
- [esn-sabre](https://github.com/linagora/esn-sabre/) CalDAV + CardDAV server, tailor made for LINAGORA needs. - [esn-sabre](https://github.com/linagora/esn-sabre/) CalDAV + CardDAV server, tailor made for LINAGORA needs.
- [Twake Calendar side service](https://github.com/linagora/twake-calendar-side-service) that delivers additional backend features for Sabre. - [Twake Calendar side service](https://github.com/linagora/twake-calendar-side-service) that delivers additional backend features for Sabre.
It is meant as a drop in replacement of [esn-frontend-calendar](https://github.com/linagora/esn-frontend-calendar). It is meant as a drop in replacement of [esn-frontend-calendar](https://github.com/linagora/esn-frontend-calendar).
## Contributing
### Formating
We use [Prettier](https://prettier.io/) to keep code style consistent.
A `.prettierrc` file is already included in the repo, so formatting rules are predefined.
Before committing, make sure you format your files either using your IDE Prettier extension or Prettier CLI.
## Running it ## Running it
Requirement: node 24+ Requirement: node 24+
@@ -89,7 +98,11 @@ Example:
```js ```js
var appList = [ var appList = [
{ name: "My App", icon: "https://myapp.com/myapp.png", link: "https://myapp.com" }, {
name: "My App",
icon: "https://myapp.com/myapp.png",
link: "https://myapp.com",
},
]; ];
``` ```
@@ -111,7 +111,7 @@ describe("CalendarApp integration", () => {
openpaasId: "667037022b752d0026472254", openpaasId: "667037022b752d0026472254",
}, },
tokens: { tokens: {
accessToken: "token" accessToken: "token",
}, },
}, },
calendars: { calendars: {
@@ -133,14 +133,16 @@ describe("CalendarApp integration", () => {
cn: "Alice", cn: "Alice",
cal_address: "alice@example.com", cal_address: "alice@example.com",
}, },
attendee: [{ attendee: [
cn: "Alice", {
partstat: "ACCEPTED", cn: "Alice",
rsvp: "TRUE", partstat: "ACCEPTED",
role: "REQ-PARTICIPANT", rsvp: "TRUE",
cutype: "INDIVIDUAL", role: "REQ-PARTICIPANT",
cal_address: "alice@example.com", cutype: "INDIVIDUAL",
}, ], cal_address: "alice@example.com",
},
],
...eventProps, ...eventProps,
}, },
}, },
+20 -19
View File
@@ -57,33 +57,34 @@ describe("MiniCalendar", () => {
}); });
it.each([ it.each([
{ today: new Date(2025, 8, 1), label: "Monday 1 Sept 2025" }, { today: new Date(2025, 8, 1), label: "Monday 1 Sept 2025" },
{ today: new Date(2025, 8, 3), label: "Wednesday 3 Sept 2025" }, { today: new Date(2025, 8, 3), label: "Wednesday 3 Sept 2025" },
{ today: new Date(2025, 8, 7), label: "Sunday 7 Sept 2025" }, { today: new Date(2025, 8, 7), label: "Sunday 7 Sept 2025" },
])( ])(
"renders mini calendar with the week in gray (except for today) when today is $label", "renders mini calendar with the week in gray (except for today) when today is $label",
({ today }) => { ({ today }) => {
jest.useFakeTimers(); jest.useFakeTimers();
jest.setSystemTime(today); jest.setSystemTime(today);
renderCalendar(); renderCalendar();
const monday = new Date(2025, 8, 1); // Monday Sept 1 const monday = new Date(2025, 8, 1); // Monday Sept 1
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
const date = new Date(monday); const date = new Date(monday);
date.setDate(monday.getDate() + i); date.setDate(monday.getDate() + i);
const dateTestId = `date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; const dateTestId = `date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
const tile = screen.getByTestId(dateTestId); const tile = screen.getByTestId(dateTestId);
if (date.getTime() !== today.setHours(0, 0, 0, 0)) { if (date.getTime() !== today.setHours(0, 0, 0, 0)) {
expect(tile?.parentElement).toHaveClass("selectedWeek"); expect(tile?.parentElement).toHaveClass("selectedWeek");
}
} }
}
jest.useRealTimers(); jest.useRealTimers();
}); }
);
it("renders mini calendar with the day in gray (except for today) when full calendar in day view", async () => { it("renders mini calendar with the day in gray (except for today) when full calendar in day view", async () => {
renderCalendar(); renderCalendar();
@@ -95,15 +95,13 @@ describe("Event Preview Display", () => {
}; };
it("renders correctly event data", () => { it("renders correctly event data", () => {
jest jest.spyOn(Date.prototype, "toLocaleString").mockImplementation(function (
.spyOn(Date.prototype, "toLocaleString") this: Date,
.mockImplementation(function ( locales?: Intl.LocalesArgument,
this: Date, options?: Intl.DateTimeFormatOptions | undefined
locales?: Intl.LocalesArgument, ): string {
options?: Intl.DateTimeFormatOptions | undefined return RealDateToLocaleString.call(this, "en-UK", options);
): string { });
return RealDateToLocaleString.call(this, "en-UK", options);
});
renderWithProviders( renderWithProviders(
<EventPreviewModal <EventPreviewModal
anchorPosition={{ top: 0, left: 0 }} anchorPosition={{ top: 0, left: 0 }}
+2 -2
View File
@@ -1,6 +1,6 @@
module.exports = { module.exports = {
presets: [ presets: [
['@babel/preset-env', { targets: { node: 'current' } }], ["@babel/preset-env", { targets: { node: "current" } }],
['@babel/preset-react', { runtime: 'automatic', importSource: 'preact' }], ["@babel/preset-react", { runtime: "automatic", importSource: "preact" }],
], ],
}; };
+1 -1
View File
@@ -6,4 +6,4 @@ var SSO_RESPONSE_TYPE = "code";
var SSO_CODE_CHALLENGE_METHOD = "S256"; var SSO_CODE_CHALLENGE_METHOD = "S256";
var SSO_POST_LOGOUT_REDIRECT = "http://example.com?logout=1"; var SSO_POST_LOGOUT_REDIRECT = "http://example.com?logout=1";
var CALENDAR_BASE_URL = "https://calendar.example.com"; var CALENDAR_BASE_URL = "https://calendar.example.com";
var MAIL_SPA_URL = "https://mail.example.com" var MAIL_SPA_URL = "https://mail.example.com";
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
+7 -1
View File
@@ -1,5 +1,11 @@
declare namespace Intl { declare namespace Intl {
type Key = 'calendar' | 'collation' | 'currency' | 'numberingSystem' | 'timeZone' | 'unit'; type Key =
| "calendar"
| "collation"
| "currency"
| "numberingSystem"
| "timeZone"
| "unit";
function supportedValuesOf(input: Key): string[]; function supportedValuesOf(input: Key): string[];
} }
+4 -4
View File
@@ -1,5 +1,5 @@
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from './store' import type { RootState, AppDispatch } from "./store";
export const useAppDispatch = useDispatch.withTypes<AppDispatch>() export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>() export const useAppSelector = useSelector.withTypes<RootState>();
+3 -1
View File
@@ -133,7 +133,9 @@ main {
/* selected day hover */ /* selected day hover */
.react-calendar__tile { .react-calendar__tile {
transition: background-color 0.3s ease, color 0.3s ease; transition:
background-color 0.3s ease,
color 0.3s ease;
border: none; border: none;
background-color: white; background-color: white;
width: 12px; width: 12px;
+15 -6
View File
@@ -31,7 +31,7 @@ import { createSelector } from "@reduxjs/toolkit";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import ClearIcon from "@mui/icons-material/Clear"; import ClearIcon from "@mui/icons-material/Clear";
import AccessTimeIcon from "@mui/icons-material/AccessTime"; import AccessTimeIcon from "@mui/icons-material/AccessTime";
import LockIcon from '@mui/icons-material/Lock'; import LockIcon from "@mui/icons-material/Lock";
import { userAttendee } from "../../features/User/userDataTypes"; import { userAttendee } from "../../features/User/userDataTypes";
const computeStartOfTheWeek = (date: Date): Date => { const computeStartOfTheWeek = (date: Date): Date => {
@@ -204,7 +204,6 @@ export default function CalendarApp() {
calendarRef.current?.view.type === "timeGridWeek" || calendarRef.current?.view.type === "timeGridWeek" ||
calendarRef.current?.view.type === undefined calendarRef.current?.view.type === undefined
) { ) {
const startOfWeek = computeStartOfTheWeek(selected); const startOfWeek = computeStartOfTheWeek(selected);
const endOfWeek = new Date(startOfWeek); const endOfWeek = new Date(startOfWeek);
@@ -430,7 +429,9 @@ export default function CalendarApp() {
if (!calendars[arg.event._def.extendedProps.calId]) return; if (!calendars[arg.event._def.extendedProps.calId]) return;
const attendees = event._def.extendedProps.attendee || []; const attendees = event._def.extendedProps.attendee || [];
const isPrivate = event._def.extendedProps.class === "PRIVATE" || event._def.extendedProps.class === "CONFIDENTIAL"; const isPrivate =
event._def.extendedProps.class === "PRIVATE" ||
event._def.extendedProps.class === "CONFIDENTIAL";
let Icon = null; let Icon = null;
let titleStyle: React.CSSProperties = {}; let titleStyle: React.CSSProperties = {};
const ownerEmails = new Set( const ownerEmails = new Set(
@@ -461,9 +462,17 @@ export default function CalendarApp() {
} }
return ( return (
<div style={{ display: 'flex', alignItems: 'center' }}> <div style={{ display: "flex", alignItems: "center" }}>
{isPrivate && <LockIcon data-testid="lock-icon" fontSize="small" style={{ marginRight: '4px' }} />} {isPrivate && (
{Icon && <Icon fontSize="small" style={{ marginRight: '4px' }}/>} <LockIcon
data-testid="lock-icon"
fontSize="small"
style={{ marginRight: "4px" }}
/>
)}
{Icon && (
<Icon fontSize="small" style={{ marginRight: "4px" }} />
)}
<span style={titleStyle}>{event.title}</span> <span style={titleStyle}>{event.title}</span>
</div> </div>
); );
+5 -2
View File
@@ -28,7 +28,6 @@ function CalendarPopover({
const [timeZone, setTimeZone] = useState(""); const [timeZone, setTimeZone] = useState("");
const timezones = Intl.supportedValuesOf?.("timeZone") ?? []; const timezones = Intl.supportedValuesOf?.("timeZone") ?? [];
const handleSave = () => { const handleSave = () => {
dispatch(createCalendar({ name, description, color })); dispatch(createCalendar({ name, description, color }));
onClose({}, "backdropClick"); onClose({}, "backdropClick");
@@ -64,7 +63,11 @@ function CalendarPopover({
}} }}
> >
<Box p={2}> <Box p={2}>
<Typography variant="h6" gutterBottom style={{backgroundColor:color}}> <Typography
variant="h6"
gutterBottom
style={{ backgroundColor: color }}
>
Create a Calendar Create a Calendar
</Typography> </Typography>
<TextField <TextField
+1 -1
View File
@@ -58,7 +58,7 @@ export function parseCalendarEvent(
case "organizer": case "organizer":
event.organizer = { event.organizer = {
cn: params?.cn ?? "", cn: params?.cn ?? "",
cal_address: value.replace(/^mailto:/, ""), cal_address: value?.replace(/^mailto:/, ""),
}; };
break; break;
case "attendee": case "attendee":
+5 -5
View File
@@ -1,13 +1,13 @@
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family:
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
sans-serif; "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family:
monospace; source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
} }
-15
View File
@@ -1,15 +0,0 @@
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;