This commit is contained in:
Flatlogic Bot 2026-05-11 12:57:58 +00:00
parent 97439eda85
commit b073dd491e
38 changed files with 540 additions and 659 deletions

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'ToolName', headerName: 'Tool Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -58,7 +58,7 @@ export const loadColumns = async (
{ {
field: 'tool_type', field: 'tool_type',
headerName: 'ToolType', headerName: 'Tool Type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -95,7 +95,7 @@ export const loadColumns = async (
{ {
field: 'deployment_model', field: 'deployment_model',
headerName: 'DeploymentModel', headerName: 'Deployment Model',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -110,7 +110,7 @@ export const loadColumns = async (
{ {
field: 'approval_status', field: 'approval_status',
headerName: 'ApprovalStatus', headerName: 'Approval Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -125,7 +125,7 @@ export const loadColumns = async (
{ {
field: 'supports_sso', field: 'supports_sso',
headerName: 'SupportsSSO', headerName: 'Supports SSO',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -141,7 +141,7 @@ export const loadColumns = async (
{ {
field: 'supports_audit_logs', field: 'supports_audit_logs',
headerName: 'SupportsAuditLogs', headerName: 'Supports Audit Logs',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -157,7 +157,7 @@ export const loadColumns = async (
{ {
field: 'soc2_status', field: 'soc2_status',
headerName: 'SOC2Status', headerName: 'SOC2 Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -172,7 +172,7 @@ export const loadColumns = async (
{ {
field: 'data_retention_policy', field: 'data_retention_policy',
headerName: 'DataRetentionPolicy', headerName: 'Data Retention Policy',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -187,7 +187,7 @@ export const loadColumns = async (
{ {
field: 'training_on_client_data_policy', field: 'training_on_client_data_policy',
headerName: 'TrainingOnClientDataPolicy', headerName: 'Training On Client Data Policy',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -202,7 +202,7 @@ export const loadColumns = async (
{ {
field: 'data_residency', field: 'data_residency',
headerName: 'DataResidency', headerName: 'Data Residency',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -217,7 +217,7 @@ export const loadColumns = async (
{ {
field: 'deletion_policy', field: 'deletion_policy',
headerName: 'DeletionPolicy', headerName: 'Deletion Policy',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -232,7 +232,7 @@ export const loadColumns = async (
{ {
field: 'security_posture_summary', field: 'security_posture_summary',
headerName: 'SecurityPostureSummary', headerName: 'Security Posture Summary',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -247,7 +247,7 @@ export const loadColumns = async (
{ {
field: 'security_documents', field: 'security_documents',
headerName: 'SecurityDocuments', headerName: 'Security Documents',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -273,7 +273,7 @@ export const loadColumns = async (
{ {
field: 'monthly_cost', field: 'monthly_cost',
headerName: 'MonthlyCost', headerName: 'Monthly Cost',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'use_case', field: 'use_case',
headerName: 'AIUseCase', headerName: 'AI Use Case',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -65,7 +65,7 @@ export const loadColumns = async (
{ {
field: 'step_type', field: 'step_type',
headerName: 'StepType', headerName: 'Step Type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -80,7 +80,7 @@ export const loadColumns = async (
{ {
field: 'assigned_reviewer', field: 'assigned_reviewer',
headerName: 'AssignedReviewer', headerName: 'Assigned Reviewer',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -132,7 +132,7 @@ export const loadColumns = async (
{ {
field: 'assigned_at', field: 'assigned_at',
headerName: 'AssignedAt', headerName: 'Assigned At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -150,7 +150,7 @@ export const loadColumns = async (
{ {
field: 'decided_at', field: 'decided_at',
headerName: 'DecidedAt', headerName: 'Decided At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -168,7 +168,7 @@ export const loadColumns = async (
{ {
field: 'step_order', field: 'step_order',
headerName: 'StepOrder', headerName: 'Step Order',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'label', field: 'label',
headerName: 'ClassificationLabel', headerName: 'Classification Label',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -58,7 +58,7 @@ export const loadColumns = async (
{ {
field: 'level', field: 'level',
headerName: 'SensitivityLevel', headerName: 'Sensitivity Level',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -88,7 +88,7 @@ export const loadColumns = async (
{ {
field: 'risk_notes', field: 'risk_notes',
headerName: 'RiskNotes', headerName: 'Risk Notes',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -103,7 +103,7 @@ export const loadColumns = async (
{ {
field: 'required_human_review_level', field: 'required_human_review_level',
headerName: 'RequiredHumanReviewLevel', headerName: 'Required Human Review Level',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -118,7 +118,7 @@ export const loadColumns = async (
{ {
field: 'requires_client_notice', field: 'requires_client_notice',
headerName: 'RequiresClientNotice', headerName: 'Requires Client Notice',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'ChecklistName', headerName: 'Checklist Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -88,7 +88,7 @@ export const loadColumns = async (
{ {
field: 'practice_group', field: 'practice_group',
headerName: 'PracticeGroupScope', headerName: 'Practice Group Scope',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -110,7 +110,7 @@ export const loadColumns = async (
{ {
field: 'data_classification', field: 'data_classification',
headerName: 'DataClassificationScope', headerName: 'Data Classification Scope',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -132,7 +132,7 @@ export const loadColumns = async (
{ {
field: 'required_reviewer_role', field: 'required_reviewer_role',
headerName: 'RequiredReviewerRole', headerName: 'Required Reviewer Role',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'IntegrationName', headerName: 'Integration Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -104,7 +104,7 @@ export const loadColumns = async (
{ {
field: 'configuration_notes', field: 'configuration_notes',
headerName: 'ConfigurationNotes', headerName: 'Configuration Notes',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -119,7 +119,7 @@ export const loadColumns = async (
{ {
field: 'configuration_files', field: 'configuration_files',
headerName: 'ConfigurationFiles', headerName: 'Configuration Files',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -1,135 +1,3 @@
import React from 'react'; import ListMatter_types from './ListMatter_types';
import ImageField from '../ImageField';
import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import dataFormatter from '../../helpers/dataFormatter';
import { Pagination } from '../Pagination';
import {saveFile} from "../../helpers/fileSaver";
import LoadingSpinner from "../LoadingSpinner";
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions"; export default ListMatter_types;
type Props = {
matter_types: any[];
loading: boolean;
onDelete: (id: string) => void;
currentPage: number;
numPages: number;
onPageChange: (page: number) => void;
};
const CardMatter_types = ({
matter_types,
loading,
onDelete,
currentPage,
numPages,
onPageChange,
}: Props) => {
const asideScrollbarsStyle = useAppSelector(
(state) => state.style.asideScrollbarsStyle,
);
const bgColor = useAppSelector((state) => state.style.cardsColor);
const darkMode = useAppSelector((state) => state.style.darkMode);
const corners = useAppSelector((state) => state.style.corners);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_MATTER_TYPES')
return (
<div className={'p-4'}>
{loading && <LoadingSpinner />}
<ul
role='list'
className='grid grid-cols-1 gap-x-6 gap-y-8 lg:grid-cols-3 2xl:grid-cols-4 xl:gap-x-8'
>
{!loading && matter_types.map((item, index) => (
<li
key={item.id}
className={`overflow-hidden ${corners !== 'rounded-full'? corners : 'rounded-3xl'} border ${focusRing} border-gray-200 dark:border-dark-700 ${
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
}`}
>
<div className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}>
<Link href={`/matter_types/matter_types-view/?id=${item.id}`} className='text-lg font-bold leading-6 line-clamp-1'>
{item.name}
</Link>
<div className='ml-auto '>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/matter_types/matter_types-edit/?id=${item.id}`}
pathView={`/matter_types/matter_types-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</div>
<dl className='divide-y divide-stone-300 dark:divide-dark-700 px-6 py-4 text-sm leading-6 h-64 overflow-y-auto'>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>MatterType</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ item.name }
</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Description</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ item.description }
</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Active</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ dataFormatter.booleanFormatter(item.is_active) }
</div>
</dd>
</div>
</dl>
</li>
))}
{!loading && matter_types.length === 0 && (
<div className='col-span-full flex items-center justify-center h-40'>
<p className=''>No data to display</p>
</div>
)}
</ul>
<div className={'flex items-center justify-center my-6'}>
<Pagination
currentPage={currentPage}
numPages={numPages}
setCurrentPage={onPageChange}
/>
</div>
</div>
);
};
export default CardMatter_types;

View File

@ -1,16 +1,10 @@
import React from 'react'; import React from 'react';
import CardBox from '../CardBox';
import ImageField from '../ImageField';
import dataFormatter from '../../helpers/dataFormatter';
import {saveFile} from "../../helpers/fileSaver";
import ListActionsPopover from "../ListActionsPopover";
import {useAppSelector} from "../../stores/hooks";
import {Pagination} from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import Link from 'next/link'; import Link from 'next/link';
import ListActionsPopover from "../ListActionsPopover";
import {hasPermission} from "../../helpers/userPermissions"; import { useAppSelector } from "../../stores/hooks";
import { Pagination } from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import { hasPermission } from "../../helpers/userPermissions";
type Props = { type Props = {
matter_types: any[]; matter_types: any[];
@ -21,84 +15,111 @@ type Props = {
onPageChange: (page: number) => void; onPageChange: (page: number) => void;
}; };
const ListMatter_types = ({ matter_types, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { const getInitials = (name?: string) => {
if (!name) {
const currentUser = useAppSelector((state) => state.auth.currentUser); return 'MT';
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_MATTER_TYPES') }
const corners = useAppSelector((state) => state.style.corners);
const bgColor = useAppSelector((state) => state.style.cardsColor);
return name
.split(' ')
.map((part) => part[0])
.join('')
.slice(0, 2)
.toUpperCase();
};
const ListMatter_types = ({ matter_types, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_MATTER_TYPES');
return ( return (
<> <>
<div className='relative overflow-x-auto p-4 space-y-4'> <div className='grid grid-cols-[repeat(auto-fit,minmax(340px,1fr))] gap-4 p-4'>
{loading && <LoadingSpinner />} {loading && (
<div className='col-span-full rounded-xl border border-[#DDD5C7] bg-white p-10'>
<LoadingSpinner />
</div>
)}
{!loading && matter_types.map((item) => ( {!loading && matter_types.map((item) => (
<div key={item.id}> <div
<CardBox hasTable isList className={'rounded shadow-none'}> key={item.id}
<div className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}> className='min-w-0 overflow-hidden rounded-xl border border-[#DDD5C7] bg-white shadow-sm shadow-[#83755E]/10 transition hover:border-[#D8B75E]/70 hover:shadow-md'
>
<Link <div className='flex items-start justify-between gap-4 border-b border-[#E5E0D6] bg-[#FBF8F1] p-5'>
href={`/matter_types/matter_types-view/?id=${item.id}`} <div className='flex min-w-0 gap-4'>
className={ <div className='flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-[#0E1A2B] text-sm font-semibold text-[#D8B75E]'>
'flex-1 px-4 py-6 h-24 flex divide-x-2 divide-stone-300 items-center overflow-hidden`}> dark:divide-dark-700 overflow-x-auto' {getInitials(item.name)}
} </div>
> <div className='min-w-0'>
<p className='text-xs font-semibold uppercase tracking-[0.14em] text-[#8B7A61]'>
Matter type
<div className={'flex-1 px-3'}> </p>
<p className={'text-xs text-gray-500 '}>MatterType</p> <Link
<p className={'line-clamp-2'}>{ item.name }</p> href={`/matter_types/matter_types-view/?id=${item.id}`}
className='mt-2 block text-lg font-semibold leading-6 text-[#0E1A2B] hover:text-[#7A5B13]'
>
{item.name || 'Unnamed matter type'}
</Link>
</div>
</div> </div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Description</p>
<p className={'line-clamp-2'}>{ item.description }</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Active</p>
<p className={'line-clamp-2'}>{ dataFormatter.booleanFormatter(item.is_active) }</p>
</div>
</Link>
<ListActionsPopover <ListActionsPopover
onDelete={onDelete} onDelete={onDelete}
itemId={item.id} itemId={item.id}
pathEdit={`/matter_types/matter_types-edit/?id=${item.id}`} pathEdit={`/matter_types/matter_types-edit/?id=${item.id}`}
pathView={`/matter_types/matter_types-view/?id=${item.id}`} pathView={`/matter_types/matter_types-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
hasUpdatePermission={hasUpdatePermission}
/> />
</div> </div>
</CardBox>
</div> <div className='space-y-4 p-5'>
<div className='flex flex-wrap gap-2'>
<span
className={
item.is_active
? 'rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1 text-xs font-semibold text-emerald-700'
: 'rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-semibold text-slate-600'
}
>
{item.is_active ? 'Active' : 'Inactive'}
</span>
<span className='rounded-full border border-[#D8D0C2] bg-[#F6F3EC] px-3 py-1 text-xs font-semibold text-[#7A5B13]'>
Intake context
</span>
</div>
<p className='min-h-[72px] text-sm leading-6 text-[#5B6472]'>
{item.description || 'No matter-type description yet.'}
</p>
<div className='rounded-lg border border-[#E5E0D6] bg-[#FBF8F1] p-4'>
<p className='text-xs font-semibold uppercase tracking-[0.14em] text-[#8B7A61]'>
Governance use
</p>
<p className='mt-2 text-sm leading-6 text-[#0E1A2B]'>
Helps classify AI use cases by legal matter context before risk review and approval.
</p>
</div>
</div>
</div>
))} ))}
{!loading && matter_types.length === 0 && ( {!loading && matter_types.length === 0 && (
<div className='col-span-full flex items-center justify-center h-40'> <div className='col-span-full flex h-40 items-center justify-center rounded-xl border border-dashed border-[#D8D0C2] bg-white'>
<p className=''>No data to display</p> <p className='text-sm text-[#5B6472]'>No matter types to display</p>
</div> </div>
)} )}
</div> </div>
<div className={'flex items-center justify-center my-6'}>
<div className='my-6 flex items-center justify-center'>
<Pagination <Pagination
currentPage={currentPage} currentPage={currentPage}
numPages={numPages} numPages={numPages}
setCurrentPage={onPageChange} setCurrentPage={onPageChange}
/> />
</div> </div>
</> </>
) )
}; };
export default ListMatter_types export default ListMatter_types

View File

@ -44,9 +44,6 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
const { matter_types, loading, count, notify: matter_typesNotify, refetch } = useAppSelector((state) => state.matter_types) const { matter_types, loading, count, notify: matter_typesNotify, refetch } = useAppSelector((state) => state.matter_types)
const { currentUser } = useAppSelector((state) => state.auth); const { currentUser } = useAppSelector((state) => state.auth);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const corners = useAppSelector((state) => state.style.corners);
const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage); const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
for (let i = 0; i < numPages; i++) { for (let i = 0; i < numPages; i++) {
pagesList.push(i); pagesList.push(i);
@ -204,9 +201,7 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
}; };
const controlClasses = const controlClasses =
'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' + 'w-full my-1.5 rounded-lg border border-[#D8D0C2] bg-white px-3 py-2 text-sm text-[#0E1A2B] shadow-sm outline-none placeholder:text-[#9A8F7F] focus:border-[#D8B75E] focus:ring-2 focus:ring-[#D8B75E]/25 dark:border-dark-700 dark:bg-slate-800 dark:placeholder-gray-400';
` ${bgColor} ${focusRing} ${corners} ` +
'dark:bg-slate-800 border';
const dataGrid = ( const dataGrid = (
@ -264,7 +259,7 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
return ( return (
<> <>
{filterItems && Array.isArray( filterItems ) && filterItems.length ? {filterItems && Array.isArray( filterItems ) && filterItems.length ?
<CardBox> <CardBox className='mb-6 border border-[#DDD5C7] bg-[#FBF8F1] shadow-sm'>
<Formik <Formik
initialValues={{ initialValues={{
checkboxes: ['lorem'], checkboxes: ['lorem'],
@ -275,11 +270,18 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
> >
<Form> <Form>
<> <>
<div className='mb-4 flex flex-wrap items-center justify-between gap-3'>
<div>
<p className='text-xs font-semibold uppercase tracking-[0.14em] text-[#7A5B13]'>Active filters</p>
<p className='mt-1 text-sm text-[#5B6472]'>Narrow matter types by name or description.</p>
</div>
<span className='rounded-full border border-[#D8B75E] bg-[#FFF8DF] px-3 py-1 text-xs font-semibold text-[#7A5B13]'>Matter scope</span>
</div>
{filterItems && filterItems.map((filterItem) => { {filterItems && filterItems.map((filterItem) => {
return ( return (
<div key={filterItem.id} className="flex mb-4"> <div key={filterItem.id} className="grid gap-3 rounded-lg border border-[#E5E0D6] bg-white p-4 shadow-sm md:grid-cols-[minmax(180px,0.9fr)_minmax(240px,1.4fr)_auto] md:items-end">
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">Filter</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">Filter</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='selectedField' name='selectedField'
@ -301,8 +303,8 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
{filters.find((filter) => {filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField filter.title === filterItem?.fields?.selectedField
)?.type === 'enum' ? ( )?.type === 'enum' ? (
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className="text-gray-500 font-bold"> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">
Value Value
</div> </div>
<Field <Field
@ -326,9 +328,9 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
) : filters.find((filter) => ) : filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField filter.title === filterItem?.fields?.selectedField
)?.number ? ( )?.number ? (
<div className="flex flex-row w-full mr-3"> <div className="grid w-full gap-3 sm:grid-cols-2">
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">From</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">From</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValueFrom' name='filterValueFrom'
@ -339,7 +341,7 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
/> />
</div> </div>
<div className="flex flex-col w-full"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">To</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">To</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValueTo' name='filterValueTo'
@ -355,9 +357,9 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
filter.title === filter.title ===
filterItem?.fields?.selectedField filterItem?.fields?.selectedField
)?.date ? ( )?.date ? (
<div className='flex flex-row w-full mr-3'> <div className='grid w-full gap-3 sm:grid-cols-2'>
<div className='flex flex-col w-full mr-3'> <div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'> <div className='text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]'>
From From
</div> </div>
<Field <Field
@ -371,7 +373,7 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
/> />
</div> </div>
<div className='flex flex-col w-full'> <div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'>To</div> <div className='text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]'>To</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValueTo' name='filterValueTo'
@ -384,8 +386,8 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
</div> </div>
</div> </div>
) : ( ) : (
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">Contains</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">Contains</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValue' name='filterValue'
@ -397,7 +399,7 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
</div> </div>
)} )}
<div className="flex flex-col"> <div className="flex flex-col">
<div className=" text-gray-500 font-bold">Action</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">Action</div>
<BaseButton <BaseButton
className="my-2" className="my-2"
type='reset' type='reset'
@ -411,17 +413,17 @@ const TableSampleMatter_types = ({ filterItems, setFilterItems, filters, showGri
</div> </div>
) )
})} })}
<div className="flex"> <div className="flex flex-wrap gap-2">
<BaseButton <BaseButton
className="my-2 mr-3" className="my-2 mr-3"
color="success" color="info"
label='Apply' label='Apply'
onClick={handleSubmit} onClick={handleSubmit}
/> />
<BaseButton <BaseButton
className="my-2" className="my-2"
color='info' color='whiteDark'
label='Cancel' label='Reset'
onClick={handleReset} onClick={handleReset}
/> />
</div> </div>

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'MatterType', headerName: 'Matter type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'title', field: 'title',
headerName: 'PolicyTitle', headerName: 'Policy Title',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -58,7 +58,7 @@ export const loadColumns = async (
{ {
field: 'policy_type', field: 'policy_type',
headerName: 'PolicyType', headerName: 'Policy Type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -88,7 +88,7 @@ export const loadColumns = async (
{ {
field: 'practice_group', field: 'practice_group',
headerName: 'PracticeGroupScope', headerName: 'Practice Group Scope',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -110,7 +110,7 @@ export const loadColumns = async (
{ {
field: 'data_classification', field: 'data_classification',
headerName: 'DataClassificationScope', headerName: 'Data Classification Scope',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -162,7 +162,7 @@ export const loadColumns = async (
{ {
field: 'effective_from', field: 'effective_from',
headerName: 'EffectiveFrom', headerName: 'Effective From',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -180,7 +180,7 @@ export const loadColumns = async (
{ {
field: 'effective_to', field: 'effective_to',
headerName: 'EffectiveTo', headerName: 'Effective To',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'PracticeGroupName', headerName: 'Practice Group Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -73,7 +73,7 @@ export const loadColumns = async (
{ {
field: 'lead_user', field: 'lead_user',
headerName: 'PracticeGroupLead', headerName: 'Practice Group Lead',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'workflow_run', field: 'workflow_run',
headerName: 'WorkflowRun', headerName: 'Workflow Run',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -87,7 +87,7 @@ export const loadColumns = async (
{ {
field: 'raised_by', field: 'raised_by',
headerName: 'RaisedBy', headerName: 'Raised By',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -109,7 +109,7 @@ export const loadColumns = async (
{ {
field: 'exception_type', field: 'exception_type',
headerName: 'ExceptionType', headerName: 'Exception Type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -139,7 +139,7 @@ export const loadColumns = async (
{ {
field: 'resolution_status', field: 'resolution_status',
headerName: 'ResolutionStatus', headerName: 'Resolution Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -154,7 +154,7 @@ export const loadColumns = async (
{ {
field: 'raised_at', field: 'raised_at',
headerName: 'RaisedAt', headerName: 'Raised At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -172,7 +172,7 @@ export const loadColumns = async (
{ {
field: 'resolved_at', field: 'resolved_at',
headerName: 'ResolvedAt', headerName: 'Resolved At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -1,123 +1,3 @@
import React from 'react'; import ListRoles_catalog from './ListRoles_catalog';
import ImageField from '../ImageField';
import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import dataFormatter from '../../helpers/dataFormatter';
import { Pagination } from '../Pagination';
import {saveFile} from "../../helpers/fileSaver";
import LoadingSpinner from "../LoadingSpinner";
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions"; export default ListRoles_catalog;
type Props = {
roles_catalog: any[];
loading: boolean;
onDelete: (id: string) => void;
currentPage: number;
numPages: number;
onPageChange: (page: number) => void;
};
const CardRoles_catalog = ({
roles_catalog,
loading,
onDelete,
currentPage,
numPages,
onPageChange,
}: Props) => {
const asideScrollbarsStyle = useAppSelector(
(state) => state.style.asideScrollbarsStyle,
);
const bgColor = useAppSelector((state) => state.style.cardsColor);
const darkMode = useAppSelector((state) => state.style.darkMode);
const corners = useAppSelector((state) => state.style.corners);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ROLES_CATALOG')
return (
<div className={'p-4'}>
{loading && <LoadingSpinner />}
<ul
role='list'
className='grid grid-cols-1 gap-x-6 gap-y-8 lg:grid-cols-3 2xl:grid-cols-4 xl:gap-x-8'
>
{!loading && roles_catalog.map((item, index) => (
<li
key={item.id}
className={`overflow-hidden ${corners !== 'rounded-full'? corners : 'rounded-3xl'} border ${focusRing} border-gray-200 dark:border-dark-700 ${
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
}`}
>
<div className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}>
<Link href={`/roles_catalog/roles_catalog-view/?id=${item.id}`} className='text-lg font-bold leading-6 line-clamp-1'>
{item.name}
</Link>
<div className='ml-auto '>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/roles_catalog/roles_catalog-edit/?id=${item.id}`}
pathView={`/roles_catalog/roles_catalog-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</div>
<dl className='divide-y divide-stone-300 dark:divide-dark-700 px-6 py-4 text-sm leading-6 h-64 overflow-y-auto'>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>RoleName</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ item.name }
</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Description</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ item.description }
</div>
</dd>
</div>
</dl>
</li>
))}
{!loading && roles_catalog.length === 0 && (
<div className='col-span-full flex items-center justify-center h-40'>
<p className=''>No data to display</p>
</div>
)}
</ul>
<div className={'flex items-center justify-center my-6'}>
<Pagination
currentPage={currentPage}
numPages={numPages}
setCurrentPage={onPageChange}
/>
</div>
</div>
);
};
export default CardRoles_catalog;

View File

@ -1,16 +1,10 @@
import React from 'react'; import React from 'react';
import CardBox from '../CardBox';
import ImageField from '../ImageField';
import dataFormatter from '../../helpers/dataFormatter';
import {saveFile} from "../../helpers/fileSaver";
import ListActionsPopover from "../ListActionsPopover";
import {useAppSelector} from "../../stores/hooks";
import {Pagination} from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import Link from 'next/link'; import Link from 'next/link';
import ListActionsPopover from "../ListActionsPopover";
import {hasPermission} from "../../helpers/userPermissions"; import { useAppSelector } from "../../stores/hooks";
import { Pagination } from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import { hasPermission } from "../../helpers/userPermissions";
type Props = { type Props = {
roles_catalog: any[]; roles_catalog: any[];
@ -21,76 +15,105 @@ type Props = {
onPageChange: (page: number) => void; onPageChange: (page: number) => void;
}; };
const ListRoles_catalog = ({ roles_catalog, loading, onDelete, currentPage, numPages, onPageChange }: Props) => { const getInitials = (name?: string) => {
if (!name) {
const currentUser = useAppSelector((state) => state.auth.currentUser); return 'RC';
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ROLES_CATALOG') }
const corners = useAppSelector((state) => state.style.corners);
const bgColor = useAppSelector((state) => state.style.cardsColor);
return name
.split(' ')
.map((part) => part[0])
.join('')
.slice(0, 2)
.toUpperCase();
};
const ListRoles_catalog = ({ roles_catalog, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ROLES_CATALOG');
return ( return (
<> <>
<div className='relative overflow-x-auto p-4 space-y-4'> <div className='grid grid-cols-[repeat(auto-fit,minmax(340px,1fr))] gap-4 p-4'>
{loading && <LoadingSpinner />} {loading && (
<div className='col-span-full rounded-xl border border-[#DDD5C7] bg-white p-10'>
<LoadingSpinner />
</div>
)}
{!loading && roles_catalog.map((item) => ( {!loading && roles_catalog.map((item) => (
<div key={item.id}> <div
<CardBox hasTable isList className={'rounded shadow-none'}> key={item.id}
<div className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}> className='min-w-0 overflow-hidden rounded-xl border border-[#DDD5C7] bg-white shadow-sm shadow-[#83755E]/10 transition hover:border-[#D8B75E]/70 hover:shadow-md'
>
<Link <div className='flex items-start justify-between gap-4 border-b border-[#E5E0D6] bg-[#FBF8F1] p-5'>
href={`/roles_catalog/roles_catalog-view/?id=${item.id}`} <div className='flex min-w-0 gap-4'>
className={ <div className='flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-[#0E1A2B] text-sm font-semibold text-[#D8B75E]'>
'flex-1 px-4 py-6 h-24 flex divide-x-2 divide-stone-300 items-center overflow-hidden`}> dark:divide-dark-700 overflow-x-auto' {getInitials(item.name)}
} </div>
> <div className='min-w-0'>
<p className='text-xs font-semibold uppercase tracking-[0.14em] text-[#8B7A61]'>
Governance role
<div className={'flex-1 px-3'}> </p>
<p className={'text-xs text-gray-500 '}>RoleName</p> <Link
<p className={'line-clamp-2'}>{ item.name }</p> href={`/roles_catalog/roles_catalog-view/?id=${item.id}`}
className='mt-2 block text-lg font-semibold leading-6 text-[#0E1A2B] hover:text-[#7A5B13]'
>
{item.name || 'Unnamed role'}
</Link>
</div>
</div> </div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Description</p>
<p className={'line-clamp-2'}>{ item.description }</p>
</div>
</Link>
<ListActionsPopover <ListActionsPopover
onDelete={onDelete} onDelete={onDelete}
itemId={item.id} itemId={item.id}
pathEdit={`/roles_catalog/roles_catalog-edit/?id=${item.id}`} pathEdit={`/roles_catalog/roles_catalog-edit/?id=${item.id}`}
pathView={`/roles_catalog/roles_catalog-view/?id=${item.id}`} pathView={`/roles_catalog/roles_catalog-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
hasUpdatePermission={hasUpdatePermission}
/> />
</div> </div>
</CardBox>
</div> <div className='space-y-4 p-5'>
<div className='flex flex-wrap gap-2'>
<span className='rounded-full border border-[#D8B75E] bg-[#FFF8DF] px-3 py-1 text-xs font-semibold text-[#7A5B13]'>
Role catalog
</span>
<span className='rounded-full border border-[#D8D0C2] bg-[#F6F3EC] px-3 py-1 text-xs font-semibold text-[#7A5B13]'>
Approval ownership
</span>
</div>
<p className='min-h-[72px] text-sm leading-6 text-[#5B6472]'>
{item.description || 'No role description yet.'}
</p>
<div className='rounded-lg border border-[#E5E0D6] bg-[#FBF8F1] p-4'>
<p className='text-xs font-semibold uppercase tracking-[0.14em] text-[#8B7A61]'>
Governance use
</p>
<p className='mt-2 text-sm leading-6 text-[#0E1A2B]'>
Defines who can own, approve, review, or monitor AI governance workflows.
</p>
</div>
</div>
</div>
))} ))}
{!loading && roles_catalog.length === 0 && ( {!loading && roles_catalog.length === 0 && (
<div className='col-span-full flex items-center justify-center h-40'> <div className='col-span-full flex h-40 items-center justify-center rounded-xl border border-dashed border-[#D8D0C2] bg-white'>
<p className=''>No data to display</p> <p className='text-sm text-[#5B6472]'>No roles to display</p>
</div> </div>
)} )}
</div> </div>
<div className={'flex items-center justify-center my-6'}>
<div className='my-6 flex items-center justify-center'>
<Pagination <Pagination
currentPage={currentPage} currentPage={currentPage}
numPages={numPages} numPages={numPages}
setCurrentPage={onPageChange} setCurrentPage={onPageChange}
/> />
</div> </div>
</> </>
) )
}; };
export default ListRoles_catalog export default ListRoles_catalog

View File

@ -44,9 +44,6 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
const { roles_catalog, loading, count, notify: roles_catalogNotify, refetch } = useAppSelector((state) => state.roles_catalog) const { roles_catalog, loading, count, notify: roles_catalogNotify, refetch } = useAppSelector((state) => state.roles_catalog)
const { currentUser } = useAppSelector((state) => state.auth); const { currentUser } = useAppSelector((state) => state.auth);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const corners = useAppSelector((state) => state.style.corners);
const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage); const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
for (let i = 0; i < numPages; i++) { for (let i = 0; i < numPages; i++) {
pagesList.push(i); pagesList.push(i);
@ -204,9 +201,7 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
}; };
const controlClasses = const controlClasses =
'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' + 'w-full my-1.5 rounded-lg border border-[#D8D0C2] bg-white px-3 py-2 text-sm text-[#0E1A2B] shadow-sm outline-none placeholder:text-[#9A8F7F] focus:border-[#D8B75E] focus:ring-2 focus:ring-[#D8B75E]/25 dark:border-dark-700 dark:bg-slate-800 dark:placeholder-gray-400';
` ${bgColor} ${focusRing} ${corners} ` +
'dark:bg-slate-800 border';
const dataGrid = ( const dataGrid = (
@ -264,7 +259,7 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
return ( return (
<> <>
{filterItems && Array.isArray( filterItems ) && filterItems.length ? {filterItems && Array.isArray( filterItems ) && filterItems.length ?
<CardBox> <CardBox className='mb-6 border border-[#DDD5C7] bg-[#FBF8F1] shadow-sm'>
<Formik <Formik
initialValues={{ initialValues={{
checkboxes: ['lorem'], checkboxes: ['lorem'],
@ -275,11 +270,18 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
> >
<Form> <Form>
<> <>
<div className='mb-4 flex flex-wrap items-center justify-between gap-3'>
<div>
<p className='text-xs font-semibold uppercase tracking-[0.14em] text-[#7A5B13]'>Active filters</p>
<p className='mt-1 text-sm text-[#5B6472]'>Narrow the role catalog by owner role or description.</p>
</div>
<span className='rounded-full border border-[#D8B75E] bg-[#FFF8DF] px-3 py-1 text-xs font-semibold text-[#7A5B13]'>Role scope</span>
</div>
{filterItems && filterItems.map((filterItem) => { {filterItems && filterItems.map((filterItem) => {
return ( return (
<div key={filterItem.id} className="flex mb-4"> <div key={filterItem.id} className="grid gap-3 rounded-lg border border-[#E5E0D6] bg-white p-4 shadow-sm md:grid-cols-[minmax(180px,0.9fr)_minmax(240px,1.4fr)_auto] md:items-end">
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">Filter</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">Filter</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='selectedField' name='selectedField'
@ -301,8 +303,8 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
{filters.find((filter) => {filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField filter.title === filterItem?.fields?.selectedField
)?.type === 'enum' ? ( )?.type === 'enum' ? (
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className="text-gray-500 font-bold"> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">
Value Value
</div> </div>
<Field <Field
@ -326,9 +328,9 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
) : filters.find((filter) => ) : filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField filter.title === filterItem?.fields?.selectedField
)?.number ? ( )?.number ? (
<div className="flex flex-row w-full mr-3"> <div className="grid w-full gap-3 sm:grid-cols-2">
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">From</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">From</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValueFrom' name='filterValueFrom'
@ -339,7 +341,7 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
/> />
</div> </div>
<div className="flex flex-col w-full"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">To</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">To</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValueTo' name='filterValueTo'
@ -351,13 +353,13 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
</div> </div>
</div> </div>
) : filters.find( ) : filters.find(
(filter) => (filter) =>
filter.title === filter.title ===
filterItem?.fields?.selectedField filterItem?.fields?.selectedField
)?.date ? ( )?.date ? (
<div className='flex flex-row w-full mr-3'> <div className='grid w-full gap-3 sm:grid-cols-2'>
<div className='flex flex-col w-full mr-3'> <div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'> <div className='text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]'>
From From
</div> </div>
<Field <Field
@ -371,7 +373,7 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
/> />
</div> </div>
<div className='flex flex-col w-full'> <div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'>To</div> <div className='text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]'>To</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValueTo' name='filterValueTo'
@ -384,8 +386,8 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
</div> </div>
</div> </div>
) : ( ) : (
<div className="flex flex-col w-full mr-3"> <div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">Contains</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">Contains</div>
<Field <Field
className={controlClasses} className={controlClasses}
name='filterValue' name='filterValue'
@ -397,7 +399,7 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
</div> </div>
)} )}
<div className="flex flex-col"> <div className="flex flex-col">
<div className=" text-gray-500 font-bold">Action</div> <div className="text-xs font-semibold uppercase tracking-[0.12em] text-[#7A5B13]">Action</div>
<BaseButton <BaseButton
className="my-2" className="my-2"
type='reset' type='reset'
@ -411,17 +413,17 @@ const TableSampleRoles_catalog = ({ filterItems, setFilterItems, filters, showGr
</div> </div>
) )
})} })}
<div className="flex"> <div className="flex flex-wrap gap-2">
<BaseButton <BaseButton
className="my-2 mr-3" className="my-2 mr-3"
color="success" color="info"
label='Apply' label='Apply'
onClick={handleSubmit} onClick={handleSubmit}
/> />
<BaseButton <BaseButton
className="my-2" className="my-2"
color='info' color='whiteDark'
label='Cancel' label='Reset'
onClick={handleReset} onClick={handleReset}
/> />
</div> </div>

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'RoleName', headerName: 'Role name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -65,7 +65,7 @@ export const loadColumns = async (
{ {
field: 'tool', field: 'tool',
headerName: 'AITool', headerName: 'AI Tool',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -87,7 +87,7 @@ export const loadColumns = async (
{ {
field: 'entitlement_status', field: 'entitlement_status',
headerName: 'EntitlementStatus', headerName: 'Entitlement Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -102,7 +102,7 @@ export const loadColumns = async (
{ {
field: 'effective_from', field: 'effective_from',
headerName: 'EffectiveFrom', headerName: 'Effective From',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -120,7 +120,7 @@ export const loadColumns = async (
{ {
field: 'effective_to', field: 'effective_to',
headerName: 'EffectiveTo', headerName: 'Effective To',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -138,7 +138,7 @@ export const loadColumns = async (
{ {
field: 'restriction_reason', field: 'restriction_reason',
headerName: 'RestrictionReason', headerName: 'Restriction Reason',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'CourseName', headerName: 'Course Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -73,7 +73,7 @@ export const loadColumns = async (
{ {
field: 'delivery_type', field: 'delivery_type',
headerName: 'DeliveryType', headerName: 'Delivery Type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -103,7 +103,7 @@ export const loadColumns = async (
{ {
field: 'duration_minutes', field: 'duration_minutes',
headerName: 'DurationMinutes', headerName: 'Duration Minutes',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -119,7 +119,7 @@ export const loadColumns = async (
{ {
field: 'validity_days', field: 'validity_days',
headerName: 'ValidityDays', headerName: 'Validity Days',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -87,7 +87,7 @@ export const loadColumns = async (
{ {
field: 'completion_status', field: 'completion_status',
headerName: 'CompletionStatus', headerName: 'Completion Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -102,7 +102,7 @@ export const loadColumns = async (
{ {
field: 'completed_at', field: 'completed_at',
headerName: 'CompletedAt', headerName: 'Completed At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -120,7 +120,7 @@ export const loadColumns = async (
{ {
field: 'expires_at', field: 'expires_at',
headerName: 'ExpiresAt', headerName: 'Expires At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -138,7 +138,7 @@ export const loadColumns = async (
{ {
field: 'evidence_note', field: 'evidence_note',
headerName: 'EvidenceNote', headerName: 'Evidence Note',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -153,7 +153,7 @@ export const loadColumns = async (
{ {
field: 'certificate_files', field: 'certificate_files',
headerName: 'CertificateFiles', headerName: 'Certificate Files',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -65,7 +65,7 @@ export const loadColumns = async (
{ {
field: 'tool', field: 'tool',
headerName: 'AITool', headerName: 'AI Tool',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -87,7 +87,7 @@ export const loadColumns = async (
{ {
field: 'assessment_status', field: 'assessment_status',
headerName: 'AssessmentStatus', headerName: 'Assessment Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -102,7 +102,7 @@ export const loadColumns = async (
{ {
field: 'confidentiality_score', field: 'confidentiality_score',
headerName: 'ConfidentialityScore', headerName: 'Confidentiality Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -118,7 +118,7 @@ export const loadColumns = async (
{ {
field: 'security_score', field: 'security_score',
headerName: 'SecurityScore', headerName: 'Security Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -134,7 +134,7 @@ export const loadColumns = async (
{ {
field: 'integration_readiness_score', field: 'integration_readiness_score',
headerName: 'IntegrationReadinessScore', headerName: 'Integration Readiness Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -150,7 +150,7 @@ export const loadColumns = async (
{ {
field: 'legal_specific_risk_score', field: 'legal_specific_risk_score',
headerName: 'LegalSpecificRiskScore', headerName: 'Legal Specific Risk Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -166,7 +166,7 @@ export const loadColumns = async (
{ {
field: 'pricing_score', field: 'pricing_score',
headerName: 'PricingScore', headerName: 'Pricing Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -182,7 +182,7 @@ export const loadColumns = async (
{ {
field: 'support_score', field: 'support_score',
headerName: 'SupportScore', headerName: 'Support Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -198,7 +198,7 @@ export const loadColumns = async (
{ {
field: 'compliance_score', field: 'compliance_score',
headerName: 'ComplianceScore', headerName: 'Compliance Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -214,7 +214,7 @@ export const loadColumns = async (
{ {
field: 'overall_score', field: 'overall_score',
headerName: 'OverallScore', headerName: 'Overall Score',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -260,7 +260,7 @@ export const loadColumns = async (
{ {
field: 'evidence_files', field: 'evidence_files',
headerName: 'EvidenceFiles', headerName: 'Evidence Files',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -286,7 +286,7 @@ export const loadColumns = async (
{ {
field: 'owner', field: 'owner',
headerName: 'AssessmentOwner', headerName: 'Assessment Owner',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -308,7 +308,7 @@ export const loadColumns = async (
{ {
field: 'started_at', field: 'started_at',
headerName: 'StartedAt', headerName: 'Started At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -326,7 +326,7 @@ export const loadColumns = async (
{ {
field: 'completed_at', field: 'completed_at',
headerName: 'CompletedAt', headerName: 'Completed At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'name', field: 'name',
headerName: 'VendorName', headerName: 'Vendor Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -73,7 +73,7 @@ export const loadColumns = async (
{ {
field: 'vendor_status', field: 'vendor_status',
headerName: 'VendorStatus', headerName: 'Vendor Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -88,7 +88,7 @@ export const loadColumns = async (
{ {
field: 'primary_contact_name', field: 'primary_contact_name',
headerName: 'PrimaryContactName', headerName: 'Primary Contact Name',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -103,7 +103,7 @@ export const loadColumns = async (
{ {
field: 'primary_contact_email', field: 'primary_contact_email',
headerName: 'PrimaryContactEmail', headerName: 'Primary Contact Email',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -118,7 +118,7 @@ export const loadColumns = async (
{ {
field: 'contract_documents', field: 'contract_documents',
headerName: 'ContractDocuments', headerName: 'Contract Documents',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -43,7 +43,7 @@ export const loadColumns = async (
{ {
field: 'use_case', field: 'use_case',
headerName: 'AIUseCase', headerName: 'AI Use Case',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -109,7 +109,7 @@ export const loadColumns = async (
{ {
field: 'practice_group', field: 'practice_group',
headerName: 'PracticeGroup', headerName: 'Practice Group',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -131,7 +131,7 @@ export const loadColumns = async (
{ {
field: 'matter_type', field: 'matter_type',
headerName: 'MatterType', headerName: 'Matter Type',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -153,7 +153,7 @@ export const loadColumns = async (
{ {
field: 'review_status', field: 'review_status',
headerName: 'ReviewStatus', headerName: 'Review Status',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -168,7 +168,7 @@ export const loadColumns = async (
{ {
field: 'output_disposition', field: 'output_disposition',
headerName: 'OutputDisposition', headerName: 'Output Disposition',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -183,7 +183,7 @@ export const loadColumns = async (
{ {
field: 'issues_found', field: 'issues_found',
headerName: 'IssuesFound', headerName: 'Issues Found',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -198,7 +198,7 @@ export const loadColumns = async (
{ {
field: 'actual_hours_saved', field: 'actual_hours_saved',
headerName: 'ActualHoursSaved', headerName: 'Actual Hours Saved',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -214,7 +214,7 @@ export const loadColumns = async (
{ {
field: 'run_cost', field: 'run_cost',
headerName: 'RunCost', headerName: 'Run Cost',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,
@ -230,7 +230,7 @@ export const loadColumns = async (
{ {
field: 'ran_at', field: 'ran_at',
headerName: 'RanAt', headerName: 'Ran At',
flex: 1, flex: 1,
minWidth: 120, minWidth: 120,
filterable: false, filterable: false,

View File

@ -70,13 +70,13 @@
@apply text-sm font-normal text-pavitra-900 dark:text-white; @apply text-sm font-normal text-pavitra-900 dark:text-white;
} }
.datagrid--table, .MuiDataGrid-root { .datagrid--table {
@apply rounded border-none !important; @apply rounded-xl border-none !important;
} }
.datagrid--header { .datagrid--header {
@apply uppercase !important; letter-spacing: 0.07em !important;
text-transform: uppercase !important;
} }
.datagrid--header, .datagrid--header,
@ -95,7 +95,31 @@
} }
.datagrid--row { .datagrid--row {
@apply even:bg-gray-100 dark:even:bg-[#1B1D22] dark:odd:bg-dark-900 !important; @apply even:bg-[#F7F5EF] odd:bg-white dark:even:bg-[#1B1D22] dark:odd:bg-dark-900 !important;
}
.datagrid--table .MuiDataGrid-cell,
.datagrid--table .MuiDataGrid-columnHeader {
min-width: 0;
}
.datagrid--table .MuiDataGrid-cellContent,
.datagrid--table .MuiDataGrid-columnHeaderTitle {
word-break: normal !important;
}
.datagrid--table .MuiDataGrid-cellContent {
overflow-wrap: normal;
white-space: nowrap !important;
}
.datagrid--table .MuiDataGrid-columnHeaderTitle {
overflow-wrap: normal;
white-space: normal !important;
}
.datagrid--table .MuiDataGrid-cellContent {
color: #374151;
} }
@ -111,7 +135,7 @@
@apply dark:bg-dark-700; @apply dark:bg-dark-700;
} }
.MuiButton-colorInherit { .datagrid--table .MuiButton-colorInherit {
@apply text-blue-600 dark:text-dark-700 !important; @apply text-blue-600 dark:text-dark-700 !important;
} }
} }

View File

@ -134,7 +134,7 @@ const AiUseCasesNew = () => {
</div> </div>
</CardBox> </CardBox>
<CardBox className='border border-[#D6E0F5] bg-[#0F172A] text-white'> <CardBox className='border-0 !bg-[#0F172A] !text-white'>
<div className='space-y-5'> <div className='space-y-5'>
<div> <div>
<p className='text-sm font-semibold uppercase tracking-[0.18em] text-slate-300'>What happens next</p> <p className='text-sm font-semibold uppercase tracking-[0.18em] text-slate-300'>What happens next</p>

View File

@ -275,7 +275,7 @@ const GovernanceWorkbench = () => {
</NotificationBar> </NotificationBar>
)} )}
<CardBox className='mb-6 overflow-hidden border-0 bg-[#0F172A] text-white'> <CardBox className='mb-6 overflow-hidden border-0 !bg-[#0F172A] !text-white'>
<div className='grid gap-8 xl:grid-cols-[minmax(0,1.45fr)_minmax(320px,0.8fr)]'> <div className='grid gap-8 xl:grid-cols-[minmax(0,1.45fr)_minmax(320px,0.8fr)]'>
<div className='space-y-6 p-2'> <div className='space-y-6 p-2'>
<div className='inline-flex items-center rounded-full border border-white/15 bg-white/5 px-3 py-1 text-xs font-semibold uppercase tracking-[0.18em] text-slate-200'> <div className='inline-flex items-center rounded-full border border-white/15 bg-white/5 px-3 py-1 text-xs font-semibold uppercase tracking-[0.18em] text-slate-200'>

View File

@ -178,11 +178,11 @@ const EditMatter_types = () => {
<FormField <FormField
label="MatterType" label="Matter type"
> >
<Field <Field
name="name" name="name"
placeholder="MatterType" placeholder="e.g. Litigation, contracts, employment"
/> />
</FormField> </FormField>

View File

@ -158,10 +158,10 @@ const EditMatter_typesPage = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Edit matter_types')}</title> <title>{getPageTitle('Edit matter type')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit matter_types'} main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit matter type'} main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
@ -175,11 +175,11 @@ const EditMatter_typesPage = () => {
<FormField <FormField
label="MatterType" label="Matter type"
> >
<Field <Field
name="name" name="name"
placeholder="MatterType" placeholder="e.g. Litigation, contracts, employment"
/> />
</FormField> </FormField>

View File

@ -6,11 +6,11 @@ import CardBox from '../../components/CardBox'
import LayoutAuthenticated from '../../layouts/Authenticated' import LayoutAuthenticated from '../../layouts/Authenticated'
import SectionMain from '../../components/SectionMain' import SectionMain from '../../components/SectionMain'
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
import LegalOpsPageIntro from '../../components/LegalOpsPageIntro'
import { getPageTitle } from '../../config' import { getPageTitle } from '../../config'
import TableMatter_types from '../../components/Matter_types/TableMatter_types' import TableMatter_types from '../../components/Matter_types/TableMatter_types'
import BaseButton from '../../components/BaseButton' import BaseButton from '../../components/BaseButton'
import axios from "axios"; import axios from "axios";
import Link from "next/link";
import {useAppDispatch, useAppSelector} from "../../stores/hooks"; import {useAppDispatch, useAppSelector} from "../../stores/hooks";
import CardBoxModal from "../../components/CardBoxModal"; import CardBoxModal from "../../components/CardBoxModal";
import DragDropFilePicker from "../../components/DragDropFilePicker"; import DragDropFilePicker from "../../components/DragDropFilePicker";
@ -34,7 +34,7 @@ const Matter_typesTablesPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [filters] = useState([{label: 'MatterType', title: 'name'},{label: 'Description', title: 'description'}, const [filters] = useState([{label: 'Matter type', title: 'name'},{label: 'Description', title: 'description'},
@ -86,27 +86,33 @@ const Matter_typesTablesPage = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Matter_types')}</title> <title>{getPageTitle('Matter types')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Matter_types" main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Matter types" main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox className='mb-6' cardBoxClassName='flex flex-wrap'> <LegalOpsPageIntro
eyebrow='Matter context'
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/matter_types/matter_types-new'} color='info' label='New Item'/>} title='Classify legal AI requests by matter type before risk review'
description='Maintain the matter taxonomy used during AI use-case intake, data sensitivity classification, reviewer routing, and policy coverage.'
metrics={[
{ label: 'Classification', value: 'Matter type', helper: 'Every AI request can carry legal context from intake.' },
{ label: 'Risk lens', value: 'Context-aware', helper: 'Different matters can imply different privilege and confidentiality concerns.' },
{ label: 'Routing', value: 'Review support', helper: 'Matter type helps send requests to the right practice owners.' },
]}
>
{hasCreatePermission && <BaseButton href={'/matter_types/matter_types-new'} color='info' label='New matter type'/>}
<BaseButton <BaseButton
className={'mr-3'}
color='info' color='info'
label='Filter' label='Add filter'
onClick={addFilter} onClick={addFilter}
/> />
<BaseButton className={'mr-3'} color='info' label='Download CSV' onClick={getMatter_typesCSV} /> <BaseButton color='whiteDark' label='Export CSV' onClick={getMatter_typesCSV} />
{hasCreatePermission && ( {hasCreatePermission && (
<BaseButton <BaseButton
color='info' color='whiteDark'
label='Upload CSV' label='Upload CSV'
onClick={() => setIsModalActive(true)} onClick={() => setIsModalActive(true)}
/> />
@ -116,11 +122,9 @@ const Matter_typesTablesPage = () => {
<div id='delete-rows-button'></div> <div id='delete-rows-button'></div>
</div> </div>
<div className='md:inline-flex items-center ms-auto'> <BaseButton href={'/matter_types/matter_types-table'} color='whiteDark' label='Table view'/>
<Link href={'/matter_types/matter_types-table'}>Switch to Table</Link>
</div>
</CardBox> </LegalOpsPageIntro>
<CardBox className="mb-6" hasTable> <CardBox className="mb-6" hasTable>
<TableMatter_types <TableMatter_types

View File

@ -94,10 +94,10 @@ const Matter_typesNew = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('New Item')}</title> <title>{getPageTitle('New matter type')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New Item" main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New matter type" main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
@ -114,11 +114,11 @@ const Matter_typesNew = () => {
<FormField <FormField
label="MatterType" label="Matter type"
> >
<Field <Field
name="name" name="name"
placeholder="MatterType" placeholder="e.g. Litigation, contracts, employment"
/> />
</FormField> </FormField>

View File

@ -6,11 +6,11 @@ import CardBox from '../../components/CardBox'
import LayoutAuthenticated from '../../layouts/Authenticated' import LayoutAuthenticated from '../../layouts/Authenticated'
import SectionMain from '../../components/SectionMain' import SectionMain from '../../components/SectionMain'
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
import LegalOpsPageIntro from '../../components/LegalOpsPageIntro'
import { getPageTitle } from '../../config' import { getPageTitle } from '../../config'
import TableMatter_types from '../../components/Matter_types/TableMatter_types' import TableMatter_types from '../../components/Matter_types/TableMatter_types'
import BaseButton from '../../components/BaseButton' import BaseButton from '../../components/BaseButton'
import axios from "axios"; import axios from "axios";
import Link from "next/link";
import {useAppDispatch, useAppSelector} from "../../stores/hooks"; import {useAppDispatch, useAppSelector} from "../../stores/hooks";
import CardBoxModal from "../../components/CardBoxModal"; import CardBoxModal from "../../components/CardBoxModal";
import DragDropFilePicker from "../../components/DragDropFilePicker"; import DragDropFilePicker from "../../components/DragDropFilePicker";
@ -34,7 +34,7 @@ const Matter_typesTablesPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [filters] = useState([{label: 'MatterType', title: 'name'},{label: 'Description', title: 'description'}, const [filters] = useState([{label: 'Matter type', title: 'name'},{label: 'Description', title: 'description'},
@ -86,27 +86,33 @@ const Matter_typesTablesPage = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Matter_types')}</title> <title>{getPageTitle('Matter types table')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Matter_types" main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Matter types table" main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox className='mb-6' cardBoxClassName='flex flex-wrap'> <LegalOpsPageIntro
eyebrow='Matter context'
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/matter_types/matter_types-new'} color='info' label='New Item'/>} title='Matter types as an editable governance table'
description='Use table view to scan and edit the matter taxonomy used for AI request classification and review routing.'
metrics={[
{ label: 'View mode', value: 'Table', helper: 'Best for quick taxonomy cleanup and bulk review.' },
{ label: 'Classification', value: 'Matter type', helper: 'Matter context gives AI workflows legal specificity.' },
{ label: 'Routing', value: 'Review support', helper: 'Matter type can inform practice-owner review paths.' },
]}
>
{hasCreatePermission && <BaseButton href={'/matter_types/matter_types-new'} color='info' label='New matter type'/>}
<BaseButton <BaseButton
className={'mr-3'}
color='info' color='info'
label='Filter' label='Add filter'
onClick={addFilter} onClick={addFilter}
/> />
<BaseButton className={'mr-3'} color='info' label='Download CSV' onClick={getMatter_typesCSV} /> <BaseButton color='whiteDark' label='Export CSV' onClick={getMatter_typesCSV} />
{hasCreatePermission && ( {hasCreatePermission && (
<BaseButton <BaseButton
color='info' color='whiteDark'
label='Upload CSV' label='Upload CSV'
onClick={() => setIsModalActive(true)} onClick={() => setIsModalActive(true)}
/> />
@ -114,13 +120,9 @@ const Matter_typesTablesPage = () => {
<div className='md:inline-flex items-center ms-auto'> <div className='md:inline-flex items-center ms-auto'>
<div id='delete-rows-button'></div> <div id='delete-rows-button'></div>
<Link href={'/matter_types/matter_types-list'}>
Back to <span className='capitalize'>list</span>
</Link>
</div> </div>
</CardBox> <BaseButton href={'/matter_types/matter_types-list'} color='whiteDark' label='Card view'/>
</LegalOpsPageIntro>
<CardBox className="mb-6" hasTable> <CardBox className="mb-6" hasTable>
<TableMatter_types <TableMatter_types
filterItems={filterItems} filterItems={filterItems}

View File

@ -29,11 +29,6 @@ const Matter_typesView = () => {
const { id } = router.query; const { id } = router.query;
function removeLastCharacter(str) {
console.log(str,`str`)
return str.slice(0, -1);
}
useEffect(() => { useEffect(() => {
dispatch(fetch({ id })); dispatch(fetch({ id }));
}, [dispatch, id]); }, [dispatch, id]);
@ -42,10 +37,10 @@ const Matter_typesView = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('View matter_types')}</title> <title>{getPageTitle('Matter type details')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={removeLastCharacter('View matter_types')} main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Matter type details" main>
<BaseButton <BaseButton
color='info' color='info'
label='Edit' label='Edit'
@ -57,7 +52,7 @@ const Matter_typesView = () => {
<div className={'mb-4'}> <div className={'mb-4'}>
<p className={'block font-bold mb-2'}>MatterType</p> <p className={'block font-bold mb-2'}>Matter type</p>
<p>{matter_types?.name}</p> <p>{matter_types?.name}</p>
</div> </div>
@ -163,7 +158,7 @@ const Matter_typesView = () => {
<> <>
<p className={'block font-bold mb-2'}>Ai_use_cases MatterType</p> <p className={'block font-bold mb-2'}>AI use cases</p>
<CardBox <CardBox
className='mb-6 border border-gray-300 rounded overflow-hidden' className='mb-6 border border-gray-300 rounded overflow-hidden'
hasTable hasTable
@ -310,7 +305,7 @@ const Matter_typesView = () => {
<> <>
<p className={'block font-bold mb-2'}>Workflow_runs MatterType</p> <p className={'block font-bold mb-2'}>Workflow runs</p>
<CardBox <CardBox
className='mb-6 border border-gray-300 rounded overflow-hidden' className='mb-6 border border-gray-300 rounded overflow-hidden'
hasTable hasTable
@ -456,4 +451,4 @@ Matter_typesView.getLayout = function getLayout(page: ReactElement) {
) )
} }
export default Matter_typesView; export default Matter_typesView;

View File

@ -133,10 +133,10 @@ const EditRoles_catalog = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Edit roles_catalog')}</title> <title>{getPageTitle('Edit governance role')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit roles_catalog'} main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit governance role'} main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
@ -150,11 +150,11 @@ const EditRoles_catalog = () => {
<FormField <FormField
label="RoleName" label="Role name"
> >
<Field <Field
name="name" name="name"
placeholder="RoleName" placeholder="e.g. AI review owner, IT security approver"
/> />
</FormField> </FormField>

View File

@ -130,10 +130,10 @@ const EditRoles_catalogPage = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Edit roles_catalog')}</title> <title>{getPageTitle('Edit governance role')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit roles_catalog'} main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit governance role'} main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
@ -147,11 +147,11 @@ const EditRoles_catalogPage = () => {
<FormField <FormField
label="RoleName" label="Role name"
> >
<Field <Field
name="name" name="name"
placeholder="RoleName" placeholder="e.g. AI review owner, IT security approver"
/> />
</FormField> </FormField>

View File

@ -6,11 +6,11 @@ import CardBox from '../../components/CardBox'
import LayoutAuthenticated from '../../layouts/Authenticated' import LayoutAuthenticated from '../../layouts/Authenticated'
import SectionMain from '../../components/SectionMain' import SectionMain from '../../components/SectionMain'
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
import LegalOpsPageIntro from '../../components/LegalOpsPageIntro'
import { getPageTitle } from '../../config' import { getPageTitle } from '../../config'
import TableRoles_catalog from '../../components/Roles_catalog/TableRoles_catalog' import TableRoles_catalog from '../../components/Roles_catalog/TableRoles_catalog'
import BaseButton from '../../components/BaseButton' import BaseButton from '../../components/BaseButton'
import axios from "axios"; import axios from "axios";
import Link from "next/link";
import {useAppDispatch, useAppSelector} from "../../stores/hooks"; import {useAppDispatch, useAppSelector} from "../../stores/hooks";
import CardBoxModal from "../../components/CardBoxModal"; import CardBoxModal from "../../components/CardBoxModal";
import DragDropFilePicker from "../../components/DragDropFilePicker"; import DragDropFilePicker from "../../components/DragDropFilePicker";
@ -34,7 +34,7 @@ const Roles_catalogTablesPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [filters] = useState([{label: 'RoleName', title: 'name'},{label: 'Description', title: 'description'}, const [filters] = useState([{label: 'Role name', title: 'name'},{label: 'Description', title: 'description'},
@ -86,27 +86,35 @@ const Roles_catalogTablesPage = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Roles_catalog')}</title> <title>{getPageTitle('Roles catalog')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Roles_catalog" main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Roles catalog" main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox className='mb-6' cardBoxClassName='flex flex-wrap'> <LegalOpsPageIntro
eyebrow='Governance ownership'
title='Define accountable roles for AI approvals and oversight'
description='Maintain the role catalog that describes who can approve use cases, review AI outputs, own vendors, and monitor compliance workflows.'
metrics={[
{ label: 'Ownership', value: 'Named role', helper: 'Clear roles keep AI approvals and escalations accountable.' },
{ label: 'Workflow fit', value: 'Approval paths', helper: 'Requests can be routed through the right legal, IT, risk, or business owners.' },
{ label: 'Audit posture', value: 'Defensible record', helper: 'Role definitions make governance decisions easier to explain.' },
]}
>
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/roles_catalog/roles_catalog-new'} color='info' label='New Item'/>} {hasCreatePermission && <BaseButton href={'/roles_catalog/roles_catalog-new'} color='info' label='New role'/>}
<BaseButton <BaseButton
className={'mr-3'}
color='info' color='info'
label='Filter' label='Add filter'
onClick={addFilter} onClick={addFilter}
/> />
<BaseButton className={'mr-3'} color='info' label='Download CSV' onClick={getRoles_catalogCSV} /> <BaseButton color='whiteDark' label='Export CSV' onClick={getRoles_catalogCSV} />
{hasCreatePermission && ( {hasCreatePermission && (
<BaseButton <BaseButton
color='info' color='whiteDark'
label='Upload CSV' label='Upload CSV'
onClick={() => setIsModalActive(true)} onClick={() => setIsModalActive(true)}
/> />
@ -116,11 +124,9 @@ const Roles_catalogTablesPage = () => {
<div id='delete-rows-button'></div> <div id='delete-rows-button'></div>
</div> </div>
<div className='md:inline-flex items-center ms-auto'> <BaseButton href={'/roles_catalog/roles_catalog-table'} color='whiteDark' label='Table view'/>
<Link href={'/roles_catalog/roles_catalog-table'}>Switch to Table</Link>
</div>
</CardBox> </LegalOpsPageIntro>
<CardBox className="mb-6" hasTable> <CardBox className="mb-6" hasTable>
<TableRoles_catalog <TableRoles_catalog

View File

@ -78,10 +78,10 @@ const Roles_catalogNew = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('New Item')}</title> <title>{getPageTitle('New governance role')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New Item" main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New governance role" main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox> <CardBox>
@ -98,11 +98,11 @@ const Roles_catalogNew = () => {
<FormField <FormField
label="RoleName" label="Role name"
> >
<Field <Field
name="name" name="name"
placeholder="RoleName" placeholder="e.g. AI review owner, IT security approver"
/> />
</FormField> </FormField>

View File

@ -6,11 +6,11 @@ import CardBox from '../../components/CardBox'
import LayoutAuthenticated from '../../layouts/Authenticated' import LayoutAuthenticated from '../../layouts/Authenticated'
import SectionMain from '../../components/SectionMain' import SectionMain from '../../components/SectionMain'
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton' import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
import LegalOpsPageIntro from '../../components/LegalOpsPageIntro'
import { getPageTitle } from '../../config' import { getPageTitle } from '../../config'
import TableRoles_catalog from '../../components/Roles_catalog/TableRoles_catalog' import TableRoles_catalog from '../../components/Roles_catalog/TableRoles_catalog'
import BaseButton from '../../components/BaseButton' import BaseButton from '../../components/BaseButton'
import axios from "axios"; import axios from "axios";
import Link from "next/link";
import {useAppDispatch, useAppSelector} from "../../stores/hooks"; import {useAppDispatch, useAppSelector} from "../../stores/hooks";
import CardBoxModal from "../../components/CardBoxModal"; import CardBoxModal from "../../components/CardBoxModal";
import DragDropFilePicker from "../../components/DragDropFilePicker"; import DragDropFilePicker from "../../components/DragDropFilePicker";
@ -34,7 +34,7 @@ const Roles_catalogTablesPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [filters] = useState([{label: 'RoleName', title: 'name'},{label: 'Description', title: 'description'}, const [filters] = useState([{label: 'Role name', title: 'name'},{label: 'Description', title: 'description'},
@ -86,27 +86,35 @@ const Roles_catalogTablesPage = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('Roles_catalog')}</title> <title>{getPageTitle('Roles catalog table')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Roles_catalog" main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Roles catalog table" main>
{''} {''}
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
<CardBox className='mb-6' cardBoxClassName='flex flex-wrap'> <LegalOpsPageIntro
eyebrow='Governance ownership'
title='Roles catalog as an editable governance table'
description='Use table view to scan and update the role definitions that support AI approval routing, review ownership, and compliance accountability.'
metrics={[
{ label: 'View mode', value: 'Table', helper: 'Best for quick role cleanup and CSV-quality review.' },
{ label: 'Ownership', value: 'Role name', helper: 'Role names give workflow approvals a clear accountable owner.' },
{ label: 'Audit posture', value: 'Documented', helper: 'Descriptions explain why each role exists in governance workflows.' },
]}
>
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/roles_catalog/roles_catalog-new'} color='info' label='New Item'/>} {hasCreatePermission && <BaseButton href={'/roles_catalog/roles_catalog-new'} color='info' label='New role'/>}
<BaseButton <BaseButton
className={'mr-3'}
color='info' color='info'
label='Filter' label='Add filter'
onClick={addFilter} onClick={addFilter}
/> />
<BaseButton className={'mr-3'} color='info' label='Download CSV' onClick={getRoles_catalogCSV} /> <BaseButton color='whiteDark' label='Export CSV' onClick={getRoles_catalogCSV} />
{hasCreatePermission && ( {hasCreatePermission && (
<BaseButton <BaseButton
color='info' color='whiteDark'
label='Upload CSV' label='Upload CSV'
onClick={() => setIsModalActive(true)} onClick={() => setIsModalActive(true)}
/> />
@ -114,13 +122,9 @@ const Roles_catalogTablesPage = () => {
<div className='md:inline-flex items-center ms-auto'> <div className='md:inline-flex items-center ms-auto'>
<div id='delete-rows-button'></div> <div id='delete-rows-button'></div>
<Link href={'/roles_catalog/roles_catalog-list'}>
Back to <span className='capitalize'>list</span>
</Link>
</div> </div>
</CardBox> <BaseButton href={'/roles_catalog/roles_catalog-list'} color='whiteDark' label='Card view'/>
</LegalOpsPageIntro>
<CardBox className="mb-6" hasTable> <CardBox className="mb-6" hasTable>
<TableRoles_catalog <TableRoles_catalog
filterItems={filterItems} filterItems={filterItems}

View File

@ -29,11 +29,6 @@ const Roles_catalogView = () => {
const { id } = router.query; const { id } = router.query;
function removeLastCharacter(str) {
console.log(str,`str`)
return str.slice(0, -1);
}
useEffect(() => { useEffect(() => {
dispatch(fetch({ id })); dispatch(fetch({ id }));
}, [dispatch, id]); }, [dispatch, id]);
@ -42,10 +37,10 @@ const Roles_catalogView = () => {
return ( return (
<> <>
<Head> <Head>
<title>{getPageTitle('View roles_catalog')}</title> <title>{getPageTitle('Governance role details')}</title>
</Head> </Head>
<SectionMain> <SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={removeLastCharacter('View roles_catalog')} main> <SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Governance role details" main>
<BaseButton <BaseButton
color='info' color='info'
label='Edit' label='Edit'
@ -57,7 +52,7 @@ const Roles_catalogView = () => {
<div className={'mb-4'}> <div className={'mb-4'}>
<p className={'block font-bold mb-2'}>RoleName</p> <p className={'block font-bold mb-2'}>Role name</p>
<p>{roles_catalog?.name}</p> <p>{roles_catalog?.name}</p>
</div> </div>
@ -90,7 +85,7 @@ const Roles_catalogView = () => {
<FormField label='Multi Text' hasTextareaHeight> <FormField label='Description' hasTextareaHeight>
<textarea className={'w-full'} disabled value={roles_catalog?.description} /> <textarea className={'w-full'} disabled value={roles_catalog?.description} />
</FormField> </FormField>
@ -132,7 +127,7 @@ const Roles_catalogView = () => {
<> <>
<p className={'block font-bold mb-2'}>Human_review_checklists RequiredReviewerRole</p> <p className={'block font-bold mb-2'}>Human review checklists</p>
<CardBox <CardBox
className='mb-6 border border-gray-300 rounded overflow-hidden' className='mb-6 border border-gray-300 rounded overflow-hidden'
hasTable hasTable
@ -291,4 +286,4 @@ Roles_catalogView.getLayout = function getLayout(page: ReactElement) {
) )
} }
export default Roles_catalogView; export default Roles_catalogView;

View File

@ -56,31 +56,68 @@ export const white: StyleObject = {
export const dataGridStyles = { export const dataGridStyles = {
'& .MuiDataGrid-cell': { '& .MuiDataGrid-cell': {
paddingX: 3, alignItems: 'center',
borderColor: '#E5E0D6', borderColor: '#E5E0D6',
color: '#374151', color: '#374151',
display: 'flex',
fontSize: '0.9rem',
lineHeight: 1.25,
padding: '8px 18px',
whiteSpace: 'nowrap',
}, },
'& .MuiDataGrid-columnHeader': { '& .MuiDataGrid-columnHeader': {
paddingX: 3, minHeight: '58px !important',
padding: '10px 18px',
color: '#0E1A2B', color: '#0E1A2B',
fontWeight: 700, fontWeight: 700,
}, },
'& .MuiDataGrid-columnHeaderCheckbox': { '& .MuiDataGrid-columnHeaderCheckbox': {
paddingX: 0, paddingX: 1.5,
}, },
'& .MuiDataGrid-columnHeaders': { '& .MuiDataGrid-columnHeaders': {
paddingY: 4, minHeight: '58px !important',
maxHeight: 'unset !important',
borderStartStartRadius: 7, borderStartStartRadius: 7,
borderStartEndRadius: 7, borderStartEndRadius: 7,
backgroundColor: '#FBF8F1', backgroundColor: '#FBF8F1',
borderColor: '#DDD5C7', borderColor: '#DDD5C7',
}, },
'& .MuiDataGrid-columnHeaderTitle': {
color: '#0E1A2B',
fontSize: '0.72rem',
fontWeight: 800,
letterSpacing: '0.07em',
lineHeight: 1.15,
overflow: 'visible',
textOverflow: 'clip',
textTransform: 'uppercase',
whiteSpace: 'normal',
wordBreak: 'normal',
},
'& .MuiDataGrid-columnHeaderTitleContainer': {
overflow: 'visible',
whiteSpace: 'normal',
},
'& .MuiDataGrid-columnHeaderTitleContainerContent': {
minWidth: 0,
overflow: 'visible',
},
'& .MuiDataGrid-cellContent': {
display: 'block',
lineHeight: 1.25,
maxWidth: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
wordBreak: 'normal',
},
'& .MuiDataGrid-footerContainer': { '& .MuiDataGrid-footerContainer': {
paddingY: 0.5, paddingY: 0.5,
borderEndStartRadius: 7, borderEndStartRadius: 7,
borderEndEndRadius: 7, borderEndEndRadius: 7,
borderColor: '#DDD5C7', borderColor: '#DDD5C7',
backgroundColor: '#FBF8F1', backgroundColor: '#FBF8F1',
minHeight: '60px',
}, },
'& .MuiDataGrid-root': { '& .MuiDataGrid-root': {
border: '1px solid #DDD5C7', border: '1px solid #DDD5C7',
@ -88,9 +125,27 @@ export const dataGridStyles = {
overflow: 'hidden', overflow: 'hidden',
backgroundColor: '#FFFFFF', backgroundColor: '#FFFFFF',
}, },
'& .MuiDataGrid-row': {
borderColor: '#E5E0D6',
},
'& .MuiDataGrid-row.Mui-selected': {
backgroundColor: '#FFF3C9',
},
'& .MuiDataGrid-row.Mui-selected:hover': {
backgroundColor: '#FFEDB1',
},
'& .MuiDataGrid-row:hover': { '& .MuiDataGrid-row:hover': {
backgroundColor: '#FFF8E8', backgroundColor: '#FFF8E8',
}, },
'& .MuiDataGrid-iconButtonContainer .MuiIconButton-root': {
color: '#7A5B13',
},
'& .MuiCheckbox-root': {
color: '#8B7A61',
},
'& .MuiCheckbox-root.Mui-checked': {
color: '#7A5B13',
},
}; };
export const basic: StyleObject = { export const basic: StyleObject = {