Skip to content

Commit

Permalink
Merge branch 'main' into 3594-add-cohort-groups
Browse files Browse the repository at this point in the history
  • Loading branch information
nicobret authored Nov 18, 2024
2 parents 3926d83 + 6231cb0 commit c20797c
Show file tree
Hide file tree
Showing 188 changed files with 14,764 additions and 4,624 deletions.
1 change: 1 addition & 0 deletions .github/workflows/deploy-custom-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ jobs:
image_name: ${{matrix.app.name}}
dockerfile_path: ${{matrix.app.path}}/Dockerfile
image_tag: ${{matrix.app.tag}}
image_tag_stable: "custom-latest"
sentry_auth_token: ${{ secrets.SENTRY_AUTH_TOKEN }}

deploy:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-tests-api-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
id: cache-npm
with:
path: |
apiv2/node_modules
node_modules
api/node_modules
app/node_modules
Expand Down
56 changes: 56 additions & 0 deletions .github/workflows/run-tests-api-v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: API V2 - Run Tests

on:
workflow_dispatch:
workflow_call:
inputs:
branch_name:
required: true
type: string
pull_request:
branches:
- main
merge_group:
types:
- checks_requested

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch_name }}

- name: Node 18.x
uses: actions/setup-node@v4
with:
node-version: 18.x

- uses: actions/cache@v4
id: cache-npm
with:
path: |
apiv2/node_modules
node_modules
api/node_modules
app/node_modules
admin/node_modules
packages/ds/node_modules
packages/lib/node_modules
key: ${{ runner.os }}-nodemodules-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-nodemodules-
- name: Install packages
if: steps.cache-npm.outputs.cache-hit != 'true'
run: npm ci

- name: Build lib
working-directory: packages/lib
run: npm run build

- name: Run tests
working-directory: apiv2
run: npm test
1 change: 1 addition & 0 deletions .github/workflows/run-tests-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
id: cache-npm
with:
path: |
apiv2/node_modules
node_modules
api/node_modules
app/node_modules
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-tests-front.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
id: cache-npm
with:
path: |
apiv2/node_modules
node_modules
api/node_modules
app/node_modules
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-tests-lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
id: cache-npm
with:
path: |
apiv2/node_modules
node_modules
api/node_modules
app/node_modules
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

