BREAKING CHANGE
API and persisted records use PowerOnModel system fields: - sysCreatedAt, sysCreatedBy, sysModifiedAt, sysModifiedBy Removed legacy JSON/DB field names: - _createdAt, _createdBy, _modifiedAt, _modifiedBy Frontend (frontend_nyla) and gateway call sites were updated accordingly. Database: - Bootstrap runs idempotent backfill (_migrateSystemFieldColumns) from old underscore columns and selected business duplicates into sys* where sys* IS NULL. - Re-run app bootstrap against each PostgreSQL database after deploy. - Optional: DROP INDEX IF EXISTS "idx_invitation_createdby" if an old index remains; new index: idx_invitation_syscreatedby on Invitation(sysCreatedBy). Tests: - RBAC integration tests aligned with current GROUP mandate filter and UserMandate-based UserConnection GROUP clause; buildRbacWhereClause(..., mandateId=...) must be passed explicitly (same as production request context).
This commit is contained in:
parent
f5f6cad542
commit
77e7eba711
34 changed files with 89 additions and 89 deletions
|
|
@ -258,7 +258,7 @@ export interface Automation2Task {
|
||||||
result?: Record<string, unknown>;
|
result?: Record<string, unknown>;
|
||||||
/** Workflow label (enriched by API) */
|
/** Workflow label (enriched by API) */
|
||||||
workflowLabel?: string;
|
workflowLabel?: string;
|
||||||
/** Unix timestamp ms (from _createdAt) */
|
/** Unix timestamp ms (from sysCreatedAt) */
|
||||||
createdAt?: number;
|
createdAt?: number;
|
||||||
/** Optional due date - configurable in future */
|
/** Optional due date - configurable in future */
|
||||||
dueAt?: number;
|
dueAt?: number;
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ export interface Automation {
|
||||||
nextExecution?: number;
|
nextExecution?: number;
|
||||||
executionLogs?: AutomationLog[];
|
executionLogs?: AutomationLog[];
|
||||||
allowedProviders?: string[];
|
allowedProviders?: string[];
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_updatedAt?: number;
|
_updatedAt?: number;
|
||||||
_createdByUserName?: string;
|
sysCreatedByUserName?: string;
|
||||||
mandateName?: string;
|
mandateName?: string;
|
||||||
featureInstanceName?: string;
|
featureInstanceName?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
@ -48,9 +48,9 @@ export interface AutomationTemplate {
|
||||||
label: TextMultilingual;
|
label: TextMultilingual;
|
||||||
overview?: TextMultilingual;
|
overview?: TextMultilingual;
|
||||||
template: string; // JSON string with {{KEY:...}} placeholders
|
template: string; // JSON string with {{KEY:...}} placeholders
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_createdByUserName?: string;
|
sysCreatedByUserName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workflow action definition from backend
|
// Workflow action definition from backend
|
||||||
|
|
@ -301,7 +301,7 @@ export async function fetchAutomationTemplateById(
|
||||||
*/
|
*/
|
||||||
export async function createAutomationTemplateApi(
|
export async function createAutomationTemplateApi(
|
||||||
request: ApiRequestFunction,
|
request: ApiRequestFunction,
|
||||||
templateData: Omit<AutomationTemplate, 'id' | '_createdAt' | '_createdBy'>
|
templateData: Omit<AutomationTemplate, 'id' | 'sysCreatedAt' | 'sysCreatedBy'>
|
||||||
): Promise<AutomationTemplate> {
|
): Promise<AutomationTemplate> {
|
||||||
return await request({
|
return await request({
|
||||||
url: '/api/automation-templates',
|
url: '/api/automation-templates',
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export interface Prompt {
|
||||||
mandateId: string;
|
mandateId: string;
|
||||||
content: string;
|
content: string;
|
||||||
name: string;
|
name: string;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_hideDelete?: boolean;
|
_hideDelete?: boolean;
|
||||||
[key: string]: any; // Allow additional properties
|
[key: string]: any; // Allow additional properties
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ export interface RealEstateProject {
|
||||||
featureInstanceId?: string;
|
featureInstanceId?: string;
|
||||||
perimeter?: any;
|
perimeter?: any;
|
||||||
parzellen?: RealEstateParcel[];
|
parzellen?: RealEstateParcel[];
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,8 +38,8 @@ export interface RealEstateParcel {
|
||||||
plz?: string;
|
plz?: string;
|
||||||
perimeter?: any;
|
perimeter?: any;
|
||||||
bauzone?: string;
|
bauzone?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ export interface TrusteeOrganisation {
|
||||||
label: string;
|
label: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_modifiedBy?: string;
|
sysModifiedBy?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,10 +29,10 @@ export interface TrusteeRole {
|
||||||
id: string;
|
id: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_modifiedBy?: string;
|
sysModifiedBy?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,10 +43,10 @@ export interface TrusteeAccess {
|
||||||
userId: string;
|
userId: string;
|
||||||
contractId?: string | null;
|
contractId?: string | null;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_modifiedBy?: string;
|
sysModifiedBy?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,10 +56,10 @@ export interface TrusteeContract {
|
||||||
label: string;
|
label: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_modifiedBy?: string;
|
sysModifiedBy?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,10 +71,10 @@ export interface TrusteeDocument {
|
||||||
documentMimeType: string;
|
documentMimeType: string;
|
||||||
documentData?: any;
|
documentData?: any;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_modifiedBy?: string;
|
sysModifiedBy?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,10 +98,10 @@ export interface TrusteePosition {
|
||||||
costCenter?: string;
|
costCenter?: string;
|
||||||
bookingReference?: string;
|
bookingReference?: string;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
_createdBy?: string;
|
sysCreatedBy?: string;
|
||||||
_modifiedBy?: string;
|
sysModifiedBy?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -696,8 +696,8 @@ export interface TrusteePositionDocument {
|
||||||
documentId: string;
|
documentId: string;
|
||||||
mandateId?: string;
|
mandateId?: string;
|
||||||
featureInstanceId?: string;
|
featureInstanceId?: string;
|
||||||
_createdAt?: number;
|
sysCreatedAt?: number;
|
||||||
_modifiedAt?: number;
|
sysModifiedAt?: number;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ export function useMandates() {
|
||||||
return false; // Don't show readonly fields in edit form
|
return false; // Don't show readonly fields in edit form
|
||||||
}
|
}
|
||||||
// Also filter out common non-editable fields
|
// Also filter out common non-editable fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -305,7 +305,7 @@ export function useMandates() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter out ID fields and other auto-generated fields
|
// Filter out ID fields and other auto-generated fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ export function useRbacRoles() {
|
||||||
return false; // Don't show readonly fields in edit form
|
return false; // Don't show readonly fields in edit form
|
||||||
}
|
}
|
||||||
// Also filter out common non-editable fields
|
// Also filter out common non-editable fields
|
||||||
const nonEditableFields = ['id', 'roleId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'roleId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -346,7 +346,7 @@ export function useRbacRoles() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter out ID fields and other auto-generated fields
|
// Filter out ID fields and other auto-generated fields
|
||||||
const nonEditableFields = ['id', 'roleId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'roleId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ export function useRbacRules() {
|
||||||
return false; // Don't show readonly fields in edit form
|
return false; // Don't show readonly fields in edit form
|
||||||
}
|
}
|
||||||
// Also filter out common non-editable fields
|
// Also filter out common non-editable fields
|
||||||
const nonEditableFields = ['id', 'ruleId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'ruleId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -322,7 +322,7 @@ export function useRbacRules() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter out ID fields and other auto-generated fields
|
// Filter out ID fields and other auto-generated fields
|
||||||
const nonEditableFields = ['id', 'ruleId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'ruleId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -536,7 +536,7 @@ export function useAutomationTemplates() {
|
||||||
return await fetchAutomationTemplateById(request, templateId);
|
return await fetchAutomationTemplateById(request, templateId);
|
||||||
}, [request]);
|
}, [request]);
|
||||||
|
|
||||||
const createTemplate = useCallback(async (data: Omit<AutomationTemplate, 'id' | '_createdAt' | '_createdBy'>) => {
|
const createTemplate = useCallback(async (data: Omit<AutomationTemplate, 'id' | 'sysCreatedAt' | 'sysCreatedBy'>) => {
|
||||||
return await createAutomationTemplateApi(request, data);
|
return await createAutomationTemplateApi(request, data);
|
||||||
}, [request]);
|
}, [request]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,11 @@ export function useTablePermission(tableName: string) {
|
||||||
canDelete: hasAccess(permission.delete),
|
canDelete: hasAccess(permission.delete),
|
||||||
|
|
||||||
// Record-basierte Prüfungen
|
// Record-basierte Prüfungen
|
||||||
canReadRecord: (record: { _createdBy?: string }) =>
|
canReadRecord: (record: { sysCreatedBy?: string }) =>
|
||||||
canAccessRecord(permission.read, record, userId),
|
canAccessRecord(permission.read, record, userId),
|
||||||
canUpdateRecord: (record: { _createdBy?: string }) =>
|
canUpdateRecord: (record: { sysCreatedBy?: string }) =>
|
||||||
canAccessRecord(permission.update, record, userId),
|
canAccessRecord(permission.update, record, userId),
|
||||||
canDeleteRecord: (record: { _createdBy?: string }) =>
|
canDeleteRecord: (record: { sysCreatedBy?: string }) =>
|
||||||
canAccessRecord(permission.delete, record, userId),
|
canAccessRecord(permission.delete, record, userId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -296,7 +296,7 @@ export function useInstancePermissions(): InstancePermissions | undefined {
|
||||||
*/
|
*/
|
||||||
export function useCanEditRecord(
|
export function useCanEditRecord(
|
||||||
tableName: string,
|
tableName: string,
|
||||||
record: { _createdBy?: string } | undefined,
|
record: { sysCreatedBy?: string } | undefined,
|
||||||
userId: string
|
userId: string
|
||||||
): boolean {
|
): boolean {
|
||||||
const { update } = useTablePermission(tableName);
|
const { update } = useTablePermission(tableName);
|
||||||
|
|
@ -311,7 +311,7 @@ export function useCanEditRecord(
|
||||||
*/
|
*/
|
||||||
export function useCanDeleteRecord(
|
export function useCanDeleteRecord(
|
||||||
tableName: string,
|
tableName: string,
|
||||||
record: { _createdBy?: string } | undefined,
|
record: { sysCreatedBy?: string } | undefined,
|
||||||
userId: string
|
userId: string
|
||||||
): boolean {
|
): boolean {
|
||||||
const { delete: deleteLevel } = useTablePermission(tableName);
|
const { delete: deleteLevel } = useTablePermission(tableName);
|
||||||
|
|
@ -329,7 +329,7 @@ interface PermissionGateProps {
|
||||||
table?: string;
|
table?: string;
|
||||||
view?: string;
|
view?: string;
|
||||||
action?: 'view' | 'read' | 'create' | 'update' | 'delete';
|
action?: 'view' | 'read' | 'create' | 'update' | 'delete';
|
||||||
record?: { _createdBy?: string };
|
record?: { sysCreatedBy?: string };
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
fallback?: React.ReactNode;
|
fallback?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ export function usePrompts() {
|
||||||
return false; // Don't show readonly fields in edit form
|
return false; // Don't show readonly fields in edit form
|
||||||
}
|
}
|
||||||
// Also filter out common non-editable fields
|
// Also filter out common non-editable fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -367,7 +367,7 @@ export function usePrompts() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter out ID fields and other auto-generated fields
|
// Filter out ID fields and other auto-generated fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -530,7 +530,7 @@ export function usePromptOperations() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Pass all provided fields (supports partial inline updates like isSystem toggle)
|
// Pass all provided fields (supports partial inline updates like isSystem toggle)
|
||||||
const { id, mandateId, _createdBy, _createdAt, _modifiedAt, _permissions, ...requestBody } = updateData;
|
const { id, mandateId, sysCreatedBy, sysCreatedAt, sysModifiedAt, _permissions, ...requestBody } = updateData;
|
||||||
|
|
||||||
const updatedPrompt = await updatePromptApi(request, promptId, requestBody as UpdatePromptData);
|
const updatedPrompt = await updatePromptApi(request, promptId, requestBody as UpdatePromptData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ function _createRealEstateEntityHook<T extends { id: string }>(config: RealEstat
|
||||||
.filter(attr => {
|
.filter(attr => {
|
||||||
if (attr.readonly === true || attr.editable === false) return false;
|
if (attr.readonly === true || attr.editable === false) return false;
|
||||||
if (attr.name === 'id') return false;
|
if (attr.name === 'id') return false;
|
||||||
const nonEditable = ['_createdBy', '_createdAt', '_modifiedBy', '_modifiedAt'];
|
const nonEditable = ['sysCreatedBy', 'sysCreatedAt', 'sysModifiedBy', 'sysModifiedAt'];
|
||||||
return !nonEditable.includes(attr.name);
|
return !nonEditable.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -210,7 +210,7 @@ function _createRealEstateEntityHook<T extends { id: string }>(config: RealEstat
|
||||||
const generateCreateFieldsFromAttributes = useCallback(() => {
|
const generateCreateFieldsFromAttributes = useCallback(() => {
|
||||||
if (!attributes || attributes.length === 0) return [];
|
if (!attributes || attributes.length === 0) return [];
|
||||||
return attributes
|
return attributes
|
||||||
.filter(attr => !['_createdBy', '_createdAt', '_modifiedBy', '_modifiedAt', 'mandateId', 'featureInstanceId'].includes(attr.name))
|
.filter(attr => !['sysCreatedBy', 'sysCreatedAt', 'sysModifiedBy', 'sysModifiedAt', 'mandateId', 'featureInstanceId'].includes(attr.name))
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
let fieldType: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'multiselect' | 'readonly' | 'number' = 'string';
|
let fieldType: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'multiselect' | 'readonly' | 'number' = 'string';
|
||||||
let options: Array<{ value: string | number; label: string }> | undefined;
|
let options: Array<{ value: string | number; label: string }> | undefined;
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ function _createTrusteeEntityHook<T extends { id: string }>(config: TrusteeEntit
|
||||||
if (attr.name === 'id') {
|
if (attr.name === 'id') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['_createdBy', '_createdAt', '_modifiedBy', '_modifiedAt'];
|
const nonEditableFields = ['sysCreatedBy', 'sysCreatedAt', 'sysModifiedBy', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -284,7 +284,7 @@ function _createTrusteeEntityHook<T extends { id: string }>(config: TrusteeEntit
|
||||||
|
|
||||||
return attributes
|
return attributes
|
||||||
.filter(attr => {
|
.filter(attr => {
|
||||||
const systemFields = ['_createdBy', '_createdAt', '_modifiedBy', '_modifiedAt', 'mandateId'];
|
const systemFields = ['sysCreatedBy', 'sysCreatedAt', 'sysModifiedBy', 'sysModifiedAt', 'mandateId'];
|
||||||
return !systemFields.includes(attr.name);
|
return !systemFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ export function useTrusteeAccess() {
|
||||||
if (attr.readonly === true || attr.editable === false) {
|
if (attr.readonly === true || attr.editable === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['id', 'mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['id', 'mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ export function useTrusteeContracts() {
|
||||||
if (attr.readonly === true || attr.editable === false) {
|
if (attr.readonly === true || attr.editable === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['id', 'mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['id', 'mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ export function useTrusteeDocuments() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// documentData is handled separately (binary upload)
|
// documentData is handled separately (binary upload)
|
||||||
const nonEditableFields = ['id', 'documentData', 'mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['id', 'documentData', 'mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ export function useTrusteeOrganisations() {
|
||||||
if (attr.readonly === true || attr.editable === false) {
|
if (attr.readonly === true || attr.editable === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ export function useTrusteePositionDocuments() {
|
||||||
if (attr.readonly === true || attr.editable === false) {
|
if (attr.readonly === true || attr.editable === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['id', 'mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['id', 'mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ export function useTrusteePositions() {
|
||||||
if (attr.readonly === true || attr.editable === false) {
|
if (attr.readonly === true || attr.editable === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['id', 'mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['id', 'mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ export function useTrusteeRoles() {
|
||||||
if (attr.readonly === true || attr.editable === false) {
|
if (attr.readonly === true || attr.editable === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nonEditableFields = ['mandate', '_createdBy', '_modifiedBy', '_createdAt', '_modifiedAt'];
|
const nonEditableFields = ['mandate', 'sysCreatedBy', 'sysModifiedBy', 'sysCreatedAt', 'sysModifiedAt'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -412,7 +412,7 @@ export function useOrgUsers() {
|
||||||
return false; // Don't show readonly fields in edit form
|
return false; // Don't show readonly fields in edit form
|
||||||
}
|
}
|
||||||
// Also filter out common non-editable fields
|
// Also filter out common non-editable fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
@ -560,7 +560,7 @@ export function useOrgUsers() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter out ID fields and other auto-generated fields
|
// Filter out ID fields and other auto-generated fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete', 'authenticationAuthority'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete', 'authenticationAuthority'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ export function useUserWorkflows(options?: { instanceId?: string; featureCode?:
|
||||||
return false; // Don't show readonly fields in edit form
|
return false; // Don't show readonly fields in edit form
|
||||||
}
|
}
|
||||||
// Also filter out common non-editable fields
|
// Also filter out common non-editable fields
|
||||||
const nonEditableFields = ['id', 'mandateId', '_createdBy', '_hideDelete'];
|
const nonEditableFields = ['id', 'mandateId', 'sysCreatedBy', '_hideDelete'];
|
||||||
return !nonEditableFields.includes(attr.name);
|
return !nonEditableFields.includes(attr.name);
|
||||||
})
|
})
|
||||||
.map(attr => {
|
.map(attr => {
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ export const ConnectionsPage: React.FC = () => {
|
||||||
|
|
||||||
// Form attributes for edit modal
|
// Form attributes for edit modal
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excludedFields = ['id', 'mandateId', 'userId', '_createdBy', '_createdAt', '_modifiedAt', 'connectedAt', 'lastChecked'];
|
const excludedFields = ['id', 'mandateId', 'userId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'connectedAt', 'lastChecked'];
|
||||||
return (attributes || [])
|
return (attributes || [])
|
||||||
.filter(attr => !excludedFields.includes(attr.name));
|
.filter(attr => !excludedFields.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ export const FilesPage: React.FC = () => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cols.push({
|
cols.push({
|
||||||
key: '_createdBy',
|
key: 'sysCreatedBy',
|
||||||
label: 'Created By',
|
label: 'Created By',
|
||||||
type: 'text' as any,
|
type: 'text' as any,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
|
@ -289,7 +289,7 @@ export const FilesPage: React.FC = () => {
|
||||||
}, [selectedFolderId, _tableRefetch]);
|
}, [selectedFolderId, _tableRefetch]);
|
||||||
|
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excludedFields = ['id', 'mandateId', 'fileHash', '_createdBy', '_createdAt', '_modifiedAt', 'creationDate', 'source'];
|
const excludedFields = ['id', 'mandateId', 'fileHash', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'creationDate', 'source'];
|
||||||
return (attributes || []).filter(attr => !excludedFields.includes(attr.name));
|
return (attributes || []).filter(attr => !excludedFields.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ export const PromptsPage: React.FC = () => {
|
||||||
// Generate columns from attributes - exclude ID fields from display
|
// Generate columns from attributes - exclude ID fields from display
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
// Fields to hide in table view
|
// Fields to hide in table view
|
||||||
const hiddenColumns = ['id', 'mandateId', '_createdAt', '_modifiedAt', '_hideDelete', '_permissions'];
|
const hiddenColumns = ['id', 'mandateId', 'sysCreatedAt', 'sysModifiedAt', '_hideDelete', '_permissions'];
|
||||||
|
|
||||||
const cols = (attributes || [])
|
const cols = (attributes || [])
|
||||||
.filter(attr => !hiddenColumns.includes(attr.name))
|
.filter(attr => !hiddenColumns.includes(attr.name))
|
||||||
|
|
@ -71,9 +71,9 @@ export const PromptsPage: React.FC = () => {
|
||||||
fkDisplayField: (attr as any).fkDisplayField,
|
fkDisplayField: (attr as any).fkDisplayField,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Add _createdBy column with FK resolution to show username
|
// Add sysCreatedBy column with FK resolution to show username
|
||||||
cols.push({
|
cols.push({
|
||||||
key: '_createdBy',
|
key: 'sysCreatedBy',
|
||||||
label: 'Created By',
|
label: 'Created By',
|
||||||
type: 'text' as any,
|
type: 'text' as any,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
|
@ -148,7 +148,7 @@ export const PromptsPage: React.FC = () => {
|
||||||
|
|
||||||
// Form attributes for create/edit modal
|
// Form attributes for create/edit modal
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excludedFields = ['id', 'mandateId', 'isSystem', '_createdBy', '_createdAt', '_modifiedAt', '_hideDelete', '_permissions'];
|
const excludedFields = ['id', 'mandateId', 'isSystem', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', '_hideDelete', '_permissions'];
|
||||||
return (attributes || [])
|
return (attributes || [])
|
||||||
.filter(attr => !excludedFields.includes(attr.name));
|
.filter(attr => !excludedFields.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
|
||||||
|
|
@ -110,9 +110,9 @@ export const AutomationDefinitionsView: React.FC = () => {
|
||||||
|
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
const hiddenColumns = [
|
const hiddenColumns = [
|
||||||
'id', 'mandateId', 'featureInstanceId', '_createdBy', '_createdAt', '_modifiedAt',
|
'id', 'mandateId', 'featureInstanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt',
|
||||||
'template', 'executionLogs', 'placeholders',
|
'template', 'executionLogs', 'placeholders',
|
||||||
'_createdByUserName', 'mandateName', 'featureInstanceName',
|
'sysCreatedByUserName', 'mandateName', 'featureInstanceName',
|
||||||
];
|
];
|
||||||
const attrColumns = (attributes || [])
|
const attrColumns = (attributes || [])
|
||||||
.filter(attr => !hiddenColumns.includes(attr.name))
|
.filter(attr => !hiddenColumns.includes(attr.name))
|
||||||
|
|
@ -130,7 +130,7 @@ export const AutomationDefinitionsView: React.FC = () => {
|
||||||
const enrichedColumns = [
|
const enrichedColumns = [
|
||||||
{ key: 'mandateName', label: 'Mandant', type: 'text' as any, sortable: true, filterable: true, searchable: true, width: 150, minWidth: 100, maxWidth: 250 },
|
{ key: 'mandateName', label: 'Mandant', type: 'text' as any, sortable: true, filterable: true, searchable: true, width: 150, minWidth: 100, maxWidth: 250 },
|
||||||
{ key: 'featureInstanceName', label: 'Feature-Instanz', type: 'text' as any, sortable: true, filterable: true, searchable: true, width: 160, minWidth: 100, maxWidth: 250 },
|
{ key: 'featureInstanceName', label: 'Feature-Instanz', type: 'text' as any, sortable: true, filterable: true, searchable: true, width: 160, minWidth: 100, maxWidth: 250 },
|
||||||
{ key: '_createdByUserName', label: 'Erstellt von', type: 'text' as any, sortable: true, filterable: true, searchable: true, width: 150, minWidth: 100, maxWidth: 250 },
|
{ key: 'sysCreatedByUserName', label: 'Erstellt von', type: 'text' as any, sortable: true, filterable: true, searchable: true, width: 150, minWidth: 100, maxWidth: 250 },
|
||||||
];
|
];
|
||||||
return [...attrColumns, ...enrichedColumns];
|
return [...attrColumns, ...enrichedColumns];
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ export const AutomationTemplatesView: React.FC = () => {
|
||||||
value ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: '0.75rem', padding: '0.125rem 0.5rem', borderRadius: 10, background: 'var(--info-color, #3182ce)', color: '#fff' }}><FaLock style={{ fontSize: '0.625rem' }} /> System</span>
|
value ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: '0.75rem', padding: '0.125rem 0.5rem', borderRadius: 10, background: 'var(--info-color, #3182ce)', color: '#fff' }}><FaLock style={{ fontSize: '0.625rem' }} /> System</span>
|
||||||
: <span style={{ fontSize: '0.75rem', padding: '0.125rem 0.5rem', borderRadius: 10, background: 'var(--success-color, #38a169)', color: '#fff' }}>Instanz</span>
|
: <span style={{ fontSize: '0.75rem', padding: '0.125rem 0.5rem', borderRadius: 10, background: 'var(--success-color, #38a169)', color: '#fff' }}>Instanz</span>
|
||||||
},
|
},
|
||||||
{ key: '_createdByUserName', label: 'Erstellt von', type: 'string' as const, width: 150 },
|
{ key: 'sysCreatedByUserName', label: 'Erstellt von', type: 'string' as const, width: 150 },
|
||||||
], []);
|
], []);
|
||||||
|
|
||||||
const handleEditClick = async (template: AutomationTemplate) => {
|
const handleEditClick = async (template: AutomationTemplate) => {
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ export const RealEstateParcelsView: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excluded = ['id', 'mandateId', 'instanceId', '_createdBy', '_createdAt', '_modifiedAt', '_modifiedBy'];
|
const excluded = ['id', 'mandateId', 'instanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy'];
|
||||||
return (attributes || []).filter(attr => !excluded.includes(attr.name));
|
return (attributes || []).filter(attr => !excluded.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ export const RealEstateProjectsView: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excluded = ['id', 'mandateId', 'instanceId', '_createdBy', '_createdAt', '_modifiedAt', '_modifiedBy'];
|
const excluded = ['id', 'mandateId', 'instanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy'];
|
||||||
return (attributes || []).filter(attr => !excluded.includes(attr.name));
|
return (attributes || []).filter(attr => !excluded.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ export const TrusteeDocumentsView: React.FC = () => {
|
||||||
|
|
||||||
// Form attributes (exclude system fields)
|
// Form attributes (exclude system fields)
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excludedFields = ['id', 'mandateId', 'instanceId', '_createdBy', '_createdAt', '_modifiedAt', '_modifiedBy'];
|
const excludedFields = ['id', 'mandateId', 'instanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy'];
|
||||||
return (attributes || []).filter(attr => !excludedFields.includes(attr.name));
|
return (attributes || []).filter(attr => !excludedFields.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ export const TrusteePositionDocumentsView: React.FC = () => {
|
||||||
if (!attributes || attributes.length === 0) return [];
|
if (!attributes || attributes.length === 0) return [];
|
||||||
|
|
||||||
// Exclude system fields from table columns
|
// Exclude system fields from table columns
|
||||||
const excludedFields = ['id', 'mandateId', 'featureInstanceId', '_createdBy', '_createdAt', '_modifiedAt', '_modifiedBy'];
|
const excludedFields = ['id', 'mandateId', 'featureInstanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy'];
|
||||||
|
|
||||||
return attributes
|
return attributes
|
||||||
.filter((attr: any) => !excludedFields.includes(attr.name))
|
.filter((attr: any) => !excludedFields.includes(attr.name))
|
||||||
|
|
@ -127,7 +127,7 @@ export const TrusteePositionDocumentsView: React.FC = () => {
|
||||||
|
|
||||||
// Form attributes (exclude system fields)
|
// Form attributes (exclude system fields)
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excludedFields = ['id', 'mandateId', 'featureInstanceId', '_createdBy', '_createdAt', '_modifiedAt', '_modifiedBy'];
|
const excludedFields = ['id', 'mandateId', 'featureInstanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy'];
|
||||||
return (attributes || []).filter((attr: any) => !excludedFields.includes(attr.name));
|
return (attributes || []).filter((attr: any) => !excludedFields.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ export const TrusteePositionsView: React.FC = () => {
|
||||||
const positionColumnOrder = [
|
const positionColumnOrder = [
|
||||||
'_documentRefs', // Belege (download icons)
|
'_documentRefs', // Belege (download icons)
|
||||||
'_syncStatus', // Sync-Status
|
'_syncStatus', // Sync-Status
|
||||||
'_createdAt', // Erstellt am
|
'sysCreatedAt', // Erstellt am
|
||||||
'valuta', // Valuta date
|
'valuta', // Valuta date
|
||||||
'tags',
|
'tags',
|
||||||
'company',
|
'company',
|
||||||
|
|
@ -372,7 +372,7 @@ export const TrusteePositionsView: React.FC = () => {
|
||||||
|
|
||||||
// Form attributes (exclude system fields)
|
// Form attributes (exclude system fields)
|
||||||
const formAttributes = useMemo(() => {
|
const formAttributes = useMemo(() => {
|
||||||
const excludedFields = ['id', 'mandateId', 'instanceId', '_createdBy', '_createdAt', '_modifiedAt', '_modifiedBy'];
|
const excludedFields = ['id', 'mandateId', 'instanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy'];
|
||||||
return (attributes || []).filter(attr => !excludedFields.includes(attr.name));
|
return (attributes || []).filter(attr => !excludedFields.includes(attr.name));
|
||||||
}, [attributes]);
|
}, [attributes]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const NeutralizationPanel: React.FC<NeutralizationPanelProps> = ({ instanceId })
|
||||||
patternType: m.patternType || 'unknown',
|
patternType: m.patternType || 'unknown',
|
||||||
fileId: m.fileId,
|
fileId: m.fileId,
|
||||||
fileName: m.fileName,
|
fileName: m.fileName,
|
||||||
createdAt: m.createdAt || m._createdAt,
|
createdAt: m.createdAt || m.sysCreatedAt,
|
||||||
})));
|
})));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to load mappings:', err);
|
console.error('Failed to load mappings:', err);
|
||||||
|
|
|
||||||
|
|
@ -322,14 +322,14 @@ export function hasAccess(level: AccessLevel): boolean {
|
||||||
*/
|
*/
|
||||||
export function canAccessRecord(
|
export function canAccessRecord(
|
||||||
level: AccessLevel,
|
level: AccessLevel,
|
||||||
record: { _createdBy?: string },
|
record: { sysCreatedBy?: string },
|
||||||
userId: string
|
userId: string
|
||||||
): boolean {
|
): boolean {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 'n':
|
case 'n':
|
||||||
return false;
|
return false;
|
||||||
case 'm':
|
case 'm':
|
||||||
return record._createdBy === userId;
|
return record.sysCreatedBy === userId;
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'a':
|
case 'a':
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue