diff --git a/targets/frontend/src/components/button/index.js b/targets/frontend/src/components/button/index.js
index 5cd31c290..cbc1d0c4b 100644
--- a/targets/frontend/src/components/button/index.js
+++ b/targets/frontend/src/components/button/index.js
@@ -37,7 +37,6 @@ const defaultButtonStyles = {
lineHeight: "inherit",
m: 0,
minWidth: 0,
- p: 1,
textAlign: "center",
textDecoration: "none",
};
@@ -51,11 +50,13 @@ const smallSize = {
};
// function _Button({ outline = false, ...props }) {}
-export const Button = React.forwardRef(({ outline, ...props }, ref) => (
-
- {outline ? : }
-
-));
+export const Button = React.forwardRef(({ outline, ...props }, ref) =>
+ outline ? (
+
+ ) : (
+
+ )
+);
Button.propTypes = {
outline: PropTypes.bool,
...buttonPropTypes,
diff --git a/targets/frontend/src/components/changes/ViewDiff.js b/targets/frontend/src/components/changes/ViewDiff.js
index 6136e5ae8..f008e8a1b 100644
--- a/targets/frontend/src/components/changes/ViewDiff.js
+++ b/targets/frontend/src/components/changes/ViewDiff.js
@@ -44,7 +44,7 @@ export const ViewDiff = ({ sx, type, inputA, inputB }) => {
setMode("words")}
+ onChange={() => setMode("words")}
style={{ marginLeft: 10 }}
checked={mode === "words"}
/>{" "}
@@ -52,7 +52,7 @@ export const ViewDiff = ({ sx, type, inputA, inputB }) => {
setMode("sentences")}
+ onChange={() => setMode("sentences")}
style={{ marginLeft: 10 }}
checked={mode === "sentences"}
/>{" "}
diff --git a/targets/frontend/src/components/changes/index.js b/targets/frontend/src/components/changes/index.js
index d7827a8c1..c7e7987cb 100644
--- a/targets/frontend/src/components/changes/index.js
+++ b/targets/frontend/src/components/changes/index.js
@@ -130,45 +130,47 @@ export function DilaDiffChange({ change }) {
{isVisible ? : }
)}
-
-
- {showDiff && (
- <>
- Modification du texte
-
- >
- )}
- {showDiff && showNotaDiff && }
- {showNotaDiff && (
- <>
- Modification du Nota
-
- >
- )}
-
-
+ {isVisible && (
+
+
+ {showDiff && (
+ <>
+ Modification du texte
+
+ >
+ )}
+ {showDiff && showNotaDiff && }
+ {showNotaDiff && (
+ <>
+ Modification du Nota
+
+ >
+ )}
+
+
+ )}
);
}
diff --git a/targets/frontend/src/components/pagination/index.js b/targets/frontend/src/components/pagination/index.js
new file mode 100644
index 000000000..e25f64464
--- /dev/null
+++ b/targets/frontend/src/components/pagination/index.js
@@ -0,0 +1,87 @@
+/** @jsx jsx */
+import PropTypes from "prop-types";
+import { Flex, jsx } from "theme-ui";
+
+import { Button } from "../button";
+import { Inline } from "../layout/Inline";
+import { Li, List } from "../list";
+
+export function Pagination({
+ count,
+ onChange,
+ offset = 0,
+ pageSize = 10,
+ visibleRange = 2,
+}) {
+ const nbPage = Math.ceil(count / pageSize);
+ const currentPage = Math.floor(offset / pageSize);
+
+ const allPages = Array.from(Array(nbPage))
+ .map((_, page) => ({
+ index: page,
+ label: `${page + 1}`,
+ offset: pageSize * page,
+ }))
+ .map((page) => (
+
+
+
+ ));
+ const rangeStartIndex = Math.min(
+ Math.max(0, currentPage - visibleRange),
+ nbPage - visibleRange * 2 - 1
+ );
+ const rangeEndIndex = Math.min(
+ rangeStartIndex + 1 + visibleRange * 2,
+ nbPage
+ );
+
+ let startPagination = [];
+ if (rangeStartIndex > 2) {
+ startPagination = allPages
+ .slice(0, 1)
+ .concat(...);
+ } else {
+ startPagination = allPages.slice(0, 2);
+ }
+
+ let endPagination = [];
+ if (nbPage - rangeEndIndex > 2) {
+ endPagination = [...].concat(allPages.slice(-1));
+ } else {
+ endPagination = allPages.slice(-2);
+ }
+
+ const pages = allPages.slice(
+ Math.max(rangeStartIndex, 2),
+ Math.min(rangeEndIndex, nbPage - 2)
+ );
+ if (nbPage === 1) {
+ return null;
+ }
+ return (
+
+
+
+ {startPagination.concat(pages, endPagination)}
+
+
+
+ );
+}
+
+Pagination.propTypes = {
+ count: PropTypes.number.isRequired,
+ offset: PropTypes.number,
+ onChange: PropTypes.func.isRequired,
+ pageSize: PropTypes.number,
+ visibleRange: PropTypes.number,
+};
diff --git a/targets/frontend/src/hoc/UserProvider.js b/targets/frontend/src/hoc/UserProvider.js
index 5ef4f9342..0f43d9744 100644
--- a/targets/frontend/src/hoc/UserProvider.js
+++ b/targets/frontend/src/hoc/UserProvider.js
@@ -35,7 +35,6 @@ function withUserProvider(WrappedComponent) {
const componentProps =
WrappedComponent.getInitialProps &&
(await WrappedComponent.getInitialProps(ctx));
-
return { ...componentProps };
}
render() {
diff --git a/targets/frontend/src/pages/alerts/[[...params]].js b/targets/frontend/src/pages/alerts/[[...params]].js
index 3c5f2e593..29b8b3ce0 100644
--- a/targets/frontend/src/pages/alerts/[[...params]].js
+++ b/targets/frontend/src/pages/alerts/[[...params]].js
@@ -5,12 +5,13 @@ import slugify from "@socialgouv/cdtn-slugify";
import { getRouteBySource } from "@socialgouv/cdtn-sources";
import Link from "next/link";
import { useRouter } from "next/router";
-import { useMemo } from "react";
+import { useMemo, useState } from "react";
import { AlertTitle } from "src/components/alerts/AlertTitle";
import { DiffChange } from "src/components/changes";
import { ChangesGroup } from "src/components/changes/ChangeGroup";
import { Layout } from "src/components/layout/auth.layout";
import { Stack } from "src/components/layout/Stack";
+import { Pagination } from "src/components/pagination";
import { TabItem, Tabs } from "src/components/tabs";
import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient";
import { withUserProvider } from "src/hoc/UserProvider";
@@ -19,7 +20,7 @@ import { Card, Container, Divider, jsx, Message, NavLink } from "theme-ui";
import { useQuery } from "urql";
const getAlertQuery = `
-query getAlerts($status: String!, $repository: String!) {
+query getAlerts($status: String!, $repository: String!, $limit: Int!, $offset: Int!) {
statuses: alert_status {
name
alerts: alerts_aggregate(where: {
@@ -31,7 +32,7 @@ query getAlerts($status: String!, $repository: String!) {
__typename
}
}
- alerts(where: {
+ alerts(limit: $limit, offset: $offset, where: {
_and: [
{status: {_eq: $status}},
{repository: {_eq: $repository}},
@@ -50,6 +51,8 @@ query getAlerts($status: String!, $repository: String!) {
export function AlertPage() {
const router = useRouter();
+ const [offset, setOffset] = useState(0);
+ const pageSize = 10;
const [repo, activeStatus = "todo"] = router.query.params;
const repository = repo.replace(/_/, "/");
@@ -58,11 +61,15 @@ export function AlertPage() {
const [result] = useQuery({
context,
query: getAlertQuery,
- variables: { repository, status: activeStatus },
+ variables: {
+ limit: pageSize,
+ offset,
+ repository,
+ status: activeStatus,
+ },
});
const { fetching, error, data } = result;
- console.log(" render", result, repository, activeStatus);
if (fetching) {
return Chargement...;
@@ -93,6 +100,7 @@ export function AlertPage() {
).toLocaleDateString()} (${alert.ref})`;
}
}
+
return (
@@ -186,8 +194,27 @@ export function AlertPage() {
))}
+ name === activeStatus).alerts.aggregate
+ .count
+ }
+ pageSize={pageSize}
+ offset={offset}
+ onChange={({ offset }) => setOffset(offset)}
+ />
);
}
+/**
+ * This getInitialProps ensure useState to reset while page url change
+ * @see https://github.com/vercel/next.js/issues/9992
+ */
+AlertPage.getInitialProps = async function ({ query }) {
+ const [repo, activeStatus = "todo"] = query.params;
+ return {
+ key: `${repo}/${activeStatus}`,
+ };
+};
export default withCustomUrqlClient(withUserProvider(AlertPage));
diff --git a/targets/frontend/src/theme.js b/targets/frontend/src/theme.js
index e2fb509dd..d56c64e90 100644
--- a/targets/frontend/src/theme.js
+++ b/targets/frontend/src/theme.js
@@ -1,5 +1,7 @@
import { darken, rgba, transparentize } from "polished";
+/* eslint-disable sort-keys-fix/sort-keys-fix */
+
export const theme = {
badges: {
circle: {
@@ -14,6 +16,11 @@ export const theme = {
boxShadow: "inset 0 0 0 1px",
color: "primary",
},
+ accent: {
+ bg: "accent",
+ color: "white",
+ px: "xxsmall",
+ },
primary: {
bg: "primary",
color: "white",
@@ -37,6 +44,11 @@ export const theme = {
bgHover: "highlight",
color: "text",
},
+ accent: {
+ bg: "accent",
+ bgHover: "accentHover",
+ color: "white",
+ },
primary: {
bg: "primary",
bgHover: "primaryHover",
@@ -61,50 +73,51 @@ export const theme = {
padding: "small",
},
},
+
colors: {
accent: "#DA4167",
accentHover: darken(0.05, "#DA4167"),
+
+ text: "#3e486e",
background: "#fff",
+ white: "#fff",
black: "#232323",
- caution: "#FED766",
- critical: "#E03616",
+ link: "#004cce",
+ linkVisited: "#733d90",
focus: rgba("#1e90ff", 0.7),
- highlight: "#E6E6EA",
info: "#2AB7CA",
- link: "#004cce",
- linkVisited: "#733d90",
- muted: "#717780",
+ caution: "#FED766",
+ critical: "#E03616",
+ positive: "#43AA8B",
neutral: "#d1dffd",
+ muted: "#717780",
+ highlight: "#E6E6EA",
- positive: "#43AA8B",
primary: "#f66663",
-
primaryHover: darken(0.05, "#f66663"),
secondary: "#7994d4",
-
secondaryHover: darken(0.05, "#7994d4"),
- text: "#3e486e",
- white: "#fff",
},
fontSizes: {
0: "0.8rem",
- icons: "1.5rem",
- large: "1.4rem",
- medium: "1rem",
+ xxsmall: "0.7rem",
+ xsmall: "0.8rem",
small: "0.9rem",
+ medium: "1rem",
+ large: "1.4rem",
xlarge: "2rem",
- xsmall: "0.8rem",
xxlarge: "3.2rem",
+ icons: "1.5rem",
},
// fontSizes: [12, 14, 16, 20, 24, 32, 48, 64],
fontWeights: {
body: 300,
- bold: 600,
heading: 600,
light: 300,
regular: 400,
semibold: 600,
+ bold: 600,
},
fonts: {
body: "muli",
@@ -132,34 +145,35 @@ export const theme = {
heading: 1.125,
},
radii: {
- large: "8px",
small: "4px",
+ large: "8px",
xlarge: "16px",
},
shadows: {
card1: "0 0 8px rgba(0, 0, 0, 0.125)",
- large:
- "0 0 4px 0px rgba(28,28,28,.1), 0 3px 18px -4px rgba(28,28,28,.1), 0 5px 30px -12px rgba(28,28,28,.2)",
- medium:
- "0 0 4px 0px rgba(28,28,28,.1), 0 8px 8px -4px rgba(28,28,28,.1), 0 12px 12px -8px rgba(28,28,28,.2)",
small:
"0 0 4px 0px rgba(28,28,28,.1), 0 2px 2px -2px rgba(28,28,28,.1), 0 4px 4px -4px rgba(28,28,28,.2)",
+ medium:
+ "0 0 4px 0px rgba(28,28,28,.1), 0 8px 8px -4px rgba(28,28,28,.1), 0 12px 12px -8px rgba(28,28,28,.2)",
+ large:
+ "0 0 4px 0px rgba(28,28,28,.1), 0 3px 18px -4px rgba(28,28,28,.1), 0 5px 30px -12px rgba(28,28,28,.2)",
},
sizes: {
- container: 1440,
normal: "xsmall",
small: "xxsmall",
+ container: 1440,
},
space: {
- large: "2rem",
- larger: "4rem",
- medium: "1.6rem",
+ 0: 0,
none: "0",
+ xxsmall: "0.4rem",
+ xsmall: "0.8rem",
small: "1rem",
+ medium: "1.6rem",
+ large: "2rem",
xlarge: "2.4rem",
- xsmall: "0.8rem",
xxlarge: "3.2rem",
- xxsmall: "0.4rem",
+ larger: "4rem",
},
styles: {
hr: {
diff --git a/targets/hasura/migrations/1598542972178_order-view/down.sql b/targets/hasura/migrations/1598542972178_order-view/down.sql
new file mode 100644
index 000000000..913480aa5
--- /dev/null
+++ b/targets/hasura/migrations/1598542972178_order-view/down.sql
@@ -0,0 +1,6 @@
+
+DROP VIEW IF EXISTS "v1"."legi_data_alerts";
+
+DROP VIEW IF EXISTS "v1"."fiche_vdd_alerts";
+
+DROP VIEW IF EXISTS "v1"."kali_data_alerts";
diff --git a/targets/hasura/migrations/1598542972178_order-view/up.sql b/targets/hasura/migrations/1598542972178_order-view/up.sql
new file mode 100644
index 000000000..71c965aa9
--- /dev/null
+++ b/targets/hasura/migrations/1598542972178_order-view/up.sql
@@ -0,0 +1,36 @@
+
+CREATE OR REPLACE VIEW "v1"."kali_data_alerts" AS
+ SELECT alerts.id,
+ alerts.info,
+ alerts.status,
+ alerts.repository,
+ alerts.ref,
+ alerts.created_at,
+ alerts.updated_at
+ FROM alerts
+ WHERE (alerts.repository = 'socialgouv/kali-data'::text)
+ ORDER BY alerts.created_at, alerts.info ->> 'num';
+
+CREATE OR REPLACE VIEW "v1"."fiche_vdd_alerts" AS
+ SELECT alerts.id,
+ alerts.info,
+ alerts.status,
+ alerts.repository,
+ alerts.ref,
+ alerts.created_at,
+ alerts.updated_at
+ FROM alerts
+ WHERE (alerts.repository = 'socialgouv/fiches-vdd'::text)
+ ORDER BY alerts.created_at;
+
+CREATE OR REPLACE VIEW "v1"."legi_data_alerts" AS
+ SELECT alerts.id,
+ alerts.info,
+ alerts.status,
+ alerts.repository,
+ alerts.ref,
+ alerts.created_at,
+ alerts.updated_at
+ FROM alerts
+ WHERE (alerts.repository = 'socialgouv/legi-data'::text)
+ ORDER BY alerts.created_at;