mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-03 19:36:20 +00:00 
			
		
		
		
	Merge branch 'main' into feature/index-morph-tables
This commit is contained in:
		
						commit
						23b798fb34
					
				@ -2,24 +2,36 @@
 | 
			
		||||
 | 
			
		||||
class LocalStorageMock {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.store = {};
 | 
			
		||||
    this.store = new Map();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  clear() {
 | 
			
		||||
    this.store = {};
 | 
			
		||||
    this.store.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getItem(key) {
 | 
			
		||||
    return this.store[key] || null;
 | 
			
		||||
    /**
 | 
			
		||||
     * We return null to avoid returning `undefined`
 | 
			
		||||
     * because `undefined` is not a valid JSON value.
 | 
			
		||||
     */
 | 
			
		||||
    return this.store.get(key) ?? null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setItem(key, value) {
 | 
			
		||||
    this.store[key] = String(value);
 | 
			
		||||
    this.store.set(key, String(value));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeItem(key) {
 | 
			
		||||
    delete this.store[key];
 | 
			
		||||
    this.store.delete(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get length() {
 | 
			
		||||
    return this.store.size;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
global.localStorage = new LocalStorageMock();
 | 
			
		||||
// eslint-disable-next-line no-undef
 | 
			
		||||
Object.defineProperty(window, 'localStorage', {
 | 
			
		||||
  writable: true,
 | 
			
		||||
  value: new LocalStorageMock(),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,39 @@
 | 
			
		||||
import { useEffect, useReducer } from 'react';
 | 
			
		||||
import { request } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient } from '@strapi/helper-plugin';
 | 
			
		||||
 | 
			
		||||
import reducer, { initialState } from './reducer';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO: refactor this to use react-query and move it to the `Roles` SettingsPage
 | 
			
		||||
 */
 | 
			
		||||
const useFetchPermissionsLayout = (id) => {
 | 
			
		||||
  const [{ data, error, isLoading }, dispatch] = useReducer(reducer, initialState);
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getData = async () => {
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA',
 | 
			
		||||
      });
 | 
			
		||||
      try {
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
      const { data } = await request('/admin/permissions', {
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        params: { role: id },
 | 
			
		||||
      });
 | 
			
		||||
        const {
 | 
			
		||||
          data: { data },
 | 
			
		||||
        } = await get('/admin/permissions', {
 | 
			
		||||
          params: { role: id },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
        data,
 | 
			
		||||
      });
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
          data,
 | 
			
		||||
        });
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        // silence is golden
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    getData();
 | 
			
		||||
  }, [id]);
 | 
			
		||||
  }, [id, get]);
 | 
			
		||||
 | 
			
		||||
  return { data, error, isLoading };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,48 @@
 | 
			
		||||
import { useCallback, useReducer, useEffect } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import reducer, { initialState } from './reducer';
 | 
			
		||||
 | 
			
		||||
const useFetchRole = (id) => {
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const [state, dispatch] = useReducer(reducer, initialState);
 | 
			
		||||
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (id) {
 | 
			
		||||
      const fetchRole = async (roleId) => {
 | 
			
		||||
        try {
 | 
			
		||||
          const [
 | 
			
		||||
            {
 | 
			
		||||
              data: { data: role },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              data: { data: permissions },
 | 
			
		||||
            },
 | 
			
		||||
          ] = await Promise.all(
 | 
			
		||||
            [`roles/${roleId}`, `roles/${roleId}/permissions`].map((endPoint) =>
 | 
			
		||||
              get(`/admin/${endPoint}`)
 | 
			
		||||
            )
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          dispatch({
 | 
			
		||||
            type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
            role,
 | 
			
		||||
            permissions,
 | 
			
		||||
          });
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          console.error(err);
 | 
			
		||||
 | 
			
		||||
          dispatch({
 | 
			
		||||
            type: 'GET_DATA_ERROR',
 | 
			
		||||
          });
 | 
			
		||||
          toggleNotification({
 | 
			
		||||
            type: 'warning',
 | 
			
		||||
            message: { id: 'notification.error' },
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      fetchRole(id);
 | 
			
		||||
    } else {
 | 
			
		||||
      dispatch({
 | 
			
		||||
@ -16,35 +51,7 @@ const useFetchRole = (id) => {
 | 
			
		||||
        permissions: [],
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [id]);
 | 
			
		||||
 | 
			
		||||
  const fetchRole = async (roleId) => {
 | 
			
		||||
    try {
 | 
			
		||||
      const [{ data: role }, { data: permissions }] = await Promise.all(
 | 
			
		||||
        [`roles/${roleId}`, `roles/${roleId}/permissions`].map((endPoint) =>
 | 
			
		||||
          request(`/admin/${endPoint}`, { method: 'GET' })
 | 
			
		||||
        )
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
        role,
 | 
			
		||||
        permissions,
 | 
			
		||||
      });
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA_ERROR',
 | 
			
		||||
      });
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'warning',
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }, [get, id, toggleNotification]);
 | 
			
		||||
 | 
			
		||||
  const handleSubmitSucceeded = useCallback((data) => {
 | 
			
		||||
    dispatch({
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,32 @@
 | 
			
		||||
import { useReducer, useEffect } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useReducer, useEffect, useCallback } from 'react';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import reducer, { initialState } from './reducer';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO: refactor this to not use the `useReducer` hook,
 | 
			
		||||
 * it's not really necessary. Also use `useQuery`?
 | 
			
		||||
 */
 | 
			
		||||
const useModels = () => {
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const [state, dispatch] = useReducer(reducer, initialState);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    fetchModels();
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, []);
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const fetchModels = async () => {
 | 
			
		||||
  const fetchModels = useCallback(async () => {
 | 
			
		||||
    dispatch({
 | 
			
		||||
      type: 'GET_MODELS',
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const [{ data: components }, { data: contentTypes }] = await Promise.all(
 | 
			
		||||
        ['components', 'content-types'].map((endPoint) =>
 | 
			
		||||
          request(`/content-manager/${endPoint}`, { method: 'GET' })
 | 
			
		||||
        )
 | 
			
		||||
      const [
 | 
			
		||||
        {
 | 
			
		||||
          data: { data: components },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          data: { data: contentTypes },
 | 
			
		||||
        },
 | 
			
		||||
      ] = await Promise.all(
 | 
			
		||||
        ['components', 'content-types'].map((endPoint) => get(`/content-manager/${endPoint}`))
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
@ -37,7 +43,11 @@ const useModels = () => {
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }, [toggleNotification, get]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    fetchModels();
 | 
			
		||||
  }, [fetchModels]);
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    ...state,
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,15 @@
 | 
			
		||||
import { useEffect, useReducer } from 'react';
 | 
			
		||||
import { request, useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
 | 
			
		||||
import omit from 'lodash/omit';
 | 
			
		||||
import { checkFormValidity, formatAPIErrors } from '../../utils';
 | 
			
		||||
import { initialState, reducer } from './reducer';
 | 
			
		||||
import init from './init';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO: refactor this, it's confusing and hard to read.
 | 
			
		||||
 * It's also only used in `Settings/pages/SingleSignOn` so it can
 | 
			
		||||
 * probably be deleted and everything written there...
 | 
			
		||||
 */
 | 
			
		||||
const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
 | 
			
		||||
  const [
 | 
			
		||||
    { formErrors, initialData, isLoading, modifiedData, showHeaderButtonLoader, showHeaderLoader },
 | 
			
		||||
@ -13,10 +18,14 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const { lockApp, unlockApp } = useOverlayBlocker();
 | 
			
		||||
 | 
			
		||||
  const { get, put } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getData = async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        const { data } = await request(endPoint, { method: 'GET' });
 | 
			
		||||
        const {
 | 
			
		||||
          data: { data },
 | 
			
		||||
        } = await get(endPoint);
 | 
			
		||||
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
@ -85,10 +94,9 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
 | 
			
		||||
          cleanedData.roles = cleanedData.roles.map((role) => role.id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const { data } = await request(endPoint, {
 | 
			
		||||
          method: 'PUT',
 | 
			
		||||
          body: cleanedData,
 | 
			
		||||
        });
 | 
			
		||||
        const {
 | 
			
		||||
          data: { data },
 | 
			
		||||
        } = await put(endPoint, cleanedData);
 | 
			
		||||
 | 
			
		||||
        cbSuccess(data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,17 +6,16 @@
 | 
			
		||||
 | 
			
		||||
import React, { useEffect, useState, useMemo, lazy, Suspense } from 'react';
 | 
			
		||||
import { Switch, Route } from 'react-router-dom';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import {
 | 
			
		||||
  LoadingIndicatorPage,
 | 
			
		||||
  auth,
 | 
			
		||||
  request,
 | 
			
		||||
  useNotification,
 | 
			
		||||
  TrackingProvider,
 | 
			
		||||
  prefixFileUrlWithBackendUrl,
 | 
			
		||||
  useAppInfos,
 | 
			
		||||
  useFetchClient,
 | 
			
		||||
} from '@strapi/helper-plugin';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import { SkipToContent } from '@strapi/design-system';
 | 
			
		||||
import { useIntl } from 'react-intl';
 | 
			
		||||
import PrivateRoute from '../../components/PrivateRoute';
 | 
			
		||||
@ -41,7 +40,7 @@ function App() {
 | 
			
		||||
    hasAdmin: false,
 | 
			
		||||
  });
 | 
			
		||||
  const appInfo = useAppInfos();
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
  const { get, post } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const authRoutes = useMemo(() => {
 | 
			
		||||
    return makeUniqueRoutes(
 | 
			
		||||
@ -57,11 +56,10 @@ function App() {
 | 
			
		||||
    const renewToken = async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        const {
 | 
			
		||||
          data: { token },
 | 
			
		||||
        } = await request('/admin/renew-token', {
 | 
			
		||||
          method: 'POST',
 | 
			
		||||
          body: { token: currentToken },
 | 
			
		||||
        });
 | 
			
		||||
          data: {
 | 
			
		||||
            data: { token },
 | 
			
		||||
          },
 | 
			
		||||
        } = await post('/admin/renew-token', { token: currentToken });
 | 
			
		||||
        auth.updateToken(token);
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        // Refresh app
 | 
			
		||||
@ -73,7 +71,7 @@ function App() {
 | 
			
		||||
    if (currentToken) {
 | 
			
		||||
      renewToken();
 | 
			
		||||
    }
 | 
			
		||||
  }, []);
 | 
			
		||||
  }, [post]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getData = async () => {
 | 
			
		||||
@ -82,7 +80,7 @@ function App() {
 | 
			
		||||
          data: {
 | 
			
		||||
            data: { hasAdmin, uuid, menuLogo, authLogo },
 | 
			
		||||
          },
 | 
			
		||||
        } = await axios.get(`${strapi.backendURL}/admin/init`);
 | 
			
		||||
        } = await get(`/admin/init`);
 | 
			
		||||
 | 
			
		||||
        updateProjectSettings({
 | 
			
		||||
          menuLogo: prefixFileUrlWithBackendUrl(menuLogo),
 | 
			
		||||
@ -102,20 +100,17 @@ function App() {
 | 
			
		||||
          setTelemetryProperties(properties);
 | 
			
		||||
 | 
			
		||||
          try {
 | 
			
		||||
            await fetch('https://analytics.strapi.io/api/v2/track', {
 | 
			
		||||
              method: 'POST',
 | 
			
		||||
              body: JSON.stringify({
 | 
			
		||||
                // This event is anonymous
 | 
			
		||||
                event: 'didInitializeAdministration',
 | 
			
		||||
                userId: '',
 | 
			
		||||
                deviceId,
 | 
			
		||||
                eventPropeties: {},
 | 
			
		||||
                userProperties: { environment: appInfo.currentEnvironment },
 | 
			
		||||
                groupProperties: { ...properties, projectId: uuid },
 | 
			
		||||
              }),
 | 
			
		||||
              headers: {
 | 
			
		||||
                'Content-Type': 'application/json',
 | 
			
		||||
              },
 | 
			
		||||
            /**
 | 
			
		||||
             * TODO: remove this call to `axios`
 | 
			
		||||
             */
 | 
			
		||||
            await axios.post('https://analytics.strapi.io/api/v2/track', {
 | 
			
		||||
              // This event is anonymous
 | 
			
		||||
              event: 'didInitializeAdministration',
 | 
			
		||||
              userId: '',
 | 
			
		||||
              deviceId,
 | 
			
		||||
              eventPropeties: {},
 | 
			
		||||
              userProperties: { environment: appInfo.currentEnvironment },
 | 
			
		||||
              groupProperties: { ...properties, projectId: uuid },
 | 
			
		||||
            });
 | 
			
		||||
          } catch (e) {
 | 
			
		||||
            // Silent.
 | 
			
		||||
 | 
			
		||||
@ -43,9 +43,7 @@ const PendingLogoDialog = ({ onClose, asset, prev, next, goTo, setLocalImage, on
 | 
			
		||||
            })}
 | 
			
		||||
          </Button>
 | 
			
		||||
        </Flex>
 | 
			
		||||
        <Box maxWidth={pxToRem(180)}>
 | 
			
		||||
          <ImageCardAsset asset={asset} />
 | 
			
		||||
        </Box>
 | 
			
		||||
        <Box maxWidth={pxToRem(180)}>{asset.url ? <ImageCardAsset asset={asset} /> : null}</Box>
 | 
			
		||||
      </Box>
 | 
			
		||||
      <ModalFooter
 | 
			
		||||
        startActions={
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ import {
 | 
			
		||||
  Form,
 | 
			
		||||
  LoadingIndicatorPage,
 | 
			
		||||
  SettingsPageTitle,
 | 
			
		||||
  request,
 | 
			
		||||
  useFetchClient,
 | 
			
		||||
  useNotification,
 | 
			
		||||
  useOverlayBlocker,
 | 
			
		||||
  useTracking,
 | 
			
		||||
@ -59,6 +59,8 @@ const CreatePage = () => {
 | 
			
		||||
  const { isLoading: isLayoutLoading, data: permissionsLayout } = useFetchPermissionsLayout();
 | 
			
		||||
  const { permissions: rolePermissions, isLoading: isRoleLoading } = useFetchRole(id);
 | 
			
		||||
 | 
			
		||||
  const { post, put } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const handleCreateRoleSubmit = (data) => {
 | 
			
		||||
    lockApp();
 | 
			
		||||
    setIsSubmiting(true);
 | 
			
		||||
@ -69,13 +71,8 @@ const CreatePage = () => {
 | 
			
		||||
      trackUsage('willCreateNewRole');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Promise.resolve(
 | 
			
		||||
      request('/admin/roles', {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        body: data,
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
      .then(async (res) => {
 | 
			
		||||
    Promise.resolve(post('/admin/roles', data))
 | 
			
		||||
      .then(async ({ data: res }) => {
 | 
			
		||||
        const { permissionsToSend } = permissionsRef.current.getPermissions();
 | 
			
		||||
 | 
			
		||||
        if (id) {
 | 
			
		||||
@ -85,10 +82,7 @@ const CreatePage = () => {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (res.data.id && !isEmpty(permissionsToSend)) {
 | 
			
		||||
          await request(`/admin/roles/${res.data.id}/permissions`, {
 | 
			
		||||
            method: 'PUT',
 | 
			
		||||
            body: { permissions: permissionsToSend },
 | 
			
		||||
          });
 | 
			
		||||
          await put(`/admin/roles/${res.data.id}/permissions`, { permissions: permissionsToSend });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return res;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import React, { useRef, useState } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
  request,
 | 
			
		||||
  useFetchClient,
 | 
			
		||||
  useNotification,
 | 
			
		||||
  useOverlayBlocker,
 | 
			
		||||
  useTracking,
 | 
			
		||||
@ -37,6 +37,8 @@ const EditPage = () => {
 | 
			
		||||
    onSubmitSucceeded,
 | 
			
		||||
  } = useFetchRole(id);
 | 
			
		||||
 | 
			
		||||
  const { put } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const handleEditRoleSubmit = async (data) => {
 | 
			
		||||
    try {
 | 
			
		||||
      lockApp();
 | 
			
		||||
@ -44,17 +46,11 @@ const EditPage = () => {
 | 
			
		||||
 | 
			
		||||
      const { permissionsToSend, didUpdateConditions } = permissionsRef.current.getPermissions();
 | 
			
		||||
 | 
			
		||||
      await request(`/admin/roles/${id}`, {
 | 
			
		||||
        method: 'PUT',
 | 
			
		||||
        body: data,
 | 
			
		||||
      });
 | 
			
		||||
      await put(`/admin/roles/${id}`, data);
 | 
			
		||||
 | 
			
		||||
      if (role.code !== 'strapi-super-admin') {
 | 
			
		||||
        await request(`/admin/roles/${id}/permissions`, {
 | 
			
		||||
          method: 'PUT',
 | 
			
		||||
          body: {
 | 
			
		||||
            permissions: permissionsToSend,
 | 
			
		||||
          },
 | 
			
		||||
        await put(`/admin/roles/${id}/permissions`, {
 | 
			
		||||
          permissions: permissionsToSend,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (didUpdateConditions) {
 | 
			
		||||
 | 
			
		||||
@ -3,12 +3,10 @@
 | 
			
		||||
 * EditView
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
import React, { useCallback, useMemo } from 'react';
 | 
			
		||||
import * as React from 'react';
 | 
			
		||||
import {
 | 
			
		||||
  LoadingIndicatorPage,
 | 
			
		||||
  request,
 | 
			
		||||
  SettingsPageTitle,
 | 
			
		||||
  to,
 | 
			
		||||
  useNotification,
 | 
			
		||||
  useOverlayBlocker,
 | 
			
		||||
  useFetchClient,
 | 
			
		||||
@ -30,19 +28,20 @@ const EditView = () => {
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const queryClient = useQueryClient();
 | 
			
		||||
  const { isLoading: isLoadingForModels, collectionTypes } = useModels();
 | 
			
		||||
  const { post } = useFetchClient();
 | 
			
		||||
  const { put, get, post } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const isCreating = id === 'create';
 | 
			
		||||
 | 
			
		||||
  const fetchWebhook = useCallback(
 | 
			
		||||
    async (id) => {
 | 
			
		||||
      const [err, { data }] = await to(
 | 
			
		||||
        request(`/admin/webhooks/${id}`, {
 | 
			
		||||
          method: 'GET',
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
  const { isLoading, data } = useQuery(
 | 
			
		||||
    ['get-webhook', id],
 | 
			
		||||
    async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        const {
 | 
			
		||||
          data: { data },
 | 
			
		||||
        } = await get(`/admin/webhooks/${id}`);
 | 
			
		||||
 | 
			
		||||
      if (err) {
 | 
			
		||||
        return data;
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        toggleNotification({
 | 
			
		||||
          type: 'warning',
 | 
			
		||||
          message: { id: 'notification.error' },
 | 
			
		||||
@ -50,16 +49,12 @@ const EditView = () => {
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return data;
 | 
			
		||||
    },
 | 
			
		||||
    [toggleNotification]
 | 
			
		||||
    {
 | 
			
		||||
      enabled: !isCreating,
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const { isLoading, data } = useQuery(['get-webhook', id], () => fetchWebhook(id), {
 | 
			
		||||
    enabled: !isCreating,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const {
 | 
			
		||||
    isLoading: isTriggering,
 | 
			
		||||
    data: triggerResponse,
 | 
			
		||||
@ -77,25 +72,15 @@ const EditView = () => {
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  const createWebhookMutation = useMutation((body) =>
 | 
			
		||||
    request('/admin/webhooks', {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
      body,
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
  const createWebhookMutation = useMutation((body) => post('/admin/webhooks', body));
 | 
			
		||||
 | 
			
		||||
  const updateWebhookMutation = useMutation(({ id, body }) =>
 | 
			
		||||
    request(`/admin/webhooks/${id}`, {
 | 
			
		||||
      method: 'PUT',
 | 
			
		||||
      body,
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
  const updateWebhookMutation = useMutation(({ id, body }) => put(`/admin/webhooks/${id}`, body));
 | 
			
		||||
 | 
			
		||||
  const handleSubmit = async (data) => {
 | 
			
		||||
    if (isCreating) {
 | 
			
		||||
      lockApp();
 | 
			
		||||
      createWebhookMutation.mutate(cleanData(data), {
 | 
			
		||||
        onSuccess(result) {
 | 
			
		||||
        onSuccess({ data: result }) {
 | 
			
		||||
          toggleNotification({
 | 
			
		||||
            type: 'success',
 | 
			
		||||
            message: { id: 'Settings.webhooks.created' },
 | 
			
		||||
@ -138,7 +123,7 @@ const EditView = () => {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const isDraftAndPublishEvents = useMemo(
 | 
			
		||||
  const isDraftAndPublishEvents = React.useMemo(
 | 
			
		||||
    () => collectionTypes.some((ct) => ct.options.draftAndPublish === true),
 | 
			
		||||
    [collectionTypes]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ import React, { useEffect, useReducer, useRef, useState } from 'react';
 | 
			
		||||
import { useHistory, useLocation } from 'react-router-dom';
 | 
			
		||||
import { useIntl } from 'react-intl';
 | 
			
		||||
import {
 | 
			
		||||
  request,
 | 
			
		||||
  useFetchClient,
 | 
			
		||||
  useRBAC,
 | 
			
		||||
  LoadingIndicatorPage,
 | 
			
		||||
  useNotification,
 | 
			
		||||
@ -63,6 +63,8 @@ const ListView = () => {
 | 
			
		||||
  );
 | 
			
		||||
  const { notifyStatus } = useNotifyAT();
 | 
			
		||||
 | 
			
		||||
  const { get, del, post, put } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useFocusWhenNavigate();
 | 
			
		||||
  const { push } = useHistory();
 | 
			
		||||
  const { pathname } = useLocation();
 | 
			
		||||
@ -78,42 +80,45 @@ const ListView = () => {
 | 
			
		||||
    };
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * TODO: refactor this, but actually refactor
 | 
			
		||||
   * the whole component. Needs some love.
 | 
			
		||||
   */
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const fetchWebHooks = async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        const {
 | 
			
		||||
          data: { data },
 | 
			
		||||
        } = await get('/admin/webhooks');
 | 
			
		||||
 | 
			
		||||
        if (isMounted.current) {
 | 
			
		||||
          dispatch({
 | 
			
		||||
            type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
            data,
 | 
			
		||||
          });
 | 
			
		||||
          notifyStatus('webhooks have been loaded');
 | 
			
		||||
        }
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        console.log(err);
 | 
			
		||||
 | 
			
		||||
        if (isMounted.current) {
 | 
			
		||||
          if (err.code !== 20) {
 | 
			
		||||
            toggleNotification({
 | 
			
		||||
              type: 'warning',
 | 
			
		||||
              message: { id: 'notification.error' },
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
          dispatch({
 | 
			
		||||
            type: 'TOGGLE_LOADING',
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (canRead) {
 | 
			
		||||
      fetchWebHooks();
 | 
			
		||||
    }
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [canRead]);
 | 
			
		||||
 | 
			
		||||
  const fetchWebHooks = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await request('/admin/webhooks', {
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      if (isMounted.current) {
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
          data,
 | 
			
		||||
        });
 | 
			
		||||
        notifyStatus('webhooks have been loaded');
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
 | 
			
		||||
      if (isMounted.current) {
 | 
			
		||||
        if (err.code !== 20) {
 | 
			
		||||
          toggleNotification({
 | 
			
		||||
            type: 'warning',
 | 
			
		||||
            message: { id: 'notification.error' },
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'TOGGLE_LOADING',
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }, [canRead, get, notifyStatus, toggleNotification]);
 | 
			
		||||
 | 
			
		||||
  const handleToggleModal = () => {
 | 
			
		||||
    setShowModal((prev) => !prev);
 | 
			
		||||
@ -129,15 +134,16 @@ const ListView = () => {
 | 
			
		||||
 | 
			
		||||
  const handleConfirmDeleteOne = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      await request(`/admin/webhooks/${webhookToDelete}`, {
 | 
			
		||||
        method: 'DELETE',
 | 
			
		||||
      });
 | 
			
		||||
      await del(`/admin/webhooks/${webhookToDelete}`);
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'WEBHOOK_DELETED',
 | 
			
		||||
        index: getWebhookIndex(webhookToDelete),
 | 
			
		||||
      });
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      /**
 | 
			
		||||
       * TODO: especially this.
 | 
			
		||||
       */
 | 
			
		||||
      if (err.code !== 20) {
 | 
			
		||||
        toggleNotification({
 | 
			
		||||
          type: 'warning',
 | 
			
		||||
@ -154,10 +160,7 @@ const ListView = () => {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await request('/admin/webhooks/batch-delete', {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        body,
 | 
			
		||||
      });
 | 
			
		||||
      await post('/admin/webhooks/batch-delete', body);
 | 
			
		||||
 | 
			
		||||
      if (isMounted.current) {
 | 
			
		||||
        dispatch({
 | 
			
		||||
@ -207,10 +210,7 @@ const ListView = () => {
 | 
			
		||||
        value,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      await request(`/admin/webhooks/${id}`, {
 | 
			
		||||
        method: 'PUT',
 | 
			
		||||
        body,
 | 
			
		||||
      });
 | 
			
		||||
      await put(`/admin/webhooks/${id}`, body);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      if (isMounted.current) {
 | 
			
		||||
        dispatch({
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
  "Auth.components.Oops.text": "Votre compte a été suspendu.",
 | 
			
		||||
  "Auth.components.Oops.text.admin": "Si c'est une erreur, veuillez contacter votre administrateur.",
 | 
			
		||||
  "Auth.components.Oops.title": "Oups !",
 | 
			
		||||
  "Auth.form.active.label": "Actif",
 | 
			
		||||
  "Auth.form.button.forgot-password": "Envoyer à nouveau",
 | 
			
		||||
  "Auth.form.button.go-home": "Retour à l'accueil",
 | 
			
		||||
  "Auth.form.button.login": "Se connecter",
 | 
			
		||||
@ -54,6 +55,7 @@
 | 
			
		||||
  "Auth.login.sso.subtitle": "Vous connecter via SSO",
 | 
			
		||||
  "Auth.privacy-policy-agreement.policy": "la politique de confidentialité",
 | 
			
		||||
  "Auth.privacy-policy-agreement.terms": "termes",
 | 
			
		||||
  "Auth.reset-password.title": "Réinitialiser le mot de passe",
 | 
			
		||||
  "Content Manager": "Content Manager",
 | 
			
		||||
  "Content Type Builder": "Content Types Builder",
 | 
			
		||||
  "Documentation": "Documentation",
 | 
			
		||||
@ -74,22 +76,95 @@
 | 
			
		||||
  "Roles.ListPage.notification.delete-all-not-allowed": "Certains rôles n'ont pas pu être supprimés car ils sont associés à des utilisateurs.",
 | 
			
		||||
  "Roles.ListPage.notification.delete-not-allowed": "Un rôle ne peu pas être supprimé s'il est associé à des utilisateurs.",
 | 
			
		||||
  "Roles.RoleRow.select-all": "Sélectionner {name} pour action groupée",
 | 
			
		||||
  "Roles.RoleRow.user-count": "{number, plural, =0 {# utilisateur} one {# utilisateur} other {# utilisateurs}}",
 | 
			
		||||
  "Roles.components.List.empty.withSearch": "Il n'y a pas de rôles correspondant à la recherche ({search})...",
 | 
			
		||||
  "Settings.PageTitle": "Réglages - {name}",
 | 
			
		||||
  "Settings.apiTokens.ListView.headers.createdAt": "Créé le",
 | 
			
		||||
  "Settings.apiTokens.ListView.headers.description": "Description",
 | 
			
		||||
  "Settings.apiTokens.ListView.headers.lastUsedAt": "Dernière utilisation le",
 | 
			
		||||
  "Settings.apiTokens.ListView.headers.name": "Nom",
 | 
			
		||||
  "Settings.apiTokens.ListView.headers.type": "Type de jeton",
 | 
			
		||||
  "Settings.apiTokens.regenerate": "Régénérer",
 | 
			
		||||
  "Settings.apiTokens.createPage.title": "Créer un jeton d'API",
 | 
			
		||||
  "Settings.transferTokens.createPage.title": "Créer un jeton de transfert",
 | 
			
		||||
  "Settings.tokens.RegenerateDialog.title": "Régénérer le jeton",
 | 
			
		||||
  "Settings.apiTokens.addFirstToken": "Ajouter votre premier jeton d'API",
 | 
			
		||||
  "Settings.apiTokens.addNewToken": "Ajouter un nouveau jeton d'API",
 | 
			
		||||
  "Settings.tokens.copy.editMessage": "Pour des raisons de sécurité, vous ne pouvoir voir votre jeton qu'une seule fois",
 | 
			
		||||
  "Settings.tokens.copy.editTitle": "Ce jeton n'est désormais plus accessible",
 | 
			
		||||
  "Settings.tokens.copy.lastWarning": "Assurez-vous de copier ce jeton, vous ne pourrez plus le revoir par la suite !",
 | 
			
		||||
  "Settings.apiTokens.create": "Ajouter une entrée",
 | 
			
		||||
  "Settings.apiTokens.createPage.permissions.description": "Seules les actions rattachées à une route sont listées ci-dessous.",
 | 
			
		||||
  "Settings.apiTokens.createPage.permissions.title": "Permissions",
 | 
			
		||||
  "Settings.apiTokens.description": "Liste des jetons générés pour consommer l'API",
 | 
			
		||||
  "Settings.apiTokens.createPage.BoundRoute.title": "Route rattachée à",
 | 
			
		||||
  "Settings.apiTokens.createPage.permissions.header.title": "Paramètres avancés",
 | 
			
		||||
  "Settings.apiTokens.createPage.permissions.header.hint": "Sélectionner les actions de l'application ou du plugin et sur l'icône de la roue crantée pour afficher la route rattachée",
 | 
			
		||||
  "Settings.tokens.duration.30-days": "30 jours",
 | 
			
		||||
  "Settings.tokens.duration.7-days": "7 jours",
 | 
			
		||||
  "Settings.tokens.duration.90-days": "90 jours",
 | 
			
		||||
  "Settings.tokens.duration.expiration-date": "Date d'expiration",
 | 
			
		||||
  "Settings.tokens.duration.unlimited": "Illimité",
 | 
			
		||||
  "Settings.apiTokens.emptyStateLayout": "Vous n'avez pas encore de contenu...",
 | 
			
		||||
  "Settings.tokens.form.duration": "Durée de vie du jeton",
 | 
			
		||||
  "Settings.tokens.form.type": "Type de jeton",
 | 
			
		||||
  "Settings.tokens.form.name": "Nom",
 | 
			
		||||
  "Settings.tokens.form.description": "Description",
 | 
			
		||||
  "Settings.tokens.notification.copied": "Jeton copié dans le press-papiers.",
 | 
			
		||||
  "Settings.apiTokens.title": "Jetons d'API",
 | 
			
		||||
  "Settings.tokens.popUpWarning.message": "Êtes-vous sûr(e) de vouloir régénérer ce jeton ?",
 | 
			
		||||
  "Settings.tokens.Button.cancel": "Annuler",
 | 
			
		||||
  "Settings.tokens.Button.regenerate": "Régénérer",
 | 
			
		||||
  "Settings.tokens.types.full-access": "Accès total",
 | 
			
		||||
  "Settings.tokens.types.read-only": "Lecture seule",
 | 
			
		||||
  "Settings.tokens.types.custom": "Custom",
 | 
			
		||||
  "Settings.tokens.regenerate": "Régénérer",
 | 
			
		||||
  "Settings.transferTokens.title": "Jetons de transfert",
 | 
			
		||||
  "Settings.transferTokens.description": "Liste des jetons de transfert générés",
 | 
			
		||||
  "Settings.transferTokens.create": "Créer un nouveau jeton de transfert",
 | 
			
		||||
  "Settings.transferTokens.addFirstToken": "Ajouter votre premier jeton de transfert",
 | 
			
		||||
  "Settings.transferTokens.addNewToken": "Ajouter un nouveau jeton de transfert",
 | 
			
		||||
  "Settings.transferTokens.emptyStateLayout": "Vous n'avez aucun contenu pour le moment...",
 | 
			
		||||
  "Settings.tokens.ListView.headers.name": "Nom",
 | 
			
		||||
  "Settings.tokens.ListView.headers.description": "Description",
 | 
			
		||||
  "Settings.transferTokens.ListView.headers.type": "Type de jeton",
 | 
			
		||||
  "Settings.tokens.ListView.headers.createdAt": "Créé le",
 | 
			
		||||
  "Settings.tokens.ListView.headers.lastUsedAt": "Dernière utilisation",
 | 
			
		||||
  "Settings.application.ee.admin-seats.count": "<text>{enforcementUserCount}</text>/{permittedSeats}",
 | 
			
		||||
  "Settings.application.ee.admin-seats.at-limit-tooltip": "Limite atteinte : ajouter des places pour inviter d'autres utilisateurs",
 | 
			
		||||
  "Settings.application.ee.admin-seats.add-seats": "{isHostedOnStrapiCloud, select, true {AJouter des places} other {Contacter le service clients}}",
 | 
			
		||||
  "Settings.application.customization": "Customisation",
 | 
			
		||||
  "Settings.application.customization.auth-logo.carousel-hint": "Remplacer le logo dans la page de connexion",
 | 
			
		||||
  "Settings.application.customization.carousel-hint": "Changer le logo dans l'interface d'administration (dimensions maximales: {dimension}x{dimension}, poids maximal du fichier : {size}KB)",
 | 
			
		||||
  "Settings.application.customization.carousel-slide.label": "Logo slide",
 | 
			
		||||
  "Settings.application.customization.carousel.auth-logo.title": "Logo de connexion",
 | 
			
		||||
  "Settings.application.customization.carousel.change-action": "Changer le logo",
 | 
			
		||||
  "Settings.application.customization.carousel.menu-logo.title": "Logo du menu",
 | 
			
		||||
  "Settings.application.customization.carousel.reset-action": "Réinitialiser le logo",
 | 
			
		||||
  "Settings.application.customization.carousel.title": "Logo",
 | 
			
		||||
  "Settings.application.customization.menu-logo.carousel-hint": "Remplacer le logo dans la navigation principale",
 | 
			
		||||
  "Settings.application.customization.modal.cancel": "Annuler",
 | 
			
		||||
  "Settings.application.customization.modal.pending": "Téléchargement du logo",
 | 
			
		||||
  "Settings.application.customization.modal.pending.card-badge": "image",
 | 
			
		||||
  "Settings.application.customization.modal.pending.choose-another": "Choisir un autre logo",
 | 
			
		||||
  "Settings.application.customization.modal.pending.subtitle": "Gérer le logo choisi avant de le télécharger",
 | 
			
		||||
  "Settings.application.customization.modal.pending.title": "Logo prêt pour le téléchargement",
 | 
			
		||||
  "Settings.application.customization.modal.pending.upload": "Téléchargement du logo",
 | 
			
		||||
  "Settings.application.customization.modal.tab.label": "Comment voulez-vous télécharger vos medias ?",
 | 
			
		||||
  "Settings.application.customization.modal.upload": "Télécharger le logo",
 | 
			
		||||
  "Settings.application.customization.modal.upload.cta.browse": "Explorer les fichiers",
 | 
			
		||||
  "Settings.application.customization.modal.upload.drag-drop": "Glisser-déposer ici ou",
 | 
			
		||||
  "Settings.application.customization.modal.upload.error-format": "Mauvais format chargé (formats acceptés : jpeg, jpg, png, svg).",
 | 
			
		||||
  "Settings.application.customization.modal.upload.error-network": "Erreur réseau",
 | 
			
		||||
  "Settings.application.customization.modal.upload.error-size": "Le fichier téléchargé est trop grand (dimensions max : {dimension}x{dimension}, poids max: {size}KB)",
 | 
			
		||||
  "Settings.application.customization.modal.upload.file-validation": "Dimensions maximales : {dimension}x{dimension}, poids maximal : {size}KB",
 | 
			
		||||
  "Settings.application.customization.modal.upload.from-computer": "Depuis l'ordinateur",
 | 
			
		||||
  "Settings.application.customization.modal.upload.from-url": "Depuis une URL",
 | 
			
		||||
  "Settings.application.customization.modal.upload.from-url.input-label": "URL",
 | 
			
		||||
  "Settings.application.customization.modal.upload.next": "Suivant",
 | 
			
		||||
  "Settings.application.customization.size-details": "Dimensions maximales : {dimension}×{dimension}, poids maximal : {size}KB",
 | 
			
		||||
  "Settings.application.description": "Informations globales du panneau d'administration",
 | 
			
		||||
  "Settings.application.edition-title": "plan actuel",
 | 
			
		||||
  "Settings.application.ee-or-ce": "{communityEdition, select, true {Édition Communauté} other {Édition Entreprise}}",
 | 
			
		||||
  "Settings.application.get-help": "Obtenir de l'aide",
 | 
			
		||||
  "Settings.application.link-pricing": "Voir tous les tarifs",
 | 
			
		||||
  "Settings.application.link-upgrade": "Mettez à niveau votre panneau d'administration",
 | 
			
		||||
@ -566,6 +641,14 @@
 | 
			
		||||
  "content-manager.plugin.description.long": "Visualisez, modifiez et supprimez les données de votre base de données.",
 | 
			
		||||
  "content-manager.plugin.description.short": "Visualisez, modifiez et supprimez les données de votre base de données.",
 | 
			
		||||
  "content-manager.popover.display-relations.label": "Afficher les relations",
 | 
			
		||||
  "content-manager.relation.add": "Ajouter une relation",
 | 
			
		||||
  "content-manager.relation.disconnect": "Supprimer",
 | 
			
		||||
  "content-manager.relation.isLoading": "Chargement des relations en cours",
 | 
			
		||||
  "content-manager.relation.loadMore": "Charger davantage",
 | 
			
		||||
  "content-manager.relation.notAvailable": "Aucune relation disponible",
 | 
			
		||||
  "content-manager.relation.publicationState.draft": "Brouillon",
 | 
			
		||||
  "content-manager.relation.publicationState.published": "Publiée",
 | 
			
		||||
  "content-manager.select.currently.selected": "{count} actuellement sélectionnées",
 | 
			
		||||
  "content-manager.success.record.delete": "Supprimé",
 | 
			
		||||
  "content-manager.success.record.publish": "Publié",
 | 
			
		||||
  "content-manager.success.record.save": "Sauvegardé",
 | 
			
		||||
@ -575,9 +658,11 @@
 | 
			
		||||
  "content-manager.popUpWarning.warning.publish-question": "Êtes-vous sûr de vouloir le publier ?",
 | 
			
		||||
  "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "Oui, publier",
 | 
			
		||||
  "content-manager.popUpwarning.warning.has-draft-relations.message": "<b>{count, plural, =0 { des relations de votre contenu n'est} one { des relations de votre contenu n'est} other { des relations de votre contenu ne sont}}</b> pas publié actuellement.<br></br>Cela peut engendrer des liens cassés ou des erreurs dans votre projet.",
 | 
			
		||||
  "dark": "Sombre",
 | 
			
		||||
  "form.button.continue": "Continuer",
 | 
			
		||||
  "global.search": "Rechercher",
 | 
			
		||||
  "global.actions": "Actions",
 | 
			
		||||
  "global.auditLogs": "Journaux d'audit",
 | 
			
		||||
  "global.back": "Retour",
 | 
			
		||||
  "global.cancel": "Annuler",
 | 
			
		||||
  "global.change-password": "Modifier le mot de passe",
 | 
			
		||||
@ -606,6 +691,7 @@
 | 
			
		||||
  "global.settings": "Paramètres",
 | 
			
		||||
  "global.type": "Type",
 | 
			
		||||
  "global.users": "Utilisateurs",
 | 
			
		||||
  "light": "Clair",
 | 
			
		||||
  "form.button.done": "Terminer",
 | 
			
		||||
  "global.prompt.unsaved": "Êtes-vous sûr de vouloir quitter cette page? Toutes vos modifications seront perdues",
 | 
			
		||||
  "notification.contentType.relations.conflict": "Le Type de Contenu à des relations qui rentrent en conflit",
 | 
			
		||||
@ -621,8 +707,10 @@
 | 
			
		||||
  "notification.success.title": "Succès :",
 | 
			
		||||
  "notification.version.update.message": "Une nouvelle version de Strapi est disponible !",
 | 
			
		||||
  "notification.warning.title": "Attention :",
 | 
			
		||||
  "notification.warning.404": "404 - Introuvable",
 | 
			
		||||
  "or": "OU",
 | 
			
		||||
  "request.error.model.unknown": "Le model n'existe pas",
 | 
			
		||||
  "selectButtonTitle": "Sélectionner",
 | 
			
		||||
  "skipToContent": "Aller au contenu",
 | 
			
		||||
  "submit": "Soumettre"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { useReducer, useEffect } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
 | 
			
		||||
import { getRequestUrl } from '../../../../admin/src/utils';
 | 
			
		||||
import reducer, { initialState } from './reducer';
 | 
			
		||||
@ -7,43 +7,42 @@ import reducer, { initialState } from './reducer';
 | 
			
		||||
const useAuthProviders = ({ ssoEnabled }) => {
 | 
			
		||||
  const [state, dispatch] = useReducer(reducer, initialState);
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    fetchAuthProviders();
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, []);
 | 
			
		||||
    const fetchAuthProviders = async () => {
 | 
			
		||||
      try {
 | 
			
		||||
        if (!ssoEnabled) {
 | 
			
		||||
          dispatch({
 | 
			
		||||
            type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
            data: [],
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const { data } = await get(getRequestUrl('providers'));
 | 
			
		||||
 | 
			
		||||
  const fetchAuthProviders = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!ssoEnabled) {
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
          data: [],
 | 
			
		||||
          data,
 | 
			
		||||
        });
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        console.error(err);
 | 
			
		||||
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA_ERROR',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
        toggleNotification({
 | 
			
		||||
          type: 'warning',
 | 
			
		||||
          message: { id: 'notification.error' },
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
      const requestUrl = getRequestUrl('providers');
 | 
			
		||||
      const data = await request(requestUrl, { method: 'GET' });
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
        data,
 | 
			
		||||
      });
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA_ERROR',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'warning',
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
    fetchAuthProviders();
 | 
			
		||||
  }, [get, ssoEnabled, toggleNotification]);
 | 
			
		||||
 | 
			
		||||
  return state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import React, { useEffect, useRef, useCallback } from 'react';
 | 
			
		||||
import { useHistory, useRouteMatch } from 'react-router-dom';
 | 
			
		||||
import { useIntl } from 'react-intl';
 | 
			
		||||
import Cookies from 'js-cookie';
 | 
			
		||||
import { auth, LoadingIndicatorPage, request } from '@strapi/helper-plugin';
 | 
			
		||||
import { auth, LoadingIndicatorPage, useFetchClient } from '@strapi/helper-plugin';
 | 
			
		||||
import { getRequestUrl } from '../../../../admin/src/utils';
 | 
			
		||||
 | 
			
		||||
const AuthResponse = () => {
 | 
			
		||||
@ -24,6 +24,8 @@ const AuthResponse = () => {
 | 
			
		||||
    );
 | 
			
		||||
  }, [push]);
 | 
			
		||||
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const fetchUserInfo = useCallback(async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const jwtToken = Cookies.get('jwtToken');
 | 
			
		||||
@ -33,7 +35,9 @@ const AuthResponse = () => {
 | 
			
		||||
      if (jwtToken) {
 | 
			
		||||
        auth.setToken(jwtToken, true);
 | 
			
		||||
        const requestUrl = getRequestUrl('users/me');
 | 
			
		||||
        const { data } = await request(requestUrl, { method: 'GET' });
 | 
			
		||||
        const {
 | 
			
		||||
          data: { data },
 | 
			
		||||
        } = await get(requestUrl);
 | 
			
		||||
 | 
			
		||||
        auth.setUserInfo(data, true);
 | 
			
		||||
 | 
			
		||||
@ -44,7 +48,7 @@ const AuthResponse = () => {
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      redirectToOops();
 | 
			
		||||
    }
 | 
			
		||||
  }, [push, redirectToOops]);
 | 
			
		||||
  }, [get, push, redirectToOops]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (authResponse === 'error') {
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import isEmpty from 'lodash/isEmpty';
 | 
			
		||||
import pickBy from 'lodash/pickBy';
 | 
			
		||||
import transform from 'lodash/transform';
 | 
			
		||||
 | 
			
		||||
import request from '../request';
 | 
			
		||||
import getFetchClient from '../getFetchClient';
 | 
			
		||||
 | 
			
		||||
const findMatchingPermissions = (userPermissions, permissions) => {
 | 
			
		||||
  return transform(
 | 
			
		||||
@ -47,13 +47,15 @@ const hasPermissions = async (userPermissions, permissions, signal) => {
 | 
			
		||||
    let hasPermission = false;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await request('/admin/permissions/check', {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        body: {
 | 
			
		||||
      const {
 | 
			
		||||
        data: { data },
 | 
			
		||||
      } = await getFetchClient().post(
 | 
			
		||||
        '/admin/permissions/check',
 | 
			
		||||
        {
 | 
			
		||||
          permissions: formatPermissionsForRequest(matchingPermissions),
 | 
			
		||||
        },
 | 
			
		||||
        signal,
 | 
			
		||||
      });
 | 
			
		||||
        { signal }
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      hasPermission = data.every((v) => v === true);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								packages/core/helper-plugin/src/utils/once.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/core/helper-plugin/src/utils/once.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
export const PREFIX = '[@strapi/helper-plugin]:';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @type {<TFunc extends (...args: any) => any>(fn: TFunc) => (...args: any[]) => void}
 | 
			
		||||
 */
 | 
			
		||||
export const once = (fn) => {
 | 
			
		||||
  const func = fn;
 | 
			
		||||
  let called = false;
 | 
			
		||||
 | 
			
		||||
  if (typeof func !== 'function') {
 | 
			
		||||
    throw new TypeError(`${PREFIX} once requires a function parameter`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (...args) => {
 | 
			
		||||
    if (!called) {
 | 
			
		||||
      func(...args);
 | 
			
		||||
      called = true;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import startsWith from 'lodash/startsWith';
 | 
			
		||||
import auth from '../auth';
 | 
			
		||||
 | 
			
		||||
import { once } from '../once';
 | 
			
		||||
/**
 | 
			
		||||
 * Parses the JSON returned by a network request
 | 
			
		||||
 *
 | 
			
		||||
@ -89,9 +89,13 @@ function serverRestartWatcher(response) {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const warnOnce = once(console.warn);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Requests a URL, returning a promise
 | 
			
		||||
 *
 | 
			
		||||
 * @deprecated use `useFetchClient` instead.
 | 
			
		||||
 *
 | 
			
		||||
 * @param  {string} url       The URL we want to request
 | 
			
		||||
 * @param  {object} [options] The options we want to pass to "fetch"
 | 
			
		||||
 *
 | 
			
		||||
@ -101,6 +105,10 @@ export default function request(...args) {
 | 
			
		||||
  let [url, options = {}, shouldWatchServerRestart, stringify = true, ...rest] = args;
 | 
			
		||||
  let noAuth;
 | 
			
		||||
 | 
			
		||||
  warnOnce(
 | 
			
		||||
    'The `request` function is deprecated and will be removed in the next major version. Please use `useFetchClient` instead.'
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    [{ noAuth }] = rest;
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
 | 
			
		||||
@ -1,31 +0,0 @@
 | 
			
		||||
import { request } from '@strapi/helper-plugin';
 | 
			
		||||
import pluginId from '../../pluginId';
 | 
			
		||||
 | 
			
		||||
const deleteDoc = ({ prefix, version }) => {
 | 
			
		||||
  return request(`${prefix}/deleteDoc/${version}`, { method: 'DELETE' });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const fetchDocumentationVersions = async (toggleNotification) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const data = await request(`/${pluginId}/getInfos`, { method: 'GET' });
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'warning',
 | 
			
		||||
      message: { id: 'notification.error' },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // FIXME
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const regenerateDoc = ({ prefix, version }) => {
 | 
			
		||||
  return request(`${prefix}/regenerateDoc`, { method: 'POST', body: { version } });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const updateSettings = ({ prefix, body }) =>
 | 
			
		||||
  request(`${prefix}/updateSettings`, { method: 'PUT', body });
 | 
			
		||||
 | 
			
		||||
export { deleteDoc, fetchDocumentationVersions, regenerateDoc, updateSettings };
 | 
			
		||||
@ -1,14 +1,28 @@
 | 
			
		||||
import { useQuery, useMutation, useQueryClient } from 'react-query';
 | 
			
		||||
import { useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { fetchDocumentationVersions, deleteDoc, regenerateDoc, updateSettings } from './api';
 | 
			
		||||
import { useNotification, useFetchClient } from '@strapi/helper-plugin';
 | 
			
		||||
import pluginId from '../../pluginId';
 | 
			
		||||
import getTrad from '../../utils/getTrad';
 | 
			
		||||
 | 
			
		||||
const useReactQuery = () => {
 | 
			
		||||
  const queryClient = useQueryClient();
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const { isLoading, data } = useQuery('get-documentation', () =>
 | 
			
		||||
    fetchDocumentationVersions(toggleNotification)
 | 
			
		||||
  );
 | 
			
		||||
  const { isLoading, data } = useQuery(['get-documentation', pluginId], async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await get(`/${pluginId}/getInfos`);
 | 
			
		||||
 | 
			
		||||
      return data;
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'warning',
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // FIXME
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const { del, post, put, get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const handleError = (err) => {
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
@ -25,20 +39,26 @@ const useReactQuery = () => {
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const deleteMutation = useMutation(deleteDoc, {
 | 
			
		||||
    onSuccess: () => handleSuccess('info', 'notification.delete.success'),
 | 
			
		||||
    onError: (error) => handleError(error),
 | 
			
		||||
  });
 | 
			
		||||
  const deleteMutation = useMutation(
 | 
			
		||||
    ({ prefix, version }) => del(`${prefix}/deleteDoc/${version}`),
 | 
			
		||||
    {
 | 
			
		||||
      onSuccess: () => handleSuccess('info', 'notification.delete.success'),
 | 
			
		||||
      onError: (error) => handleError(error),
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const submitMutation = useMutation(updateSettings, {
 | 
			
		||||
  const submitMutation = useMutation(({ prefix, body }) => put(`${prefix}/updateSettings`, body), {
 | 
			
		||||
    onSuccess: () => handleSuccess('success', 'notification.update.success'),
 | 
			
		||||
    onError: handleError,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const regenerateDocMutation = useMutation(regenerateDoc, {
 | 
			
		||||
    onSuccess: () => handleSuccess('info', 'notification.generate.success'),
 | 
			
		||||
    onError: (error) => handleError(error),
 | 
			
		||||
  });
 | 
			
		||||
  const regenerateDocMutation = useMutation(
 | 
			
		||||
    ({ prefix, version }) => post(`${prefix}/regenerateDoc`, { version }),
 | 
			
		||||
    {
 | 
			
		||||
      onSuccess: () => handleSuccess('info', 'notification.generate.success'),
 | 
			
		||||
      onError: (error) => handleError(error),
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return { data, isLoading, deleteMutation, submitMutation, regenerateDocMutation };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,39 +1,28 @@
 | 
			
		||||
import { useState } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useDispatch } from 'react-redux';
 | 
			
		||||
import get from 'lodash/get';
 | 
			
		||||
import { getTrad } from '../../utils';
 | 
			
		||||
import { ADD_LOCALE } from '../constants';
 | 
			
		||||
 | 
			
		||||
const addLocale = async ({ code, name, isDefault }, toggleNotification) => {
 | 
			
		||||
  const data = await request('/i18n/locales', {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    body: {
 | 
			
		||||
      name,
 | 
			
		||||
      code,
 | 
			
		||||
      isDefault,
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  toggleNotification({
 | 
			
		||||
    type: 'success',
 | 
			
		||||
    message: { id: getTrad('Settings.locales.modal.create.success') },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useAddLocale = () => {
 | 
			
		||||
  const [isLoading, setLoading] = useState(false);
 | 
			
		||||
  const dispatch = useDispatch();
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const { post } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const persistLocale = async (locale) => {
 | 
			
		||||
    setLoading(true);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const newLocale = await addLocale(locale, toggleNotification);
 | 
			
		||||
      dispatch({ type: ADD_LOCALE, newLocale });
 | 
			
		||||
      const { data } = await post('/i18n/locales', locale);
 | 
			
		||||
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'success',
 | 
			
		||||
        message: { id: getTrad('Settings.locales.modal.create.success') },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      dispatch({ type: ADD_LOCALE, newLocale: data });
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      const message = get(e, 'response.payload.message', null);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,32 +1,18 @@
 | 
			
		||||
import { useQuery } from 'react-query';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useNotifyAT } from '@strapi/design-system';
 | 
			
		||||
import { useIntl } from 'react-intl';
 | 
			
		||||
import { getTrad } from '../../utils';
 | 
			
		||||
 | 
			
		||||
const fetchDefaultLocalesList = async (toggleNotification) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const data = await request('/i18n/iso-locales', {
 | 
			
		||||
      method: 'GET',
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'warning',
 | 
			
		||||
      message: { id: 'notification.error' },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return [];
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useDefaultLocales = () => {
 | 
			
		||||
  const { formatMessage } = useIntl();
 | 
			
		||||
  const { notifyStatus } = useNotifyAT();
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const { isLoading, data } = useQuery('default-locales', () =>
 | 
			
		||||
    fetchDefaultLocalesList(toggleNotification).then((data) => {
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
  const { isLoading, data } = useQuery(['plugin-i18n', 'locales'], async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await get('/i18n/iso-locales');
 | 
			
		||||
 | 
			
		||||
      notifyStatus(
 | 
			
		||||
        formatMessage({
 | 
			
		||||
          id: getTrad('Settings.locales.modal.locales.loaded'),
 | 
			
		||||
@ -35,8 +21,15 @@ const useDefaultLocales = () => {
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      return data;
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'warning',
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return { defaultLocales: data, isLoading };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,43 +1,36 @@
 | 
			
		||||
import { useState } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useDispatch } from 'react-redux';
 | 
			
		||||
import { getTrad } from '../../utils';
 | 
			
		||||
import { DELETE_LOCALE } from '../constants';
 | 
			
		||||
 | 
			
		||||
const deleteLocale = async (id, toggleNotification) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const data = await request(`/i18n/locales/${id}`, {
 | 
			
		||||
      method: 'DELETE',
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'success',
 | 
			
		||||
      message: { id: getTrad('Settings.locales.modal.delete.success') },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'warning',
 | 
			
		||||
      message: { id: 'notification.error' },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return e;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useDeleteLocale = () => {
 | 
			
		||||
  const [isLoading, setLoading] = useState(false);
 | 
			
		||||
  const dispatch = useDispatch();
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
 | 
			
		||||
  const { del } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const removeLocale = async (id) => {
 | 
			
		||||
    setLoading(true);
 | 
			
		||||
    try {
 | 
			
		||||
      setLoading(true);
 | 
			
		||||
 | 
			
		||||
    await deleteLocale(id, toggleNotification);
 | 
			
		||||
      await del(`/i18n/locales/${id}`);
 | 
			
		||||
 | 
			
		||||
    dispatch({ type: DELETE_LOCALE, id });
 | 
			
		||||
    setLoading(false);
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'success',
 | 
			
		||||
        message: { id: getTrad('Settings.locales.modal.delete.success') },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      dispatch({ type: DELETE_LOCALE, id });
 | 
			
		||||
    } catch {
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'warning',
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
    } finally {
 | 
			
		||||
      setLoading(false);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return { isDeleting: isLoading, deleteLocale: removeLocale };
 | 
			
		||||
 | 
			
		||||
@ -1,44 +1,35 @@
 | 
			
		||||
import { useState } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useDispatch } from 'react-redux';
 | 
			
		||||
import { getTrad } from '../../utils';
 | 
			
		||||
import { UPDATE_LOCALE } from '../constants';
 | 
			
		||||
 | 
			
		||||
const editLocale = async (id, payload, toggleNotification) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const data = await request(`/i18n/locales/${id}`, {
 | 
			
		||||
      method: 'PUT',
 | 
			
		||||
      body: payload,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'success',
 | 
			
		||||
      message: { id: getTrad('Settings.locales.modal.edit.success') },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
  } catch {
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'warning',
 | 
			
		||||
      message: { id: 'notification.error' },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useEditLocale = () => {
 | 
			
		||||
  const [isLoading, setLoading] = useState(false);
 | 
			
		||||
  const dispatch = useDispatch();
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const { put } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  const modifyLocale = async (id, payload) => {
 | 
			
		||||
    setLoading(true);
 | 
			
		||||
    try {
 | 
			
		||||
      setLoading(true);
 | 
			
		||||
 | 
			
		||||
    const editedLocale = await editLocale(id, payload, toggleNotification);
 | 
			
		||||
      const { data } = await put(`/i18n/locales/${id}`, payload);
 | 
			
		||||
 | 
			
		||||
    dispatch({ type: UPDATE_LOCALE, editedLocale });
 | 
			
		||||
    setLoading(false);
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'success',
 | 
			
		||||
        message: { id: getTrad('Settings.locales.modal.edit.success') },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      dispatch({ type: UPDATE_LOCALE, editedLocale: data });
 | 
			
		||||
    } catch {
 | 
			
		||||
      toggleNotification({
 | 
			
		||||
        type: 'warning',
 | 
			
		||||
        message: { id: 'notification.error' },
 | 
			
		||||
      });
 | 
			
		||||
    } finally {
 | 
			
		||||
      setLoading(false);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return { isEditing: isLoading, editLocale: modifyLocale };
 | 
			
		||||
 | 
			
		||||
@ -1,36 +1,35 @@
 | 
			
		||||
import { useEffect } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useSelector, useDispatch } from 'react-redux';
 | 
			
		||||
import { RESOLVE_LOCALES } from '../constants';
 | 
			
		||||
 | 
			
		||||
const fetchLocalesList = async (toggleNotification) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const data = await request('/i18n/locales', {
 | 
			
		||||
      method: 'GET',
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    toggleNotification({
 | 
			
		||||
      type: 'warning',
 | 
			
		||||
      message: { id: 'notification.error' },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return e;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const useLocales = () => {
 | 
			
		||||
  const dispatch = useDispatch();
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const locales = useSelector((state) => state.i18n_locales.locales);
 | 
			
		||||
  const isLoading = useSelector((state) => state.i18n_locales.isLoading);
 | 
			
		||||
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    fetchLocalesList(toggleNotification).then((locales) =>
 | 
			
		||||
      dispatch({ type: RESOLVE_LOCALES, locales })
 | 
			
		||||
    );
 | 
			
		||||
  }, [dispatch, toggleNotification]);
 | 
			
		||||
    get('/i18n/locales')
 | 
			
		||||
      .then(({ data }) => dispatch({ type: RESOLVE_LOCALES, locales: data }))
 | 
			
		||||
      .catch((err) => {
 | 
			
		||||
        /**
 | 
			
		||||
         * TODO: this should be refactored.
 | 
			
		||||
         *
 | 
			
		||||
         * In fact it should be refactored to use react-query?
 | 
			
		||||
         */
 | 
			
		||||
        if ('code' in err && err?.code === 'ERR_CANCELED') {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        toggleNotification({
 | 
			
		||||
          type: 'warning',
 | 
			
		||||
          message: { id: 'notification.error' },
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
  }, [dispatch, get, toggleNotification]);
 | 
			
		||||
 | 
			
		||||
  return { locales, isLoading };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ import merge from 'lodash/merge';
 | 
			
		||||
import cloneDeep from 'lodash/cloneDeep';
 | 
			
		||||
import { parse } from 'qs';
 | 
			
		||||
import {
 | 
			
		||||
  request,
 | 
			
		||||
  getFetchClient,
 | 
			
		||||
  formatContentTypeData,
 | 
			
		||||
  contentManagementUtilRemoveFieldsFromData,
 | 
			
		||||
} from '@strapi/helper-plugin';
 | 
			
		||||
@ -44,10 +44,10 @@ const addCommonFieldsToInitialDataMiddleware =
 | 
			
		||||
      const defaultDataStructure = cloneDeep(contentTypeDataStructure);
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const requestURL = `/${pluginId}/content-manager/actions/get-non-localized-fields`;
 | 
			
		||||
        const body = { model: currentLayout.contentType.uid, id: relatedEntityId, locale };
 | 
			
		||||
 | 
			
		||||
        const data = await request(requestURL, { method: 'POST', body });
 | 
			
		||||
        const { data } = await getFetchClient().post(
 | 
			
		||||
          `/${pluginId}/content-manager/actions/get-non-localized-fields`,
 | 
			
		||||
          { model: currentLayout.contentType.uid, id: relatedEntityId, locale }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const { nonLocalizedFields, localizations } = data;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
// import { createStore, combineReducers } from 'redux';
 | 
			
		||||
// import { Provider } from 'react-redux';
 | 
			
		||||
import { request, useRBAC } from '@strapi/helper-plugin';
 | 
			
		||||
// import { request, useRBAC } from '@strapi/helper-plugin';
 | 
			
		||||
// import { fireEvent, render, screen, within, waitFor } from '@testing-library/react';
 | 
			
		||||
// import { ThemeProvider } from 'styled-components';
 | 
			
		||||
// import { QueryClient, QueryClientProvider } from 'react-query';
 | 
			
		||||
@ -81,27 +81,26 @@ jest.mock('react-intl', () => ({
 | 
			
		||||
 | 
			
		||||
describe('i18n settings page', () => {
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    request.mockImplementation(() =>
 | 
			
		||||
      Promise.resolve([
 | 
			
		||||
        {
 | 
			
		||||
          id: 1,
 | 
			
		||||
          name: 'French',
 | 
			
		||||
          code: 'fr-FR',
 | 
			
		||||
          isDefault: false,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          id: 2,
 | 
			
		||||
          name: 'English',
 | 
			
		||||
          code: 'en-US',
 | 
			
		||||
          isDefault: true,
 | 
			
		||||
        },
 | 
			
		||||
      ])
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    useRBAC.mockImplementation(() => ({
 | 
			
		||||
      isLoading: false,
 | 
			
		||||
      allowedActions: { canRead: true, canUpdate: true, canCreate: true, canDelete: true },
 | 
			
		||||
    }));
 | 
			
		||||
    // request.mockImplementation(() =>
 | 
			
		||||
    //   Promise.resolve([
 | 
			
		||||
    //     {
 | 
			
		||||
    //       id: 1,
 | 
			
		||||
    //       name: 'French',
 | 
			
		||||
    //       code: 'fr-FR',
 | 
			
		||||
    //       isDefault: false,
 | 
			
		||||
    //     },
 | 
			
		||||
    //     {
 | 
			
		||||
    //       id: 2,
 | 
			
		||||
    //       name: 'English',
 | 
			
		||||
    //       code: 'en-US',
 | 
			
		||||
    //       isDefault: true,
 | 
			
		||||
    //     },
 | 
			
		||||
    //   ])
 | 
			
		||||
    // );
 | 
			
		||||
    // useRBAC.mockImplementation(() => ({
 | 
			
		||||
    //   isLoading: false,
 | 
			
		||||
    //   allowedActions: { canRead: true, canUpdate: true, canCreate: true, canDelete: true },
 | 
			
		||||
    // }));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  afterEach(() => {
 | 
			
		||||
@ -583,14 +582,14 @@ describe('i18n settings page', () => {
 | 
			
		||||
 | 
			
		||||
  describe('create', () => {
 | 
			
		||||
    beforeEach(() => {
 | 
			
		||||
      request.mockImplementation((url) =>
 | 
			
		||||
        url.includes('/i18n/locales')
 | 
			
		||||
          ? Promise.resolve([])
 | 
			
		||||
          : Promise.resolve([
 | 
			
		||||
              { code: 'fr-FR', name: 'Francais' },
 | 
			
		||||
              { code: 'en-EN', name: 'English' },
 | 
			
		||||
            ])
 | 
			
		||||
      );
 | 
			
		||||
      // request.mockImplementation((url) =>
 | 
			
		||||
      //   url.includes('/i18n/locales')
 | 
			
		||||
      //     ? Promise.resolve([])
 | 
			
		||||
      //     : Promise.resolve([
 | 
			
		||||
      //         { code: 'fr-FR', name: 'Francais' },
 | 
			
		||||
      //         { code: 'en-EN', name: 'English' },
 | 
			
		||||
      //       ])
 | 
			
		||||
      // );
 | 
			
		||||
    });
 | 
			
		||||
    test.todo('shows the default create modal layout');
 | 
			
		||||
    // it('shows the default create modal layout', async () => {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { useCallback, useEffect, useReducer, useRef } from 'react';
 | 
			
		||||
import { useRBAC, request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useRBAC, useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { getRequestURL } from '../../utils';
 | 
			
		||||
import reducer, { initialState } from './reducer';
 | 
			
		||||
 | 
			
		||||
@ -9,8 +9,7 @@ const useUserForm = (endPoint, permissions) => {
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
  const isMounted = useRef(true);
 | 
			
		||||
 | 
			
		||||
  const abortController = new AbortController();
 | 
			
		||||
  const { signal } = abortController;
 | 
			
		||||
  const { get } = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getData = async () => {
 | 
			
		||||
@ -19,7 +18,7 @@ const useUserForm = (endPoint, permissions) => {
 | 
			
		||||
          type: 'GET_DATA',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const data = await request(getRequestURL(endPoint), { method: 'GET', signal });
 | 
			
		||||
        const { data } = await get(getRequestURL(endPoint));
 | 
			
		||||
 | 
			
		||||
        dispatch({
 | 
			
		||||
          type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
@ -45,11 +44,9 @@ const useUserForm = (endPoint, permissions) => {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      abortController.abort();
 | 
			
		||||
      isMounted.current = false;
 | 
			
		||||
    };
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [isLoadingForPermissions, endPoint]);
 | 
			
		||||
  }, [isLoadingForPermissions, endPoint, get, toggleNotification]);
 | 
			
		||||
 | 
			
		||||
  const dispatchSubmitSucceeded = useCallback((data) => {
 | 
			
		||||
    dispatch({
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { useEffect, useReducer, useRef } from 'react';
 | 
			
		||||
import { request, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import { useCallback, useEffect, useReducer, useRef } from 'react';
 | 
			
		||||
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
 | 
			
		||||
import get from 'lodash/get';
 | 
			
		||||
import init from './init';
 | 
			
		||||
import pluginId from '../../pluginId';
 | 
			
		||||
@ -12,28 +12,17 @@ const useRolesList = (shouldFetchData = true) => {
 | 
			
		||||
  const toggleNotification = useNotification();
 | 
			
		||||
 | 
			
		||||
  const isMounted = useRef(true);
 | 
			
		||||
  const abortController = new AbortController();
 | 
			
		||||
  const { signal } = abortController;
 | 
			
		||||
  const fetchClient = useFetchClient();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (shouldFetchData) {
 | 
			
		||||
      fetchRolesList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      abortController.abort();
 | 
			
		||||
      isMounted.current = false;
 | 
			
		||||
    };
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [shouldFetchData]);
 | 
			
		||||
 | 
			
		||||
  const fetchRolesList = async () => {
 | 
			
		||||
  const fetchRolesList = useCallback(async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const { roles } = await request(`/${pluginId}/roles`, { method: 'GET', signal });
 | 
			
		||||
      const {
 | 
			
		||||
        data: { roles },
 | 
			
		||||
      } = await fetchClient.get(`/${pluginId}/roles`);
 | 
			
		||||
 | 
			
		||||
      dispatch({
 | 
			
		||||
        type: 'GET_DATA_SUCCEEDED',
 | 
			
		||||
@ -55,7 +44,17 @@ const useRolesList = (shouldFetchData = true) => {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }, [fetchClient, toggleNotification]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (shouldFetchData) {
 | 
			
		||||
      fetchRolesList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      isMounted.current = false;
 | 
			
		||||
    };
 | 
			
		||||
  }, [shouldFetchData, fetchRolesList]);
 | 
			
		||||
 | 
			
		||||
  return { roles, isLoading, getData: fetchRolesList };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -280,6 +280,12 @@ module.exports = {
 | 
			
		||||
        'confirmationToken',
 | 
			
		||||
        'resetPasswordToken',
 | 
			
		||||
        'provider',
 | 
			
		||||
        'id',
 | 
			
		||||
        'createdAt',
 | 
			
		||||
        'updatedAt',
 | 
			
		||||
        'createdBy',
 | 
			
		||||
        'updatedBy',
 | 
			
		||||
        'role',
 | 
			
		||||
      ]),
 | 
			
		||||
      provider: 'local',
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,12 @@ module.exports = {
 | 
			
		||||
            message:
 | 
			
		||||
              "'Stack' has been deprecated. Please import 'Flex' from '@strapi/design-system' instead.",
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: '@strapi/helper-plugin',
 | 
			
		||||
            importNames: ['request'],
 | 
			
		||||
            message:
 | 
			
		||||
              "'request' has been deprecated. Please import 'useFetchClient' from '@strapi/helper-plugin' instead.",
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: 'lodash',
 | 
			
		||||
            message: 'Please use import [method] from lodash/[method]',
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user