import { Printer } from './models/Printer.js' import { PrinterProfile } from './models/PrinterProfile.js' import { FilamentProfile } from './models/FilamentProfile.js' import { Host } from './models/Host.js' import { Filament } from './models/Filament.js' import { Material } from './models/Material.js' import { FilamentSku } from './models/FilamentSku.js' import { Spool } from './models/Spool' import { GCodeFile } from './models/GCodeFile' import { Job } from './models/Job' import { Product } from './models/Product' import { ProductCategory } from './models/ProductCategory' import { ProductSku } from './models/ProductSku' import { Part } from './models/Part.js' import { PartSku } from './models/PartSku.js' import { Vendor } from './models/Vendor' import { Courier } from './models/Courier' import { CourierService } from './models/CourierService' import { File } from './models/File' import { SubJob } from './models/SubJob' import { Initial } from './models/Initial' import { FilamentStock } from './models/FilamentStock' import { StockEvent } from './models/StockEvent' import { StockAudit } from './models/StockAudit' import { StockAuditLevel } from './models/StockAuditLevel' import { PartStock } from './models/PartStock' import { ProductStock } from './models/ProductStock' import { StockLocation } from './models/StockLocation' import { StockTransfer } from './models/StockTransfer' import { PurchaseOrder } from './models/PurchaseOrder' import { OrderItem } from './models/OrderItem' import { Shipment } from './models/Shipment' import { AuditLog } from './models/AuditLog' import { User } from './models/User' import { UserGroup } from './models/UserGroup.js' import { PermissionSetting } from './models/PermissionSetting.js' import { AppPassword } from './models/AppPassword.js' import { NoteType } from './models/NoteType' import { Note } from './models/Note' import { DocumentSize } from './models/DocumentSize.js' import { DocumentTemplate } from './models/DocumentTemplate.js' import { DocumentPrinter } from './models/DocumentPrinter.js' import { DocumentJob } from './models/DocumentJob.js' import { EmailAccount } from './models/EmailAccount.js' import { EmailTemplate } from './models/EmailTemplate.js' import { EmailMessage } from './models/EmailMessage.js' import { TaxRate } from './models/TaxRate.js' import { TaxRecord } from './models/TaxRecord.js' import { Invoice } from './models/Invoice.js' import { Payment } from './models/Payment.js' import { Client } from './models/Client.js' import { SalesOrder } from './models/SalesOrder.js' import { Marketplace } from './models/Marketplace.js' import { Listing } from './models/Listing.js' import { ListingVarient } from './models/ListingVarient.js' import { FulfillmentPolicy } from './models/FulfillmentPolicy.js' import { ReturnPolicy } from './models/ReturnPolicy.js' import { PaymentPolicy } from './models/PaymentPolicy.js' import QuestionCircleIcon from '../components/Icons/QuestionCircleIcon' export const objectModels = [ Printer, PrinterProfile, FilamentProfile, Host, Filament, FilamentSku, Material, Spool, GCodeFile, Job, Product, ProductCategory, ProductSku, Part, PartSku, Vendor, Courier, CourierService, File, SubJob, Initial, FilamentStock, StockEvent, StockAudit, StockAuditLevel, PartStock, ProductStock, StockLocation, StockTransfer, PurchaseOrder, OrderItem, Shipment, AuditLog, User, UserGroup, PermissionSetting, AppPassword, NoteType, Note, DocumentSize, DocumentTemplate, DocumentPrinter, DocumentJob, EmailAccount, EmailTemplate, EmailMessage, TaxRate, TaxRecord, Invoice, Payment, Client, SalesOrder, Marketplace, Listing, ListingVarient, FulfillmentPolicy, ReturnPolicy, PaymentPolicy ] // Re-export individual models for direct access export { Printer, PrinterProfile, FilamentProfile, Host, Filament, FilamentSku, Material, Spool, GCodeFile, Job, Product, ProductCategory, ProductSku, Part, PartSku, Vendor, Courier, CourierService, File, SubJob, Initial, FilamentStock, StockEvent, StockAudit, StockAuditLevel, PartStock, ProductStock, StockLocation, StockTransfer, PurchaseOrder, OrderItem, Shipment, AuditLog, User, UserGroup, PermissionSetting, AppPassword, NoteType, Note, DocumentSize, DocumentTemplate, DocumentPrinter, DocumentJob, EmailAccount, EmailTemplate, EmailMessage, TaxRate, TaxRecord, Invoice, Payment, Client, SalesOrder, Marketplace, Listing, ListingVarient, FulfillmentPolicy, ReturnPolicy, PaymentPolicy } export function getModelByName(name, ignoreCase = false) { function formatName(formattedName) { if (ignoreCase == true) { formattedName = formattedName.toUpperCase() } return formattedName } return ( objectModels.find((meta) => formatName(meta.name) === formatName(name)) || { name: 'unknown', label: 'Unknown', prefix: 'UNK', icon: QuestionCircleIcon, url: () => '#', properties: {} } ) } export function getModelByPluralName(pluralName, ignoreCase = false) { function formatName(formattedName) { if (ignoreCase == true) { formattedName = formattedName.toUpperCase().replaceAll(' ', '') } return formattedName } return ( objectModels.find( (meta) => formatName(meta.labelPlural) === formatName(pluralName) ) || { name: 'unknown', label: 'Unknown', prefix: 'UNK', icon: QuestionCircleIcon, url: () => '#', properties: {} } ) } export function getModelProperty(name, property) { const model = getModelByName(name) if (!model || !model.properties) { return undefined } return model.properties.find((prop) => prop.name == property) } export function getModelProperties(name, propertyList) { const model = getModelByName(name) if (!model || !model.properties) { return [] } // If no propertyList is provided, return all properties if (!propertyList || propertyList.length === 0) { return model.properties } // Create a map of property names to properties for efficient lookup const propertyMap = new Map( model.properties.map((property) => [property.name, property]) ) // Return properties in the same order as propertyList return propertyList .map((propertyName) => propertyMap.get(propertyName)) .filter((property) => property !== undefined) } export function getModelByPrefix(prefix) { return ( objectModels.find((meta) => meta.prefix === prefix) || { name: 'unknown', label: 'Unknown', prefix: 'UNK', icon: QuestionCircleIcon, url: () => '#', properties: {} } ) } export function searchModelsByLabel(label) { return objectModels.filter( (meta) => meta.label.toLowerCase().includes(label.toLowerCase()) || meta.labelPlural.toLowerCase().includes(label.toLowerCase()) ) } const HIDDEN_PERMISSION_ACTIONS = new Set(['cancelEdit', 'finishEdit']) export function getPermissionMatrixModels() { return objectModels.filter((model) => model?.name && model.name !== 'unknown') } export function getPermissionMatrixActions() { const seen = new Map() getPermissionMatrixModels().forEach((model) => { ;(model.actions || []).forEach((action) => { if (!action?.name || action.type === 'divider') return if (HIDDEN_PERMISSION_ACTIONS.has(action.name)) return if (action.type === 'alias' || action.type === 'callback') return if (!seen.has(action.name)) { seen.set(action.name, { name: action.name, type: action.type, label: action.name === 'new' ? 'New' : action.name === 'list' ? 'List' : action.label || action.name }) } }) }) return [...seen.values()] } export function modelHasPermissionAction(model, actionName) { return (model?.actions || []).some( (action) => action?.name === actionName && action.type !== 'divider' && action.type !== 'alias' && action.type !== 'callback' ) } // Utility function to get nested object values export const getPropertyValue = (obj, path) => { if (!obj || !path) return undefined if (path.includes('.')) { const propertyPath = path.split('.') let currentValue = obj for (const prop of propertyPath) { if (currentValue && typeof currentValue === 'object') { currentValue = currentValue[prop] } else { currentValue = undefined break } } return currentValue } else { return obj[path] } } export const evaluateVariable = (expression, data) => { if (!expression) return false // Only treat as an expression if it starts and ends with () const expr = expression.trim() if (!(expr.startsWith('(') && expr.endsWith(')'))) return false // Remove the outer parentheses const innerExpr = expr.slice(1, -1) // Helper to evaluate a single condition like 'foo == "bar"' or 'foo.bar == 42' or 'foo == true' const evalCondition = (cond, data) => { const match = cond.trim().match(/^([a-zA-Z0-9_.]+)\s*==\s*(.+)$/) if (!match) return false const [, path, valueRaw] = match let value let raw = valueRaw.trim() // Check for quoted string if ( (raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'")) ) { value = raw.slice(1, -1) } else if (raw === 'true') { value = true } else if (raw === 'false') { value = false } else if (!isNaN(Number(raw))) { value = Number(raw) } else { value = raw } // Resolve nested property const propValue = path .split('.') .reduce((acc, key) => (acc ? acc[key] : undefined), data) return propValue === value } // Split by '||' first (lowest precedence) const orParts = innerExpr.split(/\|\|/) for (let orPart of orParts) { // Each orPart may have '&&' (higher precedence) const andParts = orPart.split(/&&/) const andResult = andParts.every((andPart) => evalCondition(andPart, data)) if (andResult) return true // If any OR group is true, return true } return false // None of the OR groups were true }