feat: port stroy-bot-project-assigner as resources page
Add the "resources" section (?page=resources&projectId=): professions and companies assigned to a project, with the same lists, fields, texts and optimistic add/remove with rollback as the legacy web part. PnPjs is replaced by SharePoint REST through the app's IHttpClient so the bundle needs no new dependency: the same $select/$expand/$filter, PnP paging replaced by following odata.nextLink, adds as POST to items with the same body, deletes as POST with X-HTTP-Method DELETE and IF-MATCH *. Known legacy edge cases (temporary negative id) are kept and listed in the checklist. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import * as React from 'react';
|
||||
import { Button } from '@tnsu/ui-kit';
|
||||
import { IAssignedResource } from './resourcesTypes';
|
||||
import { RESOURCES_TEXTS } from './texts';
|
||||
import styles from './ResourcesPage.module.scss';
|
||||
|
||||
const TEXTS = RESOURCES_TEXTS.assigned;
|
||||
|
||||
interface Props {
|
||||
items: IAssignedResource[];
|
||||
onRemove: (itemId: number) => void;
|
||||
}
|
||||
|
||||
/** Правая колонка «Привязаны к проекту». */
|
||||
export const AssignedPanel: React.FC<Props> = ({ items, onRemove }) => (
|
||||
<div className={styles.panelColumn}>
|
||||
<div className={styles.panelTitle}>{TEXTS.title}</div>
|
||||
{items.length === 0 && <div className={styles.emptyMsg}>{TEXTS.empty}</div>}
|
||||
{items.map((item) => (
|
||||
<div key={item.id} className={styles.itemRow}>
|
||||
<span className={styles.itemName}>{item.title}</span>
|
||||
<Button
|
||||
variant="danger"
|
||||
size="sm"
|
||||
title={TEXTS.remove}
|
||||
aria-label={TEXTS.remove}
|
||||
onClick={() => onRemove(item.id)}
|
||||
>
|
||||
−
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
Reference in New Issue
Block a user