EN · DE · RU · FR · ES

#2698: FormPage.jsx

projectforge-webapp/src/containers/page/form/FormPage.jsx Typ: JavaScript/React · Rolle: Seite · Quelle: projectforge-webapp/src/containers/page/form/FormPage.jsx 191 Zeilen · 175 Code · 4 Kommentare · 12 leer
React-Formularkomponente zur Bearbeitung von Entitäten, Validierung, Feldlayout und Senden/Abbrechen-Aktionen.

Codestruktur

Verwendete Hooks: Dispatch, Params, Selector, Location, SearchParams, Effect, Memo

Importe von: ../../../actions, ../../../components/base/dynamicLayout, ../../../components/base/page/edit/TabNavigation, ../../../components/design, ../../../components/design/loading-container, ../../../utilities/layout, ../../../utilities/rest, ../../ProjectForge.module.scss, ./history, prop-types, react, react-redux, react-router

Hat PropTypes für: FormPage

Verwendet CSS-Module für das Styling.

Quellcode (gekürzt)

import PropTypes from 'prop-types';
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation, useParams, useSearchParams } from 'react-router';
import {
    callAction,
    loadFormPage,
    setCurrentData,
    setCurrentVariables,
    switchFromCurrentCategory,
} from '../../../actions';
import DynamicLayout from '../../../components/base/dynamicLayout';
import TabNavigation from '../../../components/base/page/edit/TabNavigation';
import { Alert, Container, TabContent, TabPane } from '../../../components/design';
import LoadingContainer from '../../../components/design/loading-container';
import { getTranslation } from '../../../utilities/layout';
import { getServiceURL } from '../../../utilities/rest';
import style from '../../ProjectForge.module.scss';
import FormHistory from './history';

function FormPage(
    {
        isPublic = false,
    },
) {
    const dispatch = useDispatch();
    const onCallAction = (...args) => dispatch(callAction(...args));
    const onCategorySwitch = (...args) => dispatch(switchFromCurrentCategory(...args));
    const onDataChange = (...args) => dispatch(setCurrentData(...args));
    const onNewFormPage = (...args) => dispatch(loadFormPage(...args));
    const onVariablesChange = (...args) => dispatch(setCurrentVariables(...args));
    const {
        type,
        category: currentCategory,
        id,
        tab,
    } = useParams();
    const category = useSelector(({ form }) => form.categories[currentCategory]) || {};
    const {
        data,
        isFetching,
        ui,
        validationErrors,
        variables,
    } = category;
    const location = useLocation();
    const [searchParams] = useSearchParams();
    const { userAccess } = ui || {};

    React.useEffect(
        () => {
            // Prüft, ob es sich um eine programmatische Navigation mit noReload-Flag handelt
            // Browser-Neuladungen sollten immer frische Daten abrufen
            const isNoReloadNavigation = location.state
                && location.state.noReload
                && window.performance
                && window.performance.navigation.type !== 1; // 1 = TYPE_RELOAD

            if (isNoReloadNavigation) {
                onCategorySwitch(
                    currentCategory,
                    location.state.newVariables || {},
                    location.state.merge,
                );
            } else {
                onNewFormPage(
                    currentCategory,
                    id,
                    getServiceURL(
                        `${isPublic ? '/rsPublic/' : ''}${currentCategory}/${type || 'dynamic'}`,
                        {
                            ...Object.fromEntries(searchParams.entries()),
                            id,
                        },
                    ),
                    location.state,
                );
            }
        },
        [
            currentCategory,
            id,
            location.state && location.state.noReload,
            location.state && location.state.newVariables,
        ],
    );

    const globalValidation = React.useMemo(() => {
        if (validationErrors === undefined) {
            return null;
        }
        const globalErrors = validationErrors.filter((entry) => entry.fieldId === undefined);

        if (globalErrors.length === 0) {
            return null;
        }

        return (
            <Alert color="danger">
                <ul>
                    {globalErrors.map(({ message, messageId }) => (
                        <li key={`form-page-global-validation-${messageId}`}>
                            {message}
                        </li>
                    ))}
                </ul>
            </Alert>
        );
    }, [validationErrors]);

    if (ui === undefined || ui.title === undefined) {
        return <LoadingContainer loading />;
    }

    // Basis-URL aus aktueller Position erstellen, um verschachtelte Routen zu erhalten (z. B. /calendar/)
    // /history-Suffix entfernen, falls vorhanden, und Abfrageparameter entfernen
    const formBaseUrl = location.pathname.replace(/\/history$/, '').split('?')[0];
    const tabs = [
        {
            id: 'form',
// ... (gekürzt, insgesamt 191 Zeilen)

Git-Verlauf

bf988bc6d 43 npm-Schwachstellen beseitigt: react-scripts→Vite, ESLint 9, Abhängigkeitsbereinigung, Fehlerbehebungen
d61a30129 FormPage.jsx: Endlos-Ladespinner behoben.
05bcb43b9 Behandlung von Verlaufseinträgen in modalen Dialogen korrigiert.
f02617502 HistoryEntry.jsx: diffSummary, Benutzerkommentar bearbeiten wird nur angezeigt, wenn verfügbar.
3490f27f1 Kalender- und Zeiterfassungsseite korrigiert