@consilioweb/payload-support 4.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -35
- package/dist/components/RichTextEditor/index.js +1 -1
- package/dist/components/TicketConversation/RewriteDropdown.js +1 -1
- package/dist/components/TicketConversation/components/AISummaryPanel.js +3 -0
- package/dist/components/TicketConversation/components/ActionPanels.js +13 -8
- package/dist/components/TicketConversation/components/ClientHistory.js +1 -0
- package/dist/components/TicketConversation/components/CodeBlock.js +1 -0
- package/dist/components/TicketConversation/components/CodeBlockInserter.js +1 -1
- package/dist/components/TicketConversation/components/QuickActions.js +10 -8
- package/dist/components/TicketConversation/components/TicketHeader.js +2 -0
- package/dist/components/TicketConversation/components/TimeTrackingPanel.js +15 -9
- package/dist/components/TicketConversation/index.d.ts +10 -0
- package/dist/components/TicketConversation/index.js +25 -7
- package/dist/index.cjs +421 -73
- package/dist/index.d.cts +127 -38
- package/dist/index.d.ts +127 -38
- package/dist/index.js +415 -72
- package/dist/styles/BillingView.module.scss +11 -11
- package/dist/styles/ChatView.module.scss +7 -7
- package/dist/styles/CommandPalette.module.scss +1 -1
- package/dist/styles/CrmView.module.scss +9 -9
- package/dist/styles/EmailTracking.module.scss +6 -6
- package/dist/styles/ImportConversation.module.scss +5 -5
- package/dist/styles/Logs.module.scss +5 -5
- package/dist/styles/NewTicket.module.scss +2 -2
- package/dist/styles/PendingEmails.module.scss +13 -13
- package/dist/styles/SupportDashboard.module.scss +24 -8
- package/dist/styles/TicketDetail.module.scss +20 -20
- package/dist/styles/TicketInbox.module.scss +6 -6
- package/dist/styles/TicketingSettings.module.scss +10 -10
- package/dist/styles/TimeDashboard.module.scss +6 -6
- package/dist/styles/_tokens.scss +3 -1
- package/dist/utils/db.d.ts +34 -0
- package/dist/utils/readSettings.d.ts +90 -0
- package/dist/views/BillingView/client.js +15 -8
- package/dist/views/BillingView/index.js +4 -4
- package/dist/views/ChatView/client.js +2 -0
- package/dist/views/ChatView/index.js +4 -4
- package/dist/views/CrmView/client.js +2 -0
- package/dist/views/CrmView/index.js +4 -4
- package/dist/views/EmailTrackingView/client.js +23 -11
- package/dist/views/EmailTrackingView/index.js +4 -4
- package/dist/views/ImportConversationView/client.js +1 -0
- package/dist/views/ImportConversationView/index.js +4 -4
- package/dist/views/LogsView/client.js +1 -1
- package/dist/views/LogsView/index.js +4 -2
- package/dist/views/NewTicketView/client.js +20 -13
- package/dist/views/NewTicketView/index.js +4 -2
- package/dist/views/PendingEmailsView/client.js +9 -3
- package/dist/views/PendingEmailsView/index.js +4 -4
- package/dist/views/SupportDashboardView/client.js +17 -19
- package/dist/views/SupportDashboardView/index.js +4 -4
- package/dist/views/TicketDetailView/client.js +23 -11
- package/dist/views/TicketDetailView/index.js +4 -4
- package/dist/views/TicketInboxView/client.js +52 -26
- package/dist/views/TicketInboxView/index.js +4 -2
- package/dist/views/TicketingSettingsView/TicketingSettings.module.scss +7 -7
- package/dist/views/TicketingSettingsView/client.js +44 -26
- package/dist/views/TicketingSettingsView/index.js +4 -4
- package/dist/views/TimeDashboardView/client.js +10 -7
- package/dist/views/TimeDashboardView/index.js +4 -4
- package/dist/views/shared/ErrorBoundary.d.ts +36 -1
- package/dist/views/shared/ErrorBoundary.js +59 -28
- package/dist/views/shared/adminTokens.d.ts +15 -5
- package/dist/views/shared/adminTokens.js +23 -7
- package/dist/views/shared/icons.d.ts +49 -0
- package/dist/views/shared/icons.js +92 -0
- package/dist/views/shared/locales/en.json +15 -1
- package/dist/views/shared/locales/fr.json +15 -1
- package/dist/views/shared/viewAccess.d.ts +29 -0
- package/dist/views/shared/viewAccess.js +24 -0
- package/package.json +31 -21
- package/scripts/uninstall-data.mjs +178 -0
- package/scripts/uninstall.mjs +184 -0
- package/src/collections/Tickets.ts +7 -0
- package/src/collections/TimeEntries.ts +11 -3
- package/src/components/RichTextEditor/index.tsx +1 -1
- package/src/components/TicketConversation/RewriteDropdown.tsx +1 -1
- package/src/components/TicketConversation/components/AISummaryPanel.tsx +3 -0
- package/src/components/TicketConversation/components/ActionPanels.tsx +13 -8
- package/src/components/TicketConversation/components/ClientHistory.tsx +1 -0
- package/src/components/TicketConversation/components/CodeBlock.tsx +1 -0
- package/src/components/TicketConversation/components/CodeBlockInserter.tsx +1 -1
- package/src/components/TicketConversation/components/QuickActions.tsx +10 -8
- package/src/components/TicketConversation/components/TicketHeader.tsx +2 -0
- package/src/components/TicketConversation/components/TimeTrackingPanel.tsx +17 -9
- package/src/components/TicketConversation/index.tsx +41 -7
- package/src/endpoints/auth-2fa.ts +53 -8
- package/src/endpoints/capabilities.ts +2 -4
- package/src/endpoints/chatbot.ts +2 -2
- package/src/endpoints/delete-account.ts +191 -47
- package/src/endpoints/export-data.ts +104 -4
- package/src/endpoints/import-conversation.ts +2 -2
- package/src/endpoints/login.ts +13 -3
- package/src/endpoints/purge-logs.ts +6 -15
- package/src/endpoints/push.ts +14 -1
- package/src/endpoints/statuses.ts +17 -0
- package/src/index.ts +2 -0
- package/src/plugin.ts +51 -1
- package/src/portal/LiveChat.tsx +1 -1
- package/src/portal/auth/profile/page.tsx +3 -2
- package/src/portal/icons.tsx +91 -0
- package/src/portal/login/page.tsx +14 -4
- package/src/styles/BillingView.module.scss +11 -11
- package/src/styles/ChatView.module.scss +7 -7
- package/src/styles/CommandPalette.module.scss +1 -1
- package/src/styles/CrmView.module.scss +9 -9
- package/src/styles/EmailTracking.module.scss +6 -6
- package/src/styles/ImportConversation.module.scss +5 -5
- package/src/styles/Logs.module.scss +5 -5
- package/src/styles/NewTicket.module.scss +2 -2
- package/src/styles/PendingEmails.module.scss +13 -13
- package/src/styles/SupportDashboard.module.scss +24 -8
- package/src/styles/TicketDetail.module.scss +20 -20
- package/src/styles/TicketInbox.module.scss +6 -6
- package/src/styles/TicketingSettings.module.scss +10 -10
- package/src/styles/TimeDashboard.module.scss +6 -6
- package/src/styles/_tokens.scss +3 -1
- package/src/types.ts +20 -0
- package/src/utils/push.ts +22 -0
- package/src/utils/rateLimiter.ts +98 -0
- package/src/utils/retention.ts +111 -0
- package/src/utils/slugs.ts +15 -0
- package/src/utils/twoFactorChallenge.ts +6 -1
- package/src/utils/urlSafety.ts +36 -1
- package/src/views/BillingView/client.tsx +17 -8
- package/src/views/BillingView/index.tsx +4 -4
- package/src/views/ChatView/client.tsx +2 -0
- package/src/views/ChatView/index.tsx +4 -4
- package/src/views/CrmView/client.tsx +2 -0
- package/src/views/CrmView/index.tsx +4 -4
- package/src/views/EmailTrackingView/client.tsx +18 -7
- package/src/views/EmailTrackingView/index.tsx +4 -4
- package/src/views/ImportConversationView/client.tsx +1 -0
- package/src/views/ImportConversationView/index.tsx +4 -4
- package/src/views/LogsView/client.tsx +1 -1
- package/src/views/LogsView/index.tsx +4 -2
- package/src/views/NewTicketView/client.tsx +22 -13
- package/src/views/NewTicketView/index.tsx +4 -2
- package/src/views/PendingEmailsView/client.tsx +9 -3
- package/src/views/PendingEmailsView/index.tsx +4 -4
- package/src/views/SupportDashboardView/client.tsx +11 -5
- package/src/views/SupportDashboardView/index.tsx +4 -4
- package/src/views/TicketDetailView/client.tsx +25 -11
- package/src/views/TicketDetailView/index.tsx +4 -4
- package/src/views/TicketInboxView/client.tsx +47 -7
- package/src/views/TicketInboxView/index.tsx +4 -2
- package/src/views/TicketingSettingsView/TicketingSettings.module.scss +7 -7
- package/src/views/TicketingSettingsView/client.tsx +201 -144
- package/src/views/TicketingSettingsView/index.tsx +4 -4
- package/src/views/TimeDashboardView/client.tsx +10 -7
- package/src/views/TimeDashboardView/index.tsx +4 -4
- package/src/views/shared/ErrorBoundary.tsx +95 -31
- package/src/views/shared/adminTokens.ts +28 -11
- package/src/views/shared/icons.tsx +146 -0
- package/src/views/shared/locales/en.json +15 -1
- package/src/views/shared/locales/fr.json +15 -1
- package/src/views/shared/viewAccess.ts +73 -0
- package/src/types/lucide-react.d.ts +0 -42
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { DefaultTemplate } from '@payloadcms/next/templates';
|
|
3
3
|
import { redirect } from 'next/navigation';
|
|
4
|
+
import { supportViewRedirectTarget } from '../shared/viewAccess.js';
|
|
4
5
|
import { AdminErrorBoundary } from '../shared/ErrorBoundary.js';
|
|
5
6
|
import { TicketingSettingsClient } from './client.js';
|
|
6
7
|
|
|
7
8
|
const TicketingSettingsView = ({ initPageResult }) => {
|
|
8
9
|
const { req, visibleEntities } = initPageResult;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
10
|
+
const redirectTo = supportViewRedirectTarget(initPageResult);
|
|
11
|
+
if (redirectTo) redirect(redirectTo);
|
|
12
12
|
return /* @__PURE__ */ jsx(
|
|
13
13
|
DefaultTemplate,
|
|
14
14
|
{
|
|
@@ -18,7 +18,7 @@ const TicketingSettingsView = ({ initPageResult }) => {
|
|
|
18
18
|
payload: req.payload,
|
|
19
19
|
permissions: initPageResult.permissions,
|
|
20
20
|
searchParams: {},
|
|
21
|
-
user: req.user,
|
|
21
|
+
user: req.user ?? void 0,
|
|
22
22
|
visibleEntities,
|
|
23
23
|
children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "TicketingSettingsView", children: /* @__PURE__ */ jsx(TicketingSettingsClient, {}) })
|
|
24
24
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import React, { useState, useCallback, useEffect } from 'react';
|
|
3
|
+
import React, { useId, useState, useCallback, useEffect } from 'react';
|
|
4
4
|
import { SkeletonDashboard } from '../shared/Skeleton.js';
|
|
5
5
|
import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
|
|
6
6
|
import styles from '../../styles/TimeDashboard.module.scss';
|
|
@@ -25,6 +25,9 @@ function getMonthRange(offset) {
|
|
|
25
25
|
const MONTHS_FR = ["Jan", "Fev", "Mar", "Avr", "Mai", "Jun", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"];
|
|
26
26
|
const TimeDashboardClient = () => {
|
|
27
27
|
const { t } = useTranslation();
|
|
28
|
+
const fromId = useId();
|
|
29
|
+
const toId = useId();
|
|
30
|
+
const groupById = useId();
|
|
28
31
|
const [entries, setEntries] = useState([]);
|
|
29
32
|
const [loading, setLoading] = useState(true);
|
|
30
33
|
const [from, setFrom] = useState(() => getMonthRange(0).from);
|
|
@@ -108,16 +111,16 @@ const TimeDashboardClient = () => {
|
|
|
108
111
|
] }),
|
|
109
112
|
/* @__PURE__ */ jsxs("div", { className: styles.filterRow, children: [
|
|
110
113
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
111
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("timeDashboard.filters.from") }),
|
|
112
|
-
/* @__PURE__ */ jsx("input", { type: "date", value: from, onChange: (e) => setFrom(e.target.value), className: styles.input })
|
|
114
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: fromId, children: t("timeDashboard.filters.from") }),
|
|
115
|
+
/* @__PURE__ */ jsx("input", { id: fromId, type: "date", value: from, onChange: (e) => setFrom(e.target.value), className: styles.input })
|
|
113
116
|
] }),
|
|
114
117
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
115
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("timeDashboard.filters.to") }),
|
|
116
|
-
/* @__PURE__ */ jsx("input", { type: "date", value: to, onChange: (e) => setTo(e.target.value), className: styles.input })
|
|
118
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: toId, children: t("timeDashboard.filters.to") }),
|
|
119
|
+
/* @__PURE__ */ jsx("input", { id: toId, type: "date", value: to, onChange: (e) => setTo(e.target.value), className: styles.input })
|
|
117
120
|
] }),
|
|
118
121
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
119
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("timeDashboard.filters.groupBy") }),
|
|
120
|
-
/* @__PURE__ */ jsxs("select", { value: groupBy, onChange: (e) => setGroupBy(e.target.value), className: styles.select, children: [
|
|
122
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: groupById, children: t("timeDashboard.filters.groupBy") }),
|
|
123
|
+
/* @__PURE__ */ jsxs("select", { id: groupById, value: groupBy, onChange: (e) => setGroupBy(e.target.value), className: styles.select, children: [
|
|
121
124
|
/* @__PURE__ */ jsx("option", { value: "day", children: t("timeDashboard.filters.day") }),
|
|
122
125
|
/* @__PURE__ */ jsx("option", { value: "week", children: t("timeDashboard.filters.week") }),
|
|
123
126
|
/* @__PURE__ */ jsx("option", { value: "project", children: t("timeDashboard.filters.project") })
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { DefaultTemplate } from '@payloadcms/next/templates';
|
|
3
3
|
import { redirect } from 'next/navigation';
|
|
4
|
+
import { supportViewRedirectTarget } from '../shared/viewAccess.js';
|
|
4
5
|
import { AdminErrorBoundary } from '../shared/ErrorBoundary.js';
|
|
5
6
|
import { TimeDashboardClient } from './client.js';
|
|
6
7
|
|
|
7
8
|
const TimeDashboardView = ({ initPageResult }) => {
|
|
8
9
|
const { req, visibleEntities } = initPageResult;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
10
|
+
const redirectTo = supportViewRedirectTarget(initPageResult);
|
|
11
|
+
if (redirectTo) redirect(redirectTo);
|
|
12
12
|
return /* @__PURE__ */ jsx(
|
|
13
13
|
DefaultTemplate,
|
|
14
14
|
{
|
|
@@ -18,7 +18,7 @@ const TimeDashboardView = ({ initPageResult }) => {
|
|
|
18
18
|
payload: req.payload,
|
|
19
19
|
permissions: initPageResult.permissions,
|
|
20
20
|
searchParams: {},
|
|
21
|
-
user: req.user,
|
|
21
|
+
user: req.user ?? void 0,
|
|
22
22
|
visibleEntities,
|
|
23
23
|
children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "TimeDashboardView", children: /* @__PURE__ */ jsx(TimeDashboardClient, {}) })
|
|
24
24
|
}
|
|
@@ -3,15 +3,50 @@ interface ErrorBoundaryProps {
|
|
|
3
3
|
children: React.ReactNode;
|
|
4
4
|
fallback?: React.ReactNode;
|
|
5
5
|
viewName?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Values that identify the input the subtree renders from (a ticket id, a
|
|
8
|
+
* filter, a page number...). When any of them changes the boundary clears
|
|
9
|
+
* the error on its own, because the new input may well render fine.
|
|
10
|
+
*/
|
|
11
|
+
resetKeys?: unknown[];
|
|
6
12
|
}
|
|
7
13
|
interface ErrorBoundaryState {
|
|
8
14
|
hasError: boolean;
|
|
9
15
|
error: Error | null;
|
|
16
|
+
/**
|
|
17
|
+
* Bumped on every reset. It is used as the `key` of the wrapper around the
|
|
18
|
+
* children so that a retry REMOUNTS the subtree. Clearing `hasError` alone
|
|
19
|
+
* keeps the broken component instance and its state, so anything that threw
|
|
20
|
+
* from a bad piece of state throws again on the very next render.
|
|
21
|
+
*/
|
|
22
|
+
resetCount: number;
|
|
10
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Shallow comparison of two reset-key arrays. A missing array is treated as
|
|
26
|
+
* empty, so a boundary declared without `resetKeys` never auto-resets.
|
|
27
|
+
*/
|
|
28
|
+
export declare function haveResetKeysChanged(previous?: unknown[], next?: unknown[]): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Default fallback UI.
|
|
31
|
+
*
|
|
32
|
+
* Exported so it can be rendered (and asserted on) in isolation. It is the
|
|
33
|
+
* only screen a user sees when a view is broken, so it must stay readable in
|
|
34
|
+
* both themes: every colour comes from a Payload theme token, never a hex
|
|
35
|
+
* literal that only works on a light background.
|
|
36
|
+
*
|
|
37
|
+
* The thrown message is deliberately NOT displayed — it can carry a stack
|
|
38
|
+
* fragment, an internal path or a raw API payload. It is logged to the console
|
|
39
|
+
* by `componentDidCatch` instead.
|
|
40
|
+
*/
|
|
41
|
+
export declare function AdminErrorFallback({ onRetry }: {
|
|
42
|
+
onRetry: () => void;
|
|
43
|
+
}): React.ReactElement;
|
|
11
44
|
export declare class AdminErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
12
45
|
constructor(props: ErrorBoundaryProps);
|
|
13
|
-
static getDerivedStateFromError(error: Error): ErrorBoundaryState
|
|
46
|
+
static getDerivedStateFromError(error: Error): Pick<ErrorBoundaryState, 'hasError' | 'error'>;
|
|
14
47
|
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
|
|
48
|
+
componentDidUpdate(prevProps: ErrorBoundaryProps): void;
|
|
49
|
+
reset: () => void;
|
|
15
50
|
render(): React.ReactNode;
|
|
16
51
|
}
|
|
17
52
|
export {};
|
|
@@ -1,11 +1,53 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
3
|
import React from 'react';
|
|
4
|
+
import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
|
|
4
5
|
|
|
6
|
+
function haveResetKeysChanged(previous, next) {
|
|
7
|
+
const a = previous ?? [];
|
|
8
|
+
const b = next ?? [];
|
|
9
|
+
if (a.length !== b.length) return true;
|
|
10
|
+
return a.some((value, index) => !Object.is(value, b[index]));
|
|
11
|
+
}
|
|
12
|
+
function AdminErrorFallback({ onRetry }) {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
return /* @__PURE__ */ jsxs(
|
|
15
|
+
"div",
|
|
16
|
+
{
|
|
17
|
+
role: "alert",
|
|
18
|
+
style: {
|
|
19
|
+
padding: "40px",
|
|
20
|
+
textAlign: "center",
|
|
21
|
+
color: "var(--theme-error-550)"
|
|
22
|
+
},
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsx("h2", { style: { marginBottom: "16px", fontSize: "18px" }, children: t("errorBoundary.title") }),
|
|
25
|
+
/* @__PURE__ */ jsx("p", { style: { marginBottom: "24px", color: "var(--theme-elevation-650)", fontSize: "14px" }, children: t("errorBoundary.description") }),
|
|
26
|
+
/* @__PURE__ */ jsx(
|
|
27
|
+
"button",
|
|
28
|
+
{
|
|
29
|
+
type: "button",
|
|
30
|
+
onClick: onRetry,
|
|
31
|
+
style: {
|
|
32
|
+
padding: "8px 20px",
|
|
33
|
+
backgroundColor: "var(--theme-success-550)",
|
|
34
|
+
color: "var(--theme-elevation-0)",
|
|
35
|
+
border: "none",
|
|
36
|
+
borderRadius: "6px",
|
|
37
|
+
cursor: "pointer",
|
|
38
|
+
fontSize: "14px"
|
|
39
|
+
},
|
|
40
|
+
children: t("errorBoundary.retry")
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
5
47
|
class AdminErrorBoundary extends React.Component {
|
|
6
48
|
constructor(props) {
|
|
7
49
|
super(props);
|
|
8
|
-
this.state = { hasError: false, error: null };
|
|
50
|
+
this.state = { hasError: false, error: null, resetCount: 0 };
|
|
9
51
|
}
|
|
10
52
|
static getDerivedStateFromError(error) {
|
|
11
53
|
return { hasError: true, error };
|
|
@@ -13,38 +55,27 @@ class AdminErrorBoundary extends React.Component {
|
|
|
13
55
|
componentDidCatch(error, errorInfo) {
|
|
14
56
|
console.error(`[${this.props.viewName || "AdminView"}] Error:`, error, errorInfo);
|
|
15
57
|
}
|
|
58
|
+
componentDidUpdate(prevProps) {
|
|
59
|
+
if (!this.state.hasError) return;
|
|
60
|
+
if (!haveResetKeysChanged(prevProps.resetKeys, this.props.resetKeys)) return;
|
|
61
|
+
this.reset();
|
|
62
|
+
}
|
|
63
|
+
reset = () => {
|
|
64
|
+
this.setState((prev) => ({
|
|
65
|
+
hasError: false,
|
|
66
|
+
error: null,
|
|
67
|
+
resetCount: prev.resetCount + 1
|
|
68
|
+
}));
|
|
69
|
+
};
|
|
16
70
|
render() {
|
|
17
71
|
if (this.state.hasError) {
|
|
18
72
|
if (this.props.fallback) {
|
|
19
73
|
return this.props.fallback;
|
|
20
74
|
}
|
|
21
|
-
return /* @__PURE__ */
|
|
22
|
-
padding: "40px",
|
|
23
|
-
textAlign: "center",
|
|
24
|
-
color: "#dc2626"
|
|
25
|
-
}, children: [
|
|
26
|
-
/* @__PURE__ */ jsx("h2", { style: { marginBottom: "16px", fontSize: "18px" }, children: "Une erreur est survenue" }),
|
|
27
|
-
/* @__PURE__ */ jsx("p", { style: { marginBottom: "24px", color: "#6b7280", fontSize: "14px" }, children: this.state.error?.message || "Erreur inattendue" }),
|
|
28
|
-
/* @__PURE__ */ jsx(
|
|
29
|
-
"button",
|
|
30
|
-
{
|
|
31
|
-
onClick: () => this.setState({ hasError: false, error: null }),
|
|
32
|
-
style: {
|
|
33
|
-
padding: "8px 20px",
|
|
34
|
-
backgroundColor: "#2563eb",
|
|
35
|
-
color: "#fff",
|
|
36
|
-
border: "none",
|
|
37
|
-
borderRadius: "6px",
|
|
38
|
-
cursor: "pointer",
|
|
39
|
-
fontSize: "14px"
|
|
40
|
-
},
|
|
41
|
-
children: "Reessayer"
|
|
42
|
-
}
|
|
43
|
-
)
|
|
44
|
-
] });
|
|
75
|
+
return /* @__PURE__ */ jsx(AdminErrorFallback, { onRetry: this.reset });
|
|
45
76
|
}
|
|
46
|
-
return this.props.children;
|
|
77
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: this.props.children }, this.state.resetCount);
|
|
47
78
|
}
|
|
48
79
|
}
|
|
49
80
|
|
|
50
|
-
export { AdminErrorBoundary };
|
|
81
|
+
export { AdminErrorBoundary, AdminErrorFallback, haveResetKeysChanged };
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
export declare const V: {
|
|
3
3
|
readonly text: "var(--theme-text)";
|
|
4
|
-
readonly textSecondary: "var(--theme-elevation-
|
|
4
|
+
readonly textSecondary: "var(--theme-elevation-650)";
|
|
5
5
|
readonly bg: "var(--theme-elevation-50)";
|
|
6
6
|
readonly bgCard: "var(--theme-elevation-100)";
|
|
7
7
|
readonly border: "var(--theme-elevation-300)";
|
|
8
8
|
readonly blue: "#2563eb";
|
|
9
|
-
readonly amber: "#
|
|
10
|
-
readonly orange: "#
|
|
11
|
-
readonly green: "#
|
|
9
|
+
readonly amber: "#b45309";
|
|
10
|
+
readonly orange: "#c2410c";
|
|
11
|
+
readonly green: "#15803d";
|
|
12
12
|
readonly red: "#dc2626";
|
|
13
|
+
readonly neutralBg: "var(--theme-elevation-150)";
|
|
14
|
+
readonly neutralFg: "var(--theme-text)";
|
|
13
15
|
readonly cyan: "#2563eb";
|
|
14
|
-
readonly yellow: "#
|
|
16
|
+
readonly yellow: "#b45309";
|
|
15
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Button style factory.
|
|
20
|
+
*
|
|
21
|
+
* `bg` is expected to be one of the fixed hex values of `V`; the default
|
|
22
|
+
* foreground is white, which reaches AA on all of them. Pass `fg` whenever
|
|
23
|
+
* `bg` is a theme variable, since white only works on one of the two themes.
|
|
24
|
+
*/
|
|
16
25
|
export declare const btnStyle: (bg: string, opts?: {
|
|
17
26
|
disabled?: boolean;
|
|
18
27
|
small?: boolean;
|
|
28
|
+
fg?: string;
|
|
19
29
|
}) => React.CSSProperties;
|
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
const V = {
|
|
2
2
|
text: "var(--theme-text)",
|
|
3
|
-
|
|
3
|
+
// elevation-650, not elevation-500: Payload's dark theme does not redefine
|
|
4
|
+
// the 500 step (colors.scss jumps from 450 to 550), so elevation-500 stays
|
|
5
|
+
// rgb(128,128,128) in both themes — 3.62:1 on a light background and 4.03:1
|
|
6
|
+
// on a dark one, below WCAG AA in both. elevation-650 gives 6.63:1 / 9.03:1.
|
|
7
|
+
textSecondary: "var(--theme-elevation-650)",
|
|
4
8
|
bg: "var(--theme-elevation-50)",
|
|
5
9
|
bgCard: "var(--theme-elevation-100)",
|
|
6
10
|
border: "var(--theme-elevation-300)",
|
|
7
|
-
// Professional palette
|
|
11
|
+
// Professional palette. These are fixed hex values (they do not follow the
|
|
12
|
+
// admin theme), so they are only ever used as a background behind white
|
|
13
|
+
// text; each one is dark enough for white to reach at least 4.5:1.
|
|
8
14
|
blue: "#2563eb",
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
// white on it: 5.17:1
|
|
16
|
+
amber: "#b45309",
|
|
17
|
+
// white on it: 5.02:1
|
|
18
|
+
orange: "#c2410c",
|
|
19
|
+
// white on it: 5.18:1
|
|
20
|
+
green: "#15803d",
|
|
21
|
+
// white on it: 5.02:1
|
|
12
22
|
red: "#dc2626",
|
|
23
|
+
// white on it: 4.83:1
|
|
24
|
+
// Neutral / secondary button. Both halves follow the admin theme, so they
|
|
25
|
+
// must be used together — white on a theme token is unreadable in one of
|
|
26
|
+
// the two themes whichever token is picked.
|
|
27
|
+
neutralBg: "var(--theme-elevation-150)",
|
|
28
|
+
neutralFg: "var(--theme-text)",
|
|
13
29
|
// Legacy aliases (backward compat for views not yet updated)
|
|
14
30
|
cyan: "#2563eb",
|
|
15
|
-
yellow: "#
|
|
31
|
+
yellow: "#b45309"
|
|
16
32
|
};
|
|
17
33
|
const btnStyle = (bg, opts) => ({
|
|
18
34
|
padding: opts?.small ? "6px 12px" : "8px 14px",
|
|
19
35
|
borderRadius: 6,
|
|
20
36
|
border: `1px solid var(--theme-elevation-300)`,
|
|
21
37
|
backgroundColor: bg,
|
|
22
|
-
color: "#fff",
|
|
38
|
+
color: opts?.fg ?? "#fff",
|
|
23
39
|
fontWeight: 600,
|
|
24
40
|
fontSize: opts?.small ? 12 : 13,
|
|
25
41
|
cursor: opts?.disabled ? "not-allowed" : "pointer",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inlined Lucide icons.
|
|
3
|
+
*
|
|
4
|
+
* The plugin used to require `lucide-react` as a peer dependency for exactly
|
|
5
|
+
* 15 icons across two admin views. That made every integrator install an icon set,
|
|
6
|
+
* and a missing install a build-time failure, for 15 paths totalling a few
|
|
7
|
+
* hundred bytes. They are inlined here instead, and `lucide-react` is no longer
|
|
8
|
+
* a peer dependency.
|
|
9
|
+
*
|
|
10
|
+
* The geometry below is copied from lucide-react v1.41.0 and, like the rest of
|
|
11
|
+
* Lucide, is under the ISC licence:
|
|
12
|
+
*
|
|
13
|
+
* ISC License
|
|
14
|
+
* Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as
|
|
15
|
+
* part of Feather (MIT). All other copyright (c) for Lucide are held by
|
|
16
|
+
* Lucide Contributors 2022.
|
|
17
|
+
*
|
|
18
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
19
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
20
|
+
* copyright notice and this permission notice appear in all copies.
|
|
21
|
+
*
|
|
22
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
23
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
24
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
25
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
26
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
27
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
28
|
+
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
29
|
+
*/
|
|
30
|
+
import React from 'react';
|
|
31
|
+
export interface IconProps extends Omit<React.SVGProps<SVGSVGElement>, 'width' | 'height'> {
|
|
32
|
+
/** Rendered width and height. Lucide's own default is 24. */
|
|
33
|
+
size?: number | string;
|
|
34
|
+
}
|
|
35
|
+
export declare const Bot: React.FC<IconProps>;
|
|
36
|
+
export declare const ChevronDown: React.FC<IconProps>;
|
|
37
|
+
export declare const ChevronUp: React.FC<IconProps>;
|
|
38
|
+
export declare const Clock: React.FC<IconProps>;
|
|
39
|
+
export declare const FileSignature: React.FC<IconProps>;
|
|
40
|
+
export declare const Globe: React.FC<IconProps>;
|
|
41
|
+
export declare const Inbox: React.FC<IconProps>;
|
|
42
|
+
export declare const Link2: React.FC<IconProps>;
|
|
43
|
+
export declare const Mail: React.FC<IconProps>;
|
|
44
|
+
export declare const Paperclip: React.FC<IconProps>;
|
|
45
|
+
export declare const Plus: React.FC<IconProps>;
|
|
46
|
+
export declare const Search: React.FC<IconProps>;
|
|
47
|
+
export declare const Settings: React.FC<IconProps>;
|
|
48
|
+
export declare const Timer: React.FC<IconProps>;
|
|
49
|
+
export declare const X: React.FC<IconProps>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
function createIcon(displayName, nodes) {
|
|
5
|
+
const Icon = ({ size = 24, strokeWidth = 2, ...rest }) => /* @__PURE__ */ jsx(
|
|
6
|
+
"svg",
|
|
7
|
+
{
|
|
8
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
9
|
+
width: size,
|
|
10
|
+
height: size,
|
|
11
|
+
viewBox: "0 0 24 24",
|
|
12
|
+
fill: "none",
|
|
13
|
+
stroke: "currentColor",
|
|
14
|
+
strokeWidth,
|
|
15
|
+
strokeLinecap: "round",
|
|
16
|
+
strokeLinejoin: "round",
|
|
17
|
+
"aria-hidden": "true",
|
|
18
|
+
...rest,
|
|
19
|
+
children: nodes.map(([tag, attrs], index) => React.createElement(tag, { key: index, ...attrs }))
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
Icon.displayName = displayName;
|
|
23
|
+
return Icon;
|
|
24
|
+
}
|
|
25
|
+
const Bot = createIcon("Bot", [
|
|
26
|
+
["path", { d: "M12 8V4H8" }],
|
|
27
|
+
["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2" }],
|
|
28
|
+
["path", { d: "M2 14h2" }],
|
|
29
|
+
["path", { d: "M20 14h2" }],
|
|
30
|
+
["path", { d: "M15 13v2" }],
|
|
31
|
+
["path", { d: "M9 13v2" }]
|
|
32
|
+
]);
|
|
33
|
+
const ChevronDown = createIcon("ChevronDown", [
|
|
34
|
+
["path", { d: "m6 9 6 6 6-6" }]
|
|
35
|
+
]);
|
|
36
|
+
const ChevronUp = createIcon("ChevronUp", [
|
|
37
|
+
["path", { d: "m18 15-6-6-6 6" }]
|
|
38
|
+
]);
|
|
39
|
+
const Clock = createIcon("Clock", [
|
|
40
|
+
["circle", { cx: "12", cy: "12", r: "10" }],
|
|
41
|
+
["path", { d: "M12 6v6l4 2" }]
|
|
42
|
+
]);
|
|
43
|
+
const FileSignature = createIcon("FileSignature", [
|
|
44
|
+
["path", { d: "M14.364 13.634a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506l4.013-4.009a1 1 0 0 0-3.004-3.004z" }],
|
|
45
|
+
["path", { d: "M14.487 7.858A1 1 0 0 1 14 7V2" }],
|
|
46
|
+
["path", { d: "M20 19.645V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l2.516 2.516" }],
|
|
47
|
+
["path", { d: "M8 18h1" }]
|
|
48
|
+
]);
|
|
49
|
+
const Globe = createIcon("Globe", [
|
|
50
|
+
["circle", { cx: "12", cy: "12", r: "10" }],
|
|
51
|
+
["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }],
|
|
52
|
+
["path", { d: "M2 12h20" }]
|
|
53
|
+
]);
|
|
54
|
+
const Inbox = createIcon("Inbox", [
|
|
55
|
+
["polyline", { points: "22 12 16 12 14 15 10 15 8 12 2 12" }],
|
|
56
|
+
["path", { d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" }]
|
|
57
|
+
]);
|
|
58
|
+
const Link2 = createIcon("Link2", [
|
|
59
|
+
["path", { d: "M9 17H7A5 5 0 0 1 7 7h2" }],
|
|
60
|
+
["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2" }],
|
|
61
|
+
["line", { x1: "8", x2: "16", y1: "12", y2: "12" }]
|
|
62
|
+
]);
|
|
63
|
+
const Mail = createIcon("Mail", [
|
|
64
|
+
["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7" }],
|
|
65
|
+
["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }]
|
|
66
|
+
]);
|
|
67
|
+
const Paperclip = createIcon("Paperclip", [
|
|
68
|
+
["path", { d: "m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551" }]
|
|
69
|
+
]);
|
|
70
|
+
const Plus = createIcon("Plus", [
|
|
71
|
+
["path", { d: "M5 12h14" }],
|
|
72
|
+
["path", { d: "M12 5v14" }]
|
|
73
|
+
]);
|
|
74
|
+
const Search = createIcon("Search", [
|
|
75
|
+
["path", { d: "m21 21-4.34-4.34" }],
|
|
76
|
+
["circle", { cx: "11", cy: "11", r: "8" }]
|
|
77
|
+
]);
|
|
78
|
+
const Settings = createIcon("Settings", [
|
|
79
|
+
["path", { d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" }],
|
|
80
|
+
["circle", { cx: "12", cy: "12", r: "3" }]
|
|
81
|
+
]);
|
|
82
|
+
const Timer = createIcon("Timer", [
|
|
83
|
+
["line", { x1: "10", x2: "14", y1: "2", y2: "2" }],
|
|
84
|
+
["line", { x1: "12", x2: "15", y1: "14", y2: "11" }],
|
|
85
|
+
["circle", { cx: "12", cy: "14", r: "8" }]
|
|
86
|
+
]);
|
|
87
|
+
const X = createIcon("X", [
|
|
88
|
+
["path", { d: "M18 6 6 18" }],
|
|
89
|
+
["path", { d: "m6 6 12 12" }]
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
export { Bot, ChevronDown, ChevronUp, Clock, FileSignature, Globe, Inbox, Link2, Mail, Paperclip, Plus, Search, Settings, Timer, X };
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
+
"errorBoundary": {
|
|
3
|
+
"title": "Something went wrong",
|
|
4
|
+
"description": "This section could not be displayed. The technical details were logged to the browser console.",
|
|
5
|
+
"retry": "Retry"
|
|
6
|
+
},
|
|
2
7
|
"common": {
|
|
3
8
|
"loading": "Loading...",
|
|
4
9
|
"cancel": "Cancel",
|
|
@@ -144,6 +149,7 @@
|
|
|
144
149
|
"title": "CRM Clients",
|
|
145
150
|
"subtitle": "Client management and history",
|
|
146
151
|
"searchPlaceholder": "Search a client...",
|
|
152
|
+
"searchLabel": "Search a client",
|
|
147
153
|
"noClientFound": "No client found",
|
|
148
154
|
"selectClient": "Select a client to see their details",
|
|
149
155
|
"editButton": "Edit",
|
|
@@ -316,6 +322,8 @@
|
|
|
316
322
|
"resolved": "Resolved",
|
|
317
323
|
"slaBreach": "SLA breached"
|
|
318
324
|
},
|
|
325
|
+
"searchLabel": "Search a ticket",
|
|
326
|
+
"sortLabel": "Sort the tickets",
|
|
319
327
|
"sort": {
|
|
320
328
|
"newest": "Most recent",
|
|
321
329
|
"oldest": "Oldest first",
|
|
@@ -324,6 +332,7 @@
|
|
|
324
332
|
},
|
|
325
333
|
"selected": "{{count}} selected",
|
|
326
334
|
"selectedPlural": "{{count}} selected",
|
|
335
|
+
"tabsLabel": "Inbox filters",
|
|
327
336
|
"closeAction": "Close",
|
|
328
337
|
"reopenAction": "Reopen",
|
|
329
338
|
"moreActions": "More actions...",
|
|
@@ -344,6 +353,7 @@
|
|
|
344
353
|
"emailTracking": {
|
|
345
354
|
"title": "Email tracking",
|
|
346
355
|
"searchPlaceholder": "Search by recipient or subject...",
|
|
356
|
+
"searchLabel": "Search an email",
|
|
347
357
|
"noLogs": "No logs found for this period",
|
|
348
358
|
"tabs": {
|
|
349
359
|
"all": "All",
|
|
@@ -366,7 +376,8 @@
|
|
|
366
376
|
"action": "Action",
|
|
367
377
|
"time": "Time"
|
|
368
378
|
},
|
|
369
|
-
"errorLabel": "Error"
|
|
379
|
+
"errorLabel": "Error",
|
|
380
|
+
"toggleError": "Show the error detail"
|
|
370
381
|
},
|
|
371
382
|
"logs": {
|
|
372
383
|
"title": "Email Logs",
|
|
@@ -530,8 +541,11 @@
|
|
|
530
541
|
"messageDeletedToast": "Message deleted",
|
|
531
542
|
"split": {
|
|
532
543
|
"subjectPlaceholder": "New ticket subject...",
|
|
544
|
+
"subjectLabel": "Subject of the new ticket",
|
|
533
545
|
"createBtn": "Create ticket"
|
|
534
546
|
},
|
|
547
|
+
"sendAs": "Send as",
|
|
548
|
+
"manualMinutes": "Minutes to add",
|
|
535
549
|
"editMessage": "Edit",
|
|
536
550
|
"editMessageLabel": "Edit message",
|
|
537
551
|
"uploadItem": "Attachment {{name}}",
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
+
"errorBoundary": {
|
|
3
|
+
"title": "Une erreur est survenue",
|
|
4
|
+
"description": "Cette section n'a pas pu s'afficher. Le detail technique est consigne dans la console du navigateur.",
|
|
5
|
+
"retry": "Reessayer"
|
|
6
|
+
},
|
|
2
7
|
"common": {
|
|
3
8
|
"loading": "Chargement...",
|
|
4
9
|
"cancel": "Annuler",
|
|
@@ -144,6 +149,7 @@
|
|
|
144
149
|
"title": "CRM Clients",
|
|
145
150
|
"subtitle": "Gestion des clients et historique",
|
|
146
151
|
"searchPlaceholder": "Rechercher un client...",
|
|
152
|
+
"searchLabel": "Rechercher un client",
|
|
147
153
|
"noClientFound": "Aucun client trouvé",
|
|
148
154
|
"selectClient": "Sélectionnez un client pour voir ses détails",
|
|
149
155
|
"editButton": "Modifier",
|
|
@@ -316,6 +322,8 @@
|
|
|
316
322
|
"resolved": "Résolus",
|
|
317
323
|
"slaBreach": "SLA dépassé"
|
|
318
324
|
},
|
|
325
|
+
"searchLabel": "Rechercher un ticket",
|
|
326
|
+
"sortLabel": "Trier les tickets",
|
|
319
327
|
"sort": {
|
|
320
328
|
"newest": "Plus récent",
|
|
321
329
|
"oldest": "Plus ancien",
|
|
@@ -324,6 +332,7 @@
|
|
|
324
332
|
},
|
|
325
333
|
"selected": "{{count}} sélectionné",
|
|
326
334
|
"selectedPlural": "{{count}} sélectionnés",
|
|
335
|
+
"tabsLabel": "Filtres de la boite de reception",
|
|
327
336
|
"closeAction": "Fermer",
|
|
328
337
|
"reopenAction": "Rouvrir",
|
|
329
338
|
"moreActions": "Plus d'actions...",
|
|
@@ -344,6 +353,7 @@
|
|
|
344
353
|
"emailTracking": {
|
|
345
354
|
"title": "Suivi des emails",
|
|
346
355
|
"searchPlaceholder": "Rechercher par destinataire ou sujet...",
|
|
356
|
+
"searchLabel": "Rechercher un email",
|
|
347
357
|
"noLogs": "Aucun log trouvé pour cette période",
|
|
348
358
|
"tabs": {
|
|
349
359
|
"all": "Tous",
|
|
@@ -366,7 +376,8 @@
|
|
|
366
376
|
"action": "Action",
|
|
367
377
|
"time": "Temps"
|
|
368
378
|
},
|
|
369
|
-
"errorLabel": "Erreur"
|
|
379
|
+
"errorLabel": "Erreur",
|
|
380
|
+
"toggleError": "Afficher le detail de l'erreur"
|
|
370
381
|
},
|
|
371
382
|
"logs": {
|
|
372
383
|
"title": "Logs Email",
|
|
@@ -530,8 +541,11 @@
|
|
|
530
541
|
"messageDeletedToast": "Message supprimé",
|
|
531
542
|
"split": {
|
|
532
543
|
"subjectPlaceholder": "Sujet du nouveau ticket...",
|
|
544
|
+
"subjectLabel": "Sujet du nouveau ticket",
|
|
533
545
|
"createBtn": "Créer le ticket"
|
|
534
546
|
},
|
|
547
|
+
"sendAs": "Envoyer en tant que",
|
|
548
|
+
"manualMinutes": "Minutes a ajouter",
|
|
535
549
|
"editMessage": "Éditer",
|
|
536
550
|
"editMessageLabel": "Éditer le message",
|
|
537
551
|
"uploadItem": "PJ {{name}}",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AdminViewServerProps } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Where a custom admin view must send a caller it refuses, or `null` to render.
|
|
4
|
+
*
|
|
5
|
+
* Payload does NOT gate custom admin views. `RootPage` skips its own
|
|
6
|
+
* `canAccessAdmin` redirect as soon as `isCustomAdminView()` matches, and that
|
|
7
|
+
* helper only compares the request path against the registered `view.path` —
|
|
8
|
+
* it reads no visibility flag, despite what its docblock claims. Authorising a
|
|
9
|
+
* custom view is therefore the view's own job, and every view registered by
|
|
10
|
+
* this plugin sits at a custom path (`/support/inbox`, `/support/ticket`, …).
|
|
11
|
+
*
|
|
12
|
+
* `!req.user` alone is not that check. A single `payload-token` cookie serves
|
|
13
|
+
* every auth collection of the host app, so an ordinary front-office account —
|
|
14
|
+
* a `customers`, `members` or `subscribers` signup — carries one on `/admin`
|
|
15
|
+
* routes too. Such a caller reached `DefaultTemplate` and received the admin
|
|
16
|
+
* chrome together with the client config Payload builds for any authenticated
|
|
17
|
+
* request: the field schema of every collection and global, `admin.hidden`
|
|
18
|
+
* ones included, plus an unfiltered `visibleEntities`.
|
|
19
|
+
*
|
|
20
|
+
* The ticket data itself never travelled — the client components fetch through
|
|
21
|
+
* `/api/support/*`, which `requireAdmin` has guarded all along — but the shape
|
|
22
|
+
* of the whole CMS did.
|
|
23
|
+
*
|
|
24
|
+
* The gate mirrors `requireAdmin` (utils/auth.ts): membership of the staff
|
|
25
|
+
* collection. It additionally honours `canAccessAdmin`, so an account the host
|
|
26
|
+
* disabled through its own `access.admin` is refused here too, and it fails
|
|
27
|
+
* closed on anything it cannot resolve.
|
|
28
|
+
*/
|
|
29
|
+
export declare function supportViewRedirectTarget(initPageResult: AdminViewServerProps['initPageResult']): string | null;
|