All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Introduced new EmailAccounts and EmailMessages components for managing email accounts and messages. - Implemented ObjectTable for displaying data with filtering and sorting capabilities. - Integrated InfoActionButtons for enhanced user interactions across various management functionalities. - Refactored existing components to replace DocumentPrintButton with InfoActionButtons for consistency in action handling. - Added EmailAccountInfo component for detailed view and management of individual email accounts.
387 lines
10 KiB
JavaScript
387 lines
10 KiB
JavaScript
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
|
|
}
|