.vscode/*
!.vscode/tasks.json
!.vscode/settings.json
.env*
.cache_ggshield
Zammadwebhook.json
Expand Down
23 changes: 23 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"jest.shell": "/bin/zsh",
"jest.virtualFolders": [
{
"name": "snu-api-v2",
"rootPath": "apiv2",
"jestCommandLine": "source ~/.zshrc && nvm use && npm run test --",
"runMode": "on-demand"
},
{
"name": "snu-api-v1",
"rootPath": "api",
"jestCommandLine": "source ~/.zshrc && nvm use && npm run test --",
"runMode": "on-demand"
},
{
"name": "snu-lib",
"rootPath": "packages/lib",
"jestCommandLine": "source ~/.zshrc && nvm use && npm run test --",
"runMode": "watch"
}
]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
import React from "react";
import React, { ReactElement } from "react";
import ChevronDown from "../assets/icons/ChevronDown";

type OptionGroupItem = {
key: string;
render: React.ReactNode;
};

interface SelectActionProps {
optionsGroup: Array<{
key: string;
title: string | React.ReactNode;
items: Array<OptionGroupItem>;
}>;
title: string;
Icon?: ReactElement;
disabled?: boolean;
alignItems?: "left" | "center" | "right";
buttonClassNames?: string;
textClassNames?: string;
rightIconClassNames?: string;
}

export default function SelectAction({
optionsGroup,
title,
Expand All @@ -10,11 +30,11 @@ export default function SelectAction({
buttonClassNames = "border-[1px] border-gray-300",
textClassNames = "text-gray-700 font-medium text-sm",
rightIconClassNames = "text-gray-400",
}) {
}: SelectActionProps) {
const [open, setOpen] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const [loadingLabel, setLoadingLabel] = React.useState("Chargement...");
const ref = React.useRef(null);
const ref = React.useRef<HTMLDivElement>(null);

const onClickItem = async (item) => {
setLoading(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,41 @@ function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}

export interface Filter {
title?: string;
name?: string;
missingLabel?: string;
translate?: (item: any) => any;
filter?: any[];
// custom ?
parentGroup?: string;
customComponent?: any;
defaultValue?: string | string[];
isSingle?: boolean;
reduce?: (value: any[]) => any[];
sort?: (value: any[]) => any[];
getQuery?: (value: any) => any;
allowEmpty?: boolean;
disabledBaseQuery?: boolean;
options?: any;
}

interface FiltersProps {
route: string;
pageId: string;
filters: Filter[];
searchPlaceholder?: string;
setData: (data: any) => void;
selectedFilters: { [key: string]: Filter };
setSelectedFilters: (filters: { [key: string]: Filter }) => void;
paramData: any;
setParamData: (data: any) => void;
defaultUrlParam?: any;
size?: any;
intermediateFilters?: any[];
disabled?: boolean;
}

export default function Filters({
route,
pageId,
Expand All @@ -30,25 +65,25 @@ export default function Filters({
size,
intermediateFilters = [],
disabled = false,
}) {
}: FiltersProps) {
const [search, setSearch] = useState("");
const [dataFilter, setDataFilter] = useState({});
const [filtersVisible, setFiltersVisible] = useState(filters);
const [categories, setCategories] = useState([]);
const [categories, setCategories] = useState<string[]>([]);
const [savedView, setSavedView] = useState([]);
const [firstLoad, setFirstLoad] = useState(true);
const [isShowing, setIsShowing] = useState(false);
const [isShowing, setIsShowing] = useState<string | boolean>(false);

const location = useLocation();
const history = useHistory();

const ref = useRef(null);
const refFilter = useRef(null);
const ref = useRef<HTMLButtonElement>(null);
const refFilter = useRef<HTMLDivElement>(null);

const hasSomeFilterSelected =
selectedFilters &&
Object.keys(selectedFilters).find(
(key) => selectedFilters[key]?.filter?.length > 0 && selectedFilters[key]?.filter[0]?.toString().trim() !== "" && filters.find((f) => f.name === key),
(key) => selectedFilters[key]?.filter?.length && selectedFilters[key]?.filter?.[0]?.toString().trim() !== "" && filters.find((f) => f.name === key),
);

// Initialization
Expand Down Expand Up @@ -87,10 +122,10 @@ export default function Filters({
setCategories([]);
return;
}
const newCategories = [];
const newCategories: string[] = [];
filtersVisible?.forEach((f) => {
if (!newCategories.includes(f.parentGroup)) {
newCategories.push(f.parentGroup);
if (!newCategories.includes(f.parentGroup!)) {
newCategories.push(f.parentGroup!);
}
});
setCategories(newCategories);
Expand All @@ -103,7 +138,11 @@ export default function Filters({
buildQuery(route, selectedFilters, paramData?.page, filters, paramData?.sort, size).then((res) => {
if (!res) return;
setDataFilter({ ...dataFilter, ...res.newFilters });
const newParamData = {
const newParamData: {
count: number;
filters: { [key: string]: Filter };
page?: number;
} = {
count: res.count,
filters: { ...dataFilter, ...res.newFilters },
};
Expand All @@ -130,9 +169,9 @@ export default function Filters({
const newFilters = {};
filters.map((f) => {
if (f?.customComponent?.getQuery) {
newFilters[f.name] = { filter: f.defaultValue, customComponentQuery: f.getQuery(f.defaultValue) };
newFilters[f?.name || ""] = { filter: f.defaultValue, customComponentQuery: f.getQuery?.(f.defaultValue) };
} else {
newFilters[f.name] = { filter: f?.defaultValue ? f.defaultValue : [] };
newFilters[f?.name || ""] = { filter: f?.defaultValue ? f.defaultValue : [] };
}
});
return newFilters;
Expand Down Expand Up @@ -182,7 +221,7 @@ export default function Filters({
<input
name={"searchbar"}
placeholder={searchPlaceholder}
value={selectedFilters?.searchbar?.filter[0] || ""}
value={selectedFilters?.searchbar?.filter?.[0] || ""}
onChange={(e) => {
setSelectedFilters({ ...selectedFilters, [e.target.name]: { filter: [e.target.value] } });
}}
Expand Down Expand Up @@ -249,6 +288,7 @@ export default function Filters({
allowEmpty: false,
customComponent: (setFilter, filter) => (
<IntermediateFilter
// @ts-expect-error
selectedFilters={selectedFilters}
setSelectedFilters={setSelectedFilters}
setParamData={setParamData}
Expand All @@ -262,10 +302,12 @@ export default function Filters({
return (
<FilterPopOver
key={item.title}
// @ts-expect-error
filter={customItem}
// @ts-expect-error
selectedFilters={selectedFilters}
setSelectedFilters={setSelectedFilters}
data={item?.disabledBaseQuery ? item.options : dataFilter[item?.name] || []}
data={item?.disabledBaseQuery ? item.options : dataFilter[item?.name || ""] || []}
isShowing={isShowing === item.name}
setIsShowing={(value) => setIsShowing(value)}
setParamData={setParamData}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import React, { useEffect, useState } from "react";
import { translate, translateField, translateIndexes } from "snu-lib";
import { translate, translateField } from "snu-lib";
import ExportFieldCard from "../../../ExportFieldCard";
import ModalTailwind from "../../../modals/ModalTailwind";
import plausibleEvent from "../../../../services/plausible";
import { capitalizeFirstLetter } from "../../../../utils";
import ExportComponent from "./ExportComponent";
import { Filter } from "../Filters";

export default function ModalExport({ isOpen, setIsOpen, route, transform, exportFields, exportTitle = "", totalHits = false, selectedFilters }) {
interface ExportField {
id: string;
title: string;
desc: string[];
fields: string[];
}

interface ModalExportProps {
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
route: string;
transform: (data: any, value: any) => void;
exportFields: ExportField[];
exportTitle?: string;
totalHits?: boolean;
selectedFilters: { [key: string]: Filter };
}

export default function ModalExport({ isOpen, setIsOpen, route, transform, exportFields, exportTitle, totalHits, selectedFilters }: ModalExportProps) {
const [selectedFields, setSelectedFields] = useState(exportFields?.map((e) => e.id));
const fieldsToExport = [].concat(...exportFields.filter((e) => selectedFields.includes(e.id)).map((e) => e.fields));
const fieldsToExport = ([] as string[]).concat(...exportFields.filter((e) => selectedFields.includes(e.id)).map((e) => e.fields));
const [hasFilter, setHasFilter] = useState(false);

useEffect(() => {
Expand All @@ -24,8 +42,8 @@ export default function ModalExport({ isOpen, setIsOpen, route, transform, expor
<p className="text-center text-sm text-gray-400">Rappel des filtres appliqués</p>
<p className="text-center text-sm text-gray-600">
{Object.keys(selectedFilters)
.filter((e) => selectedFilters[e]?.filter?.length && selectedFilters[e]?.filter[0] !== "")
.map((e) => `${translateField(e)} : ${translate(selectedFilters[e]?.filter)}`)
.filter((e) => selectedFilters?.[e]?.filter?.length && selectedFilters?.[e]?.filter?.[0] !== "")
.map((e) => `${translateField(e)} : ${translate(selectedFilters?.[e]?.filter)}`)
.join(" • ")}
</p>
</div>
Expand All @@ -34,6 +52,7 @@ export default function ModalExport({ isOpen, setIsOpen, route, transform, expor
<div className="flex justify-between">
<p className="text-left">Sélectionnez pour choisir des sous-catégories</p>
<div className="flex flex-row-reverse gap-2">
{/* @ts-expect-error FIXME */}
{selectedFields == "" ? (
<div className="cursor-pointer text-blue-600 hover:text-blue-400" onClick={() => setSelectedFields(exportFields.map((e) => e.id))}>
Tout sélectionner
Expand Down Expand Up @@ -66,6 +85,7 @@ export default function ModalExport({ isOpen, setIsOpen, route, transform, expor
exportTitle={exportTitle}
route={route}
transform={(data) => transform(data, selectedFields)}
// @ts-expect-error jsx component
fieldsToExport={fieldsToExport}
selectedFilters={selectedFilters}
setIsOpen={setIsOpen}
Expand Down
Loading

0 comments on commit c20797c

Please sign in to comment.