fix: changed resolve endpoint contract form get to post

This commit is contained in:
Тимур Городецкий
2026-08-03 14:37:42 +05:00
parent 788e046ebe
commit e6203e7093
22 changed files with 512 additions and 22 deletions
@@ -0,0 +1,16 @@
import * as React from 'react';
// Режим формы «только чтение». Проставляется один раз оборачиванием
// (<FormModeProvider readOnly>...), а поля-примитивы сами его подхватывают —
// не нужно тащить readOnly через каждую секцию и каждое поле.
const FormModeContext = React.createContext<boolean>(false);
export const FormModeProvider: React.FC<{ readOnly: boolean; children: React.ReactNode }> = ({
readOnly,
children
}) => <FormModeContext.Provider value={readOnly}>{children}</FormModeContext.Provider>;
/** true, если форма отрисовывается в режиме «только чтение». */
export function useFormReadOnly(): boolean {
return React.useContext(FormModeContext);
}
@@ -2,6 +2,7 @@ import * as React from 'react';
import { PeoplePicker, PrincipalType } from '@pnp/spfx-controls-react/lib/PeoplePicker';
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { buildPickerContext, pickedLogin, IPickedUser } from './pickerContext';
import { useFormReadOnly } from '../FormMode';
interface IPeopleFieldProps {
context: WebPartContext;
@@ -9,10 +10,14 @@ interface IPeopleFieldProps {
value: string;
onChange: (login: string) => void;
placeholder?: string;
/** Только чтение (режим согласующего). */
readOnly?: boolean;
}
/** Выбор ОДНОГО сотрудника. Обёртка над PeoplePicker из @pnp/spfx-controls-react. */
export const PeopleField: React.FC<IPeopleFieldProps> = ({ context, value, onChange, placeholder }) => {
export const PeopleField: React.FC<IPeopleFieldProps> = ({ context, value, onChange, placeholder, readOnly }) => {
const contextReadOnly = useFormReadOnly();
const effectiveReadOnly = readOnly ?? contextReadOnly;
const handleChange = (items: IPickedUser[]): void => {
const first = items && items.length > 0 ? items[0] : undefined;
onChange(first ? pickedLogin(first) : '');
@@ -26,6 +31,7 @@ export const PeopleField: React.FC<IPeopleFieldProps> = ({ context, value, onCha
defaultSelectedUsers={value ? [value] : []}
resolveDelay={300}
ensureUser
disabled={effectiveReadOnly}
placeholder={placeholder}
onChange={handleChange}
/>
@@ -2,6 +2,7 @@ import * as React from 'react';
import { PeoplePicker, PrincipalType } from '@pnp/spfx-controls-react/lib/PeoplePicker';
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { buildPickerContext, pickedLogin, IPickedUser } from './pickerContext';
import { useFormReadOnly } from '../FormMode';
interface IPeopleFieldMultiProps {
context: WebPartContext;
@@ -11,6 +12,8 @@ interface IPeopleFieldMultiProps {
placeholder?: string;
/** Максимум выбираемых людей. */
limit?: number;
/** Только чтение (режим согласующего). */
readOnly?: boolean;
}
/** Выбор НЕСКОЛЬКИХ сотрудников (для колонок «Пользователь или группа (несколько)»). */
@@ -19,8 +22,11 @@ export const PeopleFieldMulti: React.FC<IPeopleFieldMultiProps> = ({
value,
onChange,
placeholder,
limit = 10
limit = 10,
readOnly
}) => {
const contextReadOnly = useFormReadOnly();
const effectiveReadOnly = readOnly ?? contextReadOnly;
const handleChange = (items: IPickedUser[]): void => {
const logins = (items || []).map(pickedLogin).filter((login) => login.length > 0);
onChange(logins);
@@ -34,6 +40,7 @@ export const PeopleFieldMulti: React.FC<IPeopleFieldMultiProps> = ({
defaultSelectedUsers={value}
resolveDelay={300}
ensureUser
disabled={effectiveReadOnly}
placeholder={placeholder}
onChange={handleChange}
/>
@@ -1,5 +1,6 @@
import * as React from 'react';
import styles from './Select.module.scss';
import { useFormReadOnly } from '../FormMode';
export interface ISelectOption {
value: string;
@@ -12,15 +13,20 @@ interface ISelectProps {
onChange: (value: string) => void;
options: ISelectOption[];
placeholder?: string;
/** Только чтение (режим согласующего). У select нет readonly — используем disabled. */
readOnly?: boolean;
}
/** Выпадающий список (SharePoint Choice). */
export const Select: React.FC<ISelectProps> = ({ id, value, onChange, options, placeholder }) => {
export const Select: React.FC<ISelectProps> = ({ id, value, onChange, options, placeholder, readOnly }) => {
const contextReadOnly = useFormReadOnly();
const effectiveReadOnly = readOnly ?? contextReadOnly;
return (
<select
id={id}
className={styles.select}
value={value}
disabled={effectiveReadOnly}
onChange={(e) => onChange(e.target.value)}
>
{placeholder && <option value="">{placeholder}</option>}
@@ -1,5 +1,6 @@
import * as React from 'react';
import styles from './TextArea.module.scss';
import { useFormReadOnly } from '../FormMode';
interface ITextAreaProps {
id?: string;
@@ -7,10 +8,14 @@ interface ITextAreaProps {
onChange: (value: string) => void;
placeholder?: string;
rows?: number;
/** Только чтение (режим согласующего). */
readOnly?: boolean;
}
/** Многострочный ввод (SharePoint Note). */
export const TextArea: React.FC<ITextAreaProps> = ({ id, value, onChange, placeholder, rows = 3 }) => {
export const TextArea: React.FC<ITextAreaProps> = ({ id, value, onChange, placeholder, rows = 3, readOnly }) => {
const contextReadOnly = useFormReadOnly();
const effectiveReadOnly = readOnly ?? contextReadOnly;
return (
<textarea
id={id}
@@ -18,6 +23,7 @@ export const TextArea: React.FC<ITextAreaProps> = ({ id, value, onChange, placeh
value={value}
placeholder={placeholder}
rows={rows}
readOnly={effectiveReadOnly}
onChange={(e) => onChange(e.target.value)}
/>
);
@@ -1,5 +1,6 @@
import * as React from 'react';
import styles from './TextInput.module.scss';
import { useFormReadOnly } from '../FormMode';
type InputType = 'text' | 'number' | 'date';
@@ -9,10 +10,21 @@ interface ITextInputProps {
value: string;
onChange: (value: string) => void;
placeholder?: string;
/** Только чтение (режим согласующего). */
readOnly?: boolean;
}
/** Однострочный ввод. type='number'|'date' — для числовых полей и дат. */
export const TextInput: React.FC<ITextInputProps> = ({ id, type = 'text', value, onChange, placeholder }) => {
export const TextInput: React.FC<ITextInputProps> = ({
id,
type = 'text',
value,
onChange,
placeholder,
readOnly
}) => {
const contextReadOnly = useFormReadOnly();
const effectiveReadOnly = readOnly ?? contextReadOnly;
return (
<input
id={id}
@@ -20,6 +32,7 @@ export const TextInput: React.FC<ITextInputProps> = ({ id, type = 'text', value,
type={type}
value={value}
placeholder={placeholder}
readOnly={effectiveReadOnly}
onChange={(e) => onChange(e.target.value)}
/>
);
@@ -1,5 +1,6 @@
import * as React from 'react';
import styles from './Toggle.module.scss';
import { useFormReadOnly } from '../FormMode';
interface IToggleProps {
id?: string;
@@ -7,10 +8,14 @@ interface IToggleProps {
onChange: (checked: boolean) => void;
/** Подпись справа от переключателя (да/нет-поля). */
onLabel?: string;
/** Только чтение (режим согласующего). */
readOnly?: boolean;
}
/** Переключатель да/нет (SharePoint Boolean). */
export const Toggle: React.FC<IToggleProps> = ({ id, checked, onChange, onLabel }) => {
export const Toggle: React.FC<IToggleProps> = ({ id, checked, onChange, onLabel, readOnly }) => {
const contextReadOnly = useFormReadOnly();
const effectiveReadOnly = readOnly ?? contextReadOnly;
return (
<label className={styles.wrap}>
<input
@@ -18,6 +23,7 @@ export const Toggle: React.FC<IToggleProps> = ({ id, checked, onChange, onLabel
type="checkbox"
className={styles.input}
checked={checked}
disabled={effectiveReadOnly}
onChange={(e) => onChange(e.target.checked)}
/>
<span className={styles.track}>
@@ -13,4 +13,5 @@ export { CollapseSection } from './CollapseSection/CollapseSection';
export { FormActions } from './FormActions/FormActions';
export { PeopleField } from './PeopleField/PeopleField';
export { PeopleFieldMulti } from './PeopleField/PeopleFieldMulti';
export { FormModeProvider, useFormReadOnly } from './FormMode';
export { Icon } from './Icon/Icon';