merge branch
Tests / frontend-test (push) Successful in 1m10s

This commit is contained in:
Тимур Городецкий
2026-08-26 16:03:49 +05:00
40 changed files with 2462 additions and 47 deletions
@@ -0,0 +1,30 @@
@import '../../../../../styles/design-tokens';
// Read-only «карточка» со ссылкой — те же радиус/паддинг/приглушённый фон, что у
// OrganizationField (сигнал «подставлено автоматически, не редактируется»),
// отличается только тем, что содержимое кликабельно.
.box {
box-sizing: border-box;
padding: 11px 13px;
border: 1px solid $gray-200;
border-radius: $r-sm;
background: $gray-50;
font-family: $font-sans;
font-size: 13.5px;
color: $gray-700;
}
.link {
display: inline-flex;
align-items: center;
gap: $sp-2;
color: $navy-700;
text-decoration: none;
transition: color .18s;
&:hover,
&:focus {
color: $gold-600;
text-decoration: underline;
}
}
@@ -0,0 +1,52 @@
import * as React from 'react';
import styles from './LinkField.module.scss';
import { FormField, Icon } from '@tnsu/ui-kit';
import { navigateToRequestLink } from '../../routing';
interface ILinkFieldProps {
label: string;
/** Адрес. Пусто — поле не рендерится вовсе (см. ниже). */
url: string;
/** Текст ссылки. По умолчанию — сам адрес. */
text?: string;
}
/**
* Поле-ссылка: read-only, кликабельное, руками не редактируется.
*
* Пустой url — ничего не рендерим (а не пустую рамку): такие поля появляются
* только когда связь уже есть (напр. ClearanceUrl заявления на увольнение
* заполняется автосозданием обходного листа), и до этого момента их нет смысла
* показывать.
*
* Открывается в ТОЙ ЖЕ вкладке, и если ссылка ведёт на заявку этого же портала —
* вообще без перезагрузки страницы (navigateToRequestLink: та же страница, другие
* rp-параметры). href при этом настоящий, а не «#»: ссылку можно скопировать,
* открыть в новой вкладке через Ctrl/⌘+клик или среднюю кнопку — такие клики
* перехват намеренно пропускает.
*/
export const LinkField: React.FC<ILinkFieldProps> = ({ label, url, text }) => {
if (!url) return null;
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>): void => {
// Клик с модификатором или не левой кнопкой — осознанное «открыть отдельно»,
// отдаём браузеру. Иначе пробуем перейти внутри портала.
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
return;
}
if (navigateToRequestLink(url)) {
e.preventDefault();
}
};
return (
<FormField label={label} full>
<div className={styles.box}>
<a className={styles.link} href={url} onClick={handleClick}>
<span>{text || url}</span>
<Icon name="chevron-right" size="sm" />
</a>
</div>
</FormField>
);
};
@@ -41,6 +41,7 @@ export { PeopleFieldMulti } from './PeopleField/PeopleFieldMulti';
export { OrganizationField } from './OrganizationField/OrganizationField';
export { PrintOrgSelect } from './PrintOrgSelect/PrintOrgSelect';
export { OrgLetterhead } from './OrgLetterhead/OrgLetterhead';
export { LinkField } from './LinkField/LinkField';
export { ErrorOverlay } from './ErrorOverlay/ErrorOverlay';
export { SubmitActions } from './SubmitActions/SubmitActions';
export { InitiatorLine } from './InitiatorLine/InitiatorLine';