diff --git a/src/codemirror/fcTemplateLang/index.js b/src/codemirror/fcTemplateLang/index.js
index d397375e..f79b6741 100644
--- a/src/codemirror/fcTemplateLang/index.js
+++ b/src/codemirror/fcTemplateLang/index.js
@@ -8,11 +8,8 @@ import {
} from '@codemirror/language'
import { styleTags, tags as t } from '@lezer/highlight'
import { parseMixed } from '@lezer/common'
-import {
- javascriptLanguage,
- scopeCompletionSource,
- localCompletionSource
-} from '@codemirror/lang-javascript'
+import { javascriptLanguage } from '@codemirror/lang-javascript'
+import { javascriptCompletionSources } from '../javascriptLang'
import {
xmlLanguage,
completeFromSchema,
@@ -109,7 +106,7 @@ export function fcTemplateLang(options = {}) {
}),
autoCloseTags,
javascriptLanguage.data.of({
- autocomplete: [localCompletionSource, scopeCompletionSource(jsScope)]
+ autocomplete: javascriptCompletionSources(jsScope)
})
])
}
diff --git a/src/codemirror/javascriptLang/index.js b/src/codemirror/javascriptLang/index.js
new file mode 100644
index 00000000..89980e57
--- /dev/null
+++ b/src/codemirror/javascriptLang/index.js
@@ -0,0 +1,60 @@
+import { completeFromList } from '@codemirror/autocomplete'
+import {
+ javascript,
+ javascriptLanguage,
+ localCompletionSource,
+ scopeCompletionSource,
+ snippets
+} from '@codemirror/lang-javascript'
+import { nodeJsScope } from './nodeScope.js'
+
+function extraScope(autoCompleteObject) {
+ let data = autoCompleteObject
+ if (typeof data === 'string') {
+ try {
+ data = JSON.parse(data)
+ } catch {
+ data = {}
+ }
+ }
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
+ return {}
+ }
+ return data
+}
+
+export function nodeScopeCompletionSource(autoCompleteObject) {
+ return scopeCompletionSource({
+ ...nodeJsScope,
+ ...extraScope(autoCompleteObject)
+ })
+}
+
+/**
+ * Completions for mixed languages that mount `javascriptLanguage`
+ * without `javascript()` (snippets + locals + Node globals).
+ */
+export function javascriptCompletionSources(autoCompleteObject) {
+ return [
+ completeFromList(snippets),
+ localCompletionSource,
+ nodeScopeCompletionSource(autoCompleteObject)
+ ]
+}
+
+/**
+ * JavaScript language support with Node.js globals, snippets, and
+ * local-variable completion.
+ * @param {{ autoCompleteObject?: object|string }} [options]
+ */
+export function javascriptLang(options = {}) {
+ const { autoCompleteObject } = options
+ return [
+ javascript(),
+ javascriptLanguage.data.of({
+ autocomplete: nodeScopeCompletionSource(autoCompleteObject)
+ })
+ ]
+}
+
+export { nodeJsScope }
diff --git a/src/codemirror/javascriptLang/nodeScope.js b/src/codemirror/javascriptLang/nodeScope.js
new file mode 100644
index 00000000..fca44de0
--- /dev/null
+++ b/src/codemirror/javascriptLang/nodeScope.js
@@ -0,0 +1,200 @@
+/** No-op used so Node APIs enumerate as functions in completions. */
+function fn() {}
+
+const streamLike = {
+ write: fn,
+ end: fn,
+ cork: fn,
+ uncork: fn,
+ on: fn,
+ once: fn,
+ off: fn,
+ emit: fn,
+ pipe: fn,
+ isTTY: false
+}
+
+const nodeProcess = {
+ env: {},
+ argv: ['node'],
+ argv0: 'node',
+ execArgv: [],
+ execPath: '',
+ cwd: fn,
+ chdir: fn,
+ exit: fn,
+ exitCode: 0,
+ nextTick: fn,
+ pid: 0,
+ ppid: 0,
+ platform: 'linux',
+ arch: 'x64',
+ version: 'v20.0.0',
+ versions: { node: '20.0.0' },
+ title: 'node',
+ stdout: streamLike,
+ stderr: { ...streamLike },
+ stdin: { on: fn, once: fn, read: fn, isTTY: false },
+ hrtime: Object.assign(fn, { bigint: fn }),
+ uptime: fn,
+ memoryUsage: fn,
+ cpuUsage: fn,
+ resourceUsage: fn,
+ abort: fn,
+ kill: fn,
+ getuid: fn,
+ getgid: fn,
+ setuid: fn,
+ setgid: fn,
+ umask: fn,
+ binding: fn,
+ dlopen: fn,
+ features: {},
+ config: {},
+ release: { name: 'node' }
+}
+
+const BufferStub = Object.assign(fn, {
+ from: fn,
+ alloc: fn,
+ allocUnsafe: fn,
+ allocUnsafeSlow: fn,
+ concat: fn,
+ isBuffer: fn,
+ isEncoding: fn,
+ byteLength: fn,
+ compare: fn,
+ prototype: {}
+})
+
+const requireFn = Object.assign(fn, {
+ resolve: Object.assign(fn, { paths: fn }),
+ cache: {},
+ extensions: {},
+ main: {}
+})
+
+/**
+ * Scope object for CodeMirror `scopeCompletionSource`.
+ * Browser-only globals (`window`, `document`, …) are omitted.
+ */
+export function createNodeJsScope() {
+ const scope = {
+ process: nodeProcess,
+ Buffer: BufferStub,
+ require: requireFn,
+ module: {
+ exports: {},
+ require: requireFn,
+ id: '.',
+ filename: '',
+ dirname: '',
+ paths: [],
+ loaded: false,
+ children: [],
+ parent: null
+ },
+ exports: {},
+ __dirname: '',
+ __filename: '',
+ console,
+ setTimeout,
+ clearTimeout,
+ setInterval,
+ clearInterval,
+ setImmediate: fn,
+ clearImmediate: fn,
+ queueMicrotask,
+ fetch,
+ URL,
+ URLSearchParams,
+ TextEncoder,
+ TextDecoder,
+ AbortController,
+ AbortSignal,
+ Event,
+ EventTarget,
+ Request,
+ Response,
+ Headers,
+ FormData,
+ Blob,
+ structuredClone,
+ performance,
+ crypto,
+ atob,
+ btoa,
+ WebAssembly,
+ Promise,
+ Map,
+ Set,
+ WeakMap,
+ WeakSet,
+ Array,
+ Object,
+ String,
+ Number,
+ Boolean,
+ Symbol,
+ BigInt,
+ Date,
+ RegExp,
+ Error,
+ TypeError,
+ RangeError,
+ SyntaxError,
+ URIError,
+ EvalError,
+ ReferenceError,
+ JSON,
+ Math,
+ Intl,
+ Proxy,
+ Reflect,
+ ArrayBuffer,
+ DataView,
+ Int8Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array,
+ BigInt64Array,
+ BigUint64Array,
+ Infinity,
+ NaN,
+ parseInt,
+ parseFloat,
+ isNaN,
+ isFinite,
+ encodeURI,
+ decodeURI,
+ encodeURIComponent,
+ decodeURIComponent,
+ eval,
+ Function
+ }
+
+ if (typeof File !== 'undefined') scope.File = File
+ if (typeof globalThis.WeakRef !== 'undefined') {
+ scope.WeakRef = globalThis.WeakRef
+ }
+ if (typeof globalThis.FinalizationRegistry !== 'undefined') {
+ scope.FinalizationRegistry = globalThis.FinalizationRegistry
+ }
+ if (typeof globalThis.AggregateError !== 'undefined') {
+ scope.AggregateError = globalThis.AggregateError
+ }
+ if (typeof SharedArrayBuffer !== 'undefined') {
+ scope.SharedArrayBuffer = SharedArrayBuffer
+ }
+
+ scope.global = scope
+ scope.globalThis = scope
+ return scope
+}
+
+export const nodeJsScope = createNodeJsScope()
diff --git a/src/components/Dashboard/Finance/Invoices.jsx b/src/components/Dashboard/Finance/Invoices.jsx
index d16a8553..908d1b34 100644
--- a/src/components/Dashboard/Finance/Invoices.jsx
+++ b/src/components/Dashboard/Finance/Invoices.jsx
@@ -1,9 +1,7 @@
-import { useState, useRef } from 'react'
-import { Button, Flex, Space, Dropdown, Modal } from 'antd'
-import NewInvoice from './Invoices/NewInvoice'
+import { useRef } from 'react'
+import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
-import PlusIcon from '../../Icons/PlusIcon'
-import ReloadIcon from '../../Icons/ReloadIcon'
+import ObjectActions from '../common/ObjectActions'
import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton'
@@ -15,7 +13,6 @@ import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
const Invoices = () => {
- const [newInvoiceOpen, setNewInvoiceOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('invoices')
@@ -29,37 +26,17 @@ const Invoices = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Invoices')
- const actionItems = {
- items: [
- {
- label: 'New Invoice',
- key: 'newInvoice',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newInvoice') {
- setNewInvoiceOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewInvoiceOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewInvoiceOpen(false)
- tableRef.current?.reload()
- }}
- reset={newInvoiceOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx b/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx
index 14757a46..e7011b8f 100644
--- a/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx
+++ b/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx
@@ -98,6 +98,7 @@ const InvoiceInfo = () => {
{
- const [newPaymentOpen, setNewPaymentOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('payments')
@@ -29,37 +26,17 @@ const Payments = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Payments')
- const actionItems = {
- items: [
- {
- label: 'New Payment',
- key: 'newPayment',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPayment') {
- setNewPaymentOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewPaymentOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewPaymentOpen(false)
- tableRef.current?.reload()
- }}
- reset={newPaymentOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Finance/Payments/PaymentInfo.jsx b/src/components/Dashboard/Finance/Payments/PaymentInfo.jsx
index 8164eced..6b3e5398 100644
--- a/src/components/Dashboard/Finance/Payments/PaymentInfo.jsx
+++ b/src/components/Dashboard/Finance/Payments/PaymentInfo.jsx
@@ -91,6 +91,7 @@ const PaymentInfo = () => {
{
- const [newTaxRecordOpen, setNewTaxRecordOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('taxRecord')
@@ -29,37 +26,17 @@ const TaxRecords = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('TaxRecords')
- const actionItems = {
- items: [
- {
- label: 'New Tax Record',
- key: 'newTaxRecord',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newTaxRecord') {
- setNewTaxRecordOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewTaxRecordOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewTaxRecordOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newTaxRecordOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Finance/TaxRecords/TaxRecordInfo.jsx b/src/components/Dashboard/Finance/TaxRecords/TaxRecordInfo.jsx
index 6cf21942..924826c8 100644
--- a/src/components/Dashboard/Finance/TaxRecords/TaxRecordInfo.jsx
+++ b/src/components/Dashboard/Finance/TaxRecords/TaxRecordInfo.jsx
@@ -81,6 +81,7 @@ const TaxRecordInfo = () => {
{
const tableRef = useRef()
- const [newFilamentStockOpen, setNewFilamentStockOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('filamentStocks')
@@ -34,37 +31,17 @@ const FilamentStocks = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('FilamentStocks')
- const actionItems = {
- items: [
- {
- label: 'New Filament Stock',
- key: 'newFilamentStock',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newFilamentStock') {
- setNewFilamentStockOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewFilamentStockOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewFilamentStockOpen(false)
- tableRef.current?.reload()
- }}
- reset={newFilamentStockOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/FilamentStocks/FilamentStockInfo.jsx b/src/components/Dashboard/Inventory/FilamentStocks/FilamentStockInfo.jsx
index 99b4746d..dc8301b5 100644
--- a/src/components/Dashboard/Inventory/FilamentStocks/FilamentStockInfo.jsx
+++ b/src/components/Dashboard/Inventory/FilamentStocks/FilamentStockInfo.jsx
@@ -79,6 +79,7 @@ const FilamentStockInfo = () => {
{
- const [newOrderItemOpen, setNewOrderItemOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('orderItems')
@@ -29,37 +26,17 @@ const OrderItems = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('OrderItems')
- const actionItems = {
- items: [
- {
- label: 'New Order Item',
- key: 'newOrderItem',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newOrderItem') {
- setNewOrderItemOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewOrderItemOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewOrderItemOpen(false)
- tableRef.current?.reload()
- }}
- reset={newOrderItemOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/OrderItems/OrderItemInfo.jsx b/src/components/Dashboard/Inventory/OrderItems/OrderItemInfo.jsx
index a4b763ea..852d86ea 100644
--- a/src/components/Dashboard/Inventory/OrderItems/OrderItemInfo.jsx
+++ b/src/components/Dashboard/Inventory/OrderItems/OrderItemInfo.jsx
@@ -85,6 +85,7 @@ const OrderItemInfo = () => {
{
const tableRef = useRef()
- const [newPartStockOpen, setNewPartStockOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('partStocks')
@@ -34,37 +31,17 @@ const PartStocks = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('PartStocks')
- const actionItems = {
- items: [
- {
- label: 'New Part Stock',
- key: 'newPartStock',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPartStock') {
- setNewPartStockOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewPartStockOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewPartStockOpen(false)
- tableRef.current?.reload()
- }}
- reset={newPartStockOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/PartStocks/PartStockInfo.jsx b/src/components/Dashboard/Inventory/PartStocks/PartStockInfo.jsx
index 0cff01a1..2156e3b2 100644
--- a/src/components/Dashboard/Inventory/PartStocks/PartStockInfo.jsx
+++ b/src/components/Dashboard/Inventory/PartStocks/PartStockInfo.jsx
@@ -87,6 +87,7 @@ const PartStockInfo = () => {
{
const tableRef = useRef()
- const [newProductStockOpen, setNewProductStockOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('productStocks')
@@ -35,37 +32,17 @@ const ProductStocks = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('ProductStocks')
- const actionItems = {
- items: [
- {
- label: 'New Product Stock',
- key: 'newProductStock',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newProductStock') {
- setNewProductStockOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewProductStockOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewProductStockOpen(false)
- tableRef.current?.reload()
- }}
- reset={newProductStockOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx b/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx
index dbdd3c71..131ccd98 100644
--- a/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx
+++ b/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx
@@ -104,6 +104,7 @@ const ProductStockInfo = () => {
{
- const [newPurchaseOrderOpen, setNewPurchaseOrderOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('purchaseOrders')
@@ -29,37 +26,17 @@ const PurchaseOrders = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('PurchaseOrders')
- const actionItems = {
- items: [
- {
- label: 'New Purchase Order',
- key: 'newPurchaseOrder',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPurchaseOrder') {
- setNewPurchaseOrderOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewPurchaseOrderOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewPurchaseOrderOpen(false)
- tableRef.current?.reload()
- }}
- reset={newPurchaseOrderOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/PurchaseOrders/PurchaseOrderInfo.jsx b/src/components/Dashboard/Inventory/PurchaseOrders/PurchaseOrderInfo.jsx
index 38d1a309..bfaf5b60 100644
--- a/src/components/Dashboard/Inventory/PurchaseOrders/PurchaseOrderInfo.jsx
+++ b/src/components/Dashboard/Inventory/PurchaseOrders/PurchaseOrderInfo.jsx
@@ -109,6 +109,7 @@ const PurchaseOrderInfo = () => {
{
- const [newShipmentOpen, setNewShipmentOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('shipments')
@@ -29,37 +26,17 @@ const Shipments = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Shipments')
- const actionItems = {
- items: [
- {
- label: 'New Shipment',
- key: 'newShipment',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newShipment') {
- setNewShipmentOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewShipmentOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewShipmentOpen(false)
- tableRef.current?.reload()
- }}
- reset={newShipmentOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/Shipments/PurchaseOrderInfo.jsx b/src/components/Dashboard/Inventory/Shipments/PurchaseOrderInfo.jsx
index bcc8cbd1..801c469e 100644
--- a/src/components/Dashboard/Inventory/Shipments/PurchaseOrderInfo.jsx
+++ b/src/components/Dashboard/Inventory/Shipments/PurchaseOrderInfo.jsx
@@ -119,6 +119,7 @@ const PurchaseOrderInfo = () => {
{
{
const tableRef = useRef()
- const [newStockAuditOpen, setNewStockAuditOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('stockAudits')
@@ -34,37 +31,17 @@ const StockAudits = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('StockAudits')
- const actionItems = {
- items: [
- {
- label: 'New Stock audit',
- key: 'newStockAudit',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newStockAudit') {
- setNewStockAuditOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewStockAuditOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewStockAuditOpen(false)
- tableRef.current?.reload()
- }}
- reset={newStockAuditOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/StockAudits/StockAuditInfo.jsx b/src/components/Dashboard/Inventory/StockAudits/StockAuditInfo.jsx
index d86ffd8c..ab7f0a78 100644
--- a/src/components/Dashboard/Inventory/StockAudits/StockAuditInfo.jsx
+++ b/src/components/Dashboard/Inventory/StockAudits/StockAuditInfo.jsx
@@ -83,6 +83,7 @@ const StockAuditInfo = () => {
{
const tableRef = useRef()
@@ -25,29 +25,17 @@ const StockEvents = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('StockEvents')
- const actionItems = {
- items: [
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
const tableRef = useRef()
- const [newOpen, setNewOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('stockLocations')
@@ -32,37 +29,17 @@ const StockLocations = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('StockLocations')
- const actionItems = {
- items: [
- {
- label: 'New Stock Location',
- key: 'new',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'new') {
- setNewOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewOpen(false)
- tableRef.current?.reload()
- }}
- reset={newOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/StockLocations/StockLocationInfo.jsx b/src/components/Dashboard/Inventory/StockLocations/StockLocationInfo.jsx
index 659ebc91..08a319ed 100644
--- a/src/components/Dashboard/Inventory/StockLocations/StockLocationInfo.jsx
+++ b/src/components/Dashboard/Inventory/StockLocations/StockLocationInfo.jsx
@@ -84,6 +84,7 @@ const StockLocationInfo = () => {
{
const tableRef = useRef()
- const [newOpen, setNewOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('stockTransfers')
@@ -32,37 +29,17 @@ const StockTransfers = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('StockTransfers')
- const actionItems = {
- items: [
- {
- label: 'New Stock Transfer',
- key: 'new',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'new') {
- setNewOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewOpen(false)
- tableRef.current?.reload()
- }}
- reset={newOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Inventory/StockTransfers/StockTransferInfo.jsx b/src/components/Dashboard/Inventory/StockTransfers/StockTransferInfo.jsx
index 05c792de..3a0ae2d5 100644
--- a/src/components/Dashboard/Inventory/StockTransfers/StockTransferInfo.jsx
+++ b/src/components/Dashboard/Inventory/StockTransfers/StockTransferInfo.jsx
@@ -94,6 +94,7 @@ const StockTransferInfo = () => {
{
- const [newAppPasswordOpen, setNewAppPasswordOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('appPassword')
@@ -28,37 +25,17 @@ const AppPasswords = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('AppPasswords')
- const actionItems = {
- items: [
- {
- label: 'New App Password',
- key: 'newAppPassword',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newAppPassword') {
- setNewAppPasswordOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewAppPasswordOpen(false)
- }}
- >
- {
- setNewAppPasswordOpen(false)
- tableRef.current?.reload()
- }}
- reset={newAppPasswordOpen}
- />
-
>
)
diff --git a/src/components/Dashboard/Management/AppPasswords/AppPasswordInfo.jsx b/src/components/Dashboard/Management/AppPasswords/AppPasswordInfo.jsx
index f9e95fb5..57941bab 100644
--- a/src/components/Dashboard/Management/AppPasswords/AppPasswordInfo.jsx
+++ b/src/components/Dashboard/Management/AppPasswords/AppPasswordInfo.jsx
@@ -80,6 +80,7 @@ const AppPasswordInfo = () => {
{
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('AuditLogs')
- const actionItems = {
- items: [
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
- const [newCourierServiceOpen, setNewCourierServiceOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('courierService')
@@ -29,37 +26,17 @@ const CourierServices = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('CourierServices')
- const actionItems = {
- items: [
- {
- label: 'New Courier Service',
- key: 'newCourierService',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newCourierService') {
- setNewCourierServiceOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewCourierServiceOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewCourierServiceOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newCourierServiceOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/CourierServices/CourierServiceInfo.jsx b/src/components/Dashboard/Management/CourierServices/CourierServiceInfo.jsx
index 08430416..e4499b8c 100644
--- a/src/components/Dashboard/Management/CourierServices/CourierServiceInfo.jsx
+++ b/src/components/Dashboard/Management/CourierServices/CourierServiceInfo.jsx
@@ -83,6 +83,7 @@ const CourierServiceInfo = () => {
{
- const [newCourierOpen, setNewCourierOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('courier')
@@ -28,37 +25,17 @@ const Couriers = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Couriers')
- const actionItems = {
- items: [
- {
- label: 'New Courier',
- key: 'newCourier',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newCourier') {
- setNewCourierOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewCourierOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewCourierOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newCourierOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/Couriers/CourierInfo.jsx b/src/components/Dashboard/Management/Couriers/CourierInfo.jsx
index 3d0efac9..29d89a25 100644
--- a/src/components/Dashboard/Management/Couriers/CourierInfo.jsx
+++ b/src/components/Dashboard/Management/Couriers/CourierInfo.jsx
@@ -79,6 +79,7 @@ const CourierInfo = () => {
{
- const [newDocumentJobOpen, setNewDocumentJobOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentJob')
@@ -29,37 +26,17 @@ const DocumentJobs = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('DocumentJobs')
- const actionItems = {
- items: [
- {
- label: 'New Document Job',
- key: 'newDocumentJob',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newDocumentJob') {
- setNewDocumentJobOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewDocumentJobOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={900}
- >
- {
- setNewDocumentJobOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newDocumentJobOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/DocumentJobs/DocumentJobInfo.jsx b/src/components/Dashboard/Management/DocumentJobs/DocumentJobInfo.jsx
index 1048ab3f..52ac06bf 100644
--- a/src/components/Dashboard/Management/DocumentJobs/DocumentJobInfo.jsx
+++ b/src/components/Dashboard/Management/DocumentJobs/DocumentJobInfo.jsx
@@ -80,6 +80,7 @@ const DocumentJobInfo = () => {
{
const tableRef = useRef()
- const [newDocumentPrinterOpen, setNewDocumentPrinterOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('documentPrinter')
const [columnVisibility, setColumnVisibility] =
@@ -28,37 +25,17 @@ const DocumentPrinters = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('DocumentPrinters')
- const actionItems = {
- items: [
- {
- label: 'New Document Printer',
- key: 'newDocumentPrinter',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newDocumentPrinter') {
- setNewDocumentPrinterOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewDocumentPrinterOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewDocumentPrinterOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newDocumentPrinterOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/DocumentPrinters/DocumentPrinterInfo.jsx b/src/components/Dashboard/Management/DocumentPrinters/DocumentPrinterInfo.jsx
index 7f4c12ca..abffb8c0 100644
--- a/src/components/Dashboard/Management/DocumentPrinters/DocumentPrinterInfo.jsx
+++ b/src/components/Dashboard/Management/DocumentPrinters/DocumentPrinterInfo.jsx
@@ -85,6 +85,7 @@ const DocumentPrinterInfo = () => {
{
- const [newDocumentSizeOpen, setNewDocumentSizeOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentSize')
const [columnVisibility, setColumnVisibility] =
@@ -27,37 +24,17 @@ const DocumentSizes = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('DocumentSizes')
- const actionItems = {
- items: [
- {
- label: 'New Document Size',
- key: 'newDocumentSize',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newDocumentSize') {
- setNewDocumentSizeOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewDocumentSizeOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewDocumentSizeOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newDocumentSizeOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/DocumentSizes/DocumentSizeInfo.jsx b/src/components/Dashboard/Management/DocumentSizes/DocumentSizeInfo.jsx
index 0bcc856a..36410685 100644
--- a/src/components/Dashboard/Management/DocumentSizes/DocumentSizeInfo.jsx
+++ b/src/components/Dashboard/Management/DocumentSizes/DocumentSizeInfo.jsx
@@ -80,6 +80,7 @@ const DocumentSizeInfo = () => {
{
- const [newDocumentTemplateOpen, setNewDocumentTemplateOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentTemplate')
@@ -29,37 +26,17 @@ const DocumentTemplates = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('DocumentTemplates')
- const actionItems = {
- items: [
- {
- label: 'New Document Template',
- key: 'newDocumentTemplate',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newDocumentTemplate') {
- setNewDocumentTemplateOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewDocumentTemplateOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewDocumentTemplateOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newDocumentTemplateOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/DocumentTemplates/DocumentTemplateDesign.jsx b/src/components/Dashboard/Management/DocumentTemplates/DocumentTemplateDesign.jsx
index 87568335..ccfb2093 100644
--- a/src/components/Dashboard/Management/DocumentTemplates/DocumentTemplateDesign.jsx
+++ b/src/components/Dashboard/Management/DocumentTemplates/DocumentTemplateDesign.jsx
@@ -75,6 +75,7 @@ const DocumentTemplateDesign = () => {
{
{
const tableRef = useRef()
- const [newFilamentSkuOpen, setNewFilamentSkuOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('filamentSkus')
@@ -32,37 +29,17 @@ const FilamentSkus = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('FilamentSkus')
- const actionItems = {
- items: [
- {
- label: 'New Filament SKU',
- key: 'newFilamentSku',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newFilamentSku') {
- setNewFilamentSkuOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewFilamentSkuOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewFilamentSkuOpen(false)
- tableRef.current?.reload()
- }}
- reset={newFilamentSkuOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/FilamentSkus/FilamentSkuInfo.jsx b/src/components/Dashboard/Management/FilamentSkus/FilamentSkuInfo.jsx
index 02229089..305f96e4 100644
--- a/src/components/Dashboard/Management/FilamentSkus/FilamentSkuInfo.jsx
+++ b/src/components/Dashboard/Management/FilamentSkus/FilamentSkuInfo.jsx
@@ -78,6 +78,7 @@ const FilamentSkuInfo = () => {
{
- const [newFilamentOpen, setNewFilamentOpen] = useState(false)
const tableRef = useRef()
// View mode state (cards/list), persisted in sessionStorage via custom hook
@@ -34,37 +31,17 @@ const Filaments = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Filaments')
- const actionItems = {
- items: [
- {
- label: 'New Filament',
- key: 'newFilament',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newFilament') {
- setNewFilamentOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewFilamentOpen(false)
- }}
- >
- {
- setNewFilamentOpen(false)
- tableRef.current?.reload()
- }}
- reset={newFilamentOpen}
- />
-
>
)
diff --git a/src/components/Dashboard/Management/Filaments/FilamentInfo.jsx b/src/components/Dashboard/Management/Filaments/FilamentInfo.jsx
index d9461371..7ee2e650 100644
--- a/src/components/Dashboard/Management/Filaments/FilamentInfo.jsx
+++ b/src/components/Dashboard/Management/Filaments/FilamentInfo.jsx
@@ -99,6 +99,7 @@ const FilamentInfo = () => {
{
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Files')
- const actionItems = {
- items: [
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
{
- const [newHostOpen, setNewHostOpen] = useState(false)
const tableRef = useRef()
// View mode state (cards/list), persisted in sessionStorage via custom hook
@@ -33,37 +30,17 @@ const Hosts = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Hosts')
- const actionItems = {
- items: [
- {
- label: 'New Host',
- key: 'newHost',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newHost') {
- setNewHostOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewHostOpen(false)
- }}
- >
- {
- setNewHostOpen(false)
- tableRef.current?.reload()
- }}
- reset={newHostOpen}
- />
-
>
)
diff --git a/src/components/Dashboard/Management/Hosts/HostInfo.jsx b/src/components/Dashboard/Management/Hosts/HostInfo.jsx
index 39bce0f6..c217fc15 100644
--- a/src/components/Dashboard/Management/Hosts/HostInfo.jsx
+++ b/src/components/Dashboard/Management/Hosts/HostInfo.jsx
@@ -94,6 +94,7 @@ const HostInfo = () => {
{
- const [newMaterialOpen, setNewMaterialOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('material')
@@ -31,37 +28,17 @@ const Materials = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Materials')
- const actionItems = {
- items: [
- {
- label: 'New Material',
- key: 'newMaterial',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newMaterial') {
- setNewMaterialOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewMaterialOpen(false)
- }}
- >
- {
- setNewMaterialOpen(false)
- tableRef.current?.reload()
- }}
- reset={newMaterialOpen}
- />
-
>
)
diff --git a/src/components/Dashboard/Management/Materials/MaterialInfo.jsx b/src/components/Dashboard/Management/Materials/MaterialInfo.jsx
index 580a886b..f4e48288 100644
--- a/src/components/Dashboard/Management/Materials/MaterialInfo.jsx
+++ b/src/components/Dashboard/Management/Materials/MaterialInfo.jsx
@@ -81,6 +81,7 @@ const MaterialInfo = () => {
{
- const [newNoteTypeOpen, setNewNoteTypeOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('noteType')
@@ -29,37 +26,17 @@ const NoteTypes = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('NoteTypes')
- const actionItems = {
- items: [
- {
- label: 'New Note Type',
- key: 'newNoteType',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newNoteType') {
- setNewNoteTypeOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewNoteTypeOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewNoteTypeOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newNoteTypeOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx b/src/components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx
index 71ccabbb..011eee0b 100644
--- a/src/components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx
+++ b/src/components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx
@@ -70,6 +70,7 @@ const NoteTypeInfo = () => {
{
{
const tableRef = useRef()
- const [newPartSkuOpen, setNewPartSkuOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('partSkus')
@@ -31,37 +28,17 @@ const PartSkus = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('PartSkus')
- const actionItems = {
- items: [
- {
- label: 'New Part SKU',
- key: 'newPartSku',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPartSku') {
- setNewPartSkuOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewPartSkuOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewPartSkuOpen(false)
- tableRef.current?.reload()
- }}
- reset={newPartSkuOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/PartSkus/PartSkuInfo.jsx b/src/components/Dashboard/Management/PartSkus/PartSkuInfo.jsx
index d0e3a2fa..f949a991 100644
--- a/src/components/Dashboard/Management/PartSkus/PartSkuInfo.jsx
+++ b/src/components/Dashboard/Management/PartSkus/PartSkuInfo.jsx
@@ -73,6 +73,7 @@ const PartSkuInfo = () => {
{
- const [newPartOpen, setNewPartOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('part')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('part')
@@ -33,37 +30,17 @@ const Parts = (filter) => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Parts')
- const actionItems = {
- items: [
- {
- label: 'New Part',
- key: 'newPart',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPart') {
- setNewPartOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewPartOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewPartOpen(false)
- tableRef.current?.reload()
- }}
- reset={newPartOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/Parts/PartInfo.jsx b/src/components/Dashboard/Management/Parts/PartInfo.jsx
index c17e500e..04723b02 100644
--- a/src/components/Dashboard/Management/Parts/PartInfo.jsx
+++ b/src/components/Dashboard/Management/Parts/PartInfo.jsx
@@ -80,6 +80,7 @@ const PartInfo = () => {
{
- const [newPermissionSettingsOpen, setNewPermissionSettingsOpen] =
- useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('permissionSetting')
@@ -30,37 +26,17 @@ const PermissionSettingsList = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('PermissionSettings')
- const actionItems = {
- items: [
- {
- label: 'New Permission Settings',
- key: 'newPermissionSettings',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPermissionSettings') {
- setNewPermissionSettingsOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewPermissionSettingsOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewPermissionSettingsOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newPermissionSettingsOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/PermissionSettings/PermissionSettingInfo.jsx b/src/components/Dashboard/Management/PermissionSettings/PermissionSettingInfo.jsx
index 7d22b591..2dd8be0f 100644
--- a/src/components/Dashboard/Management/PermissionSettings/PermissionSettingInfo.jsx
+++ b/src/components/Dashboard/Management/PermissionSettings/PermissionSettingInfo.jsx
@@ -85,6 +85,7 @@ const PermissionSettingInfo = () => {
{
- const [newProductCategoryOpen, setNewProductCategoryOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('productCategory')
@@ -31,37 +28,17 @@ const ProductCategories = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('ProductCategories')
- const actionItems = {
- items: [
- {
- label: 'New Product Category',
- key: 'newProductCategory',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newProductCategory') {
- setNewProductCategoryOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewProductCategoryOpen(false)
- }}
- >
- {
- setNewProductCategoryOpen(false)
- tableRef.current?.reload()
- }}
- reset={newProductCategoryOpen}
- />
-
>
)
diff --git a/src/components/Dashboard/Management/ProductCategories/ProductCategoryInfo.jsx b/src/components/Dashboard/Management/ProductCategories/ProductCategoryInfo.jsx
index 5e84b0fd..60f6e0b1 100644
--- a/src/components/Dashboard/Management/ProductCategories/ProductCategoryInfo.jsx
+++ b/src/components/Dashboard/Management/ProductCategories/ProductCategoryInfo.jsx
@@ -78,6 +78,7 @@ const ProductCategoryInfo = () => {
{
const tableRef = useRef()
- const [newProductSkuOpen, setNewProductSkuOpen] = useState(false)
const [viewMode, setViewMode] = useViewMode('productSkus')
@@ -32,37 +29,17 @@ const ProductSkus = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('ProductSkus')
- const actionItems = {
- items: [
- {
- label: 'New Product SKU',
- key: 'newProductSku',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newProductSku') {
- setNewProductSkuOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewProductSkuOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewProductSkuOpen(false)
- tableRef.current?.reload()
- }}
- reset={newProductSkuOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/ProductSkus/ProductSkuInfo.jsx b/src/components/Dashboard/Management/ProductSkus/ProductSkuInfo.jsx
index 2a124b83..00b5799b 100644
--- a/src/components/Dashboard/Management/ProductSkus/ProductSkuInfo.jsx
+++ b/src/components/Dashboard/Management/ProductSkus/ProductSkuInfo.jsx
@@ -79,6 +79,7 @@ const ProductSkuInfo = () => {
{
const navigate = useNavigate()
- const [newProductOpen, setNewProductOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('Products')
@@ -244,28 +240,6 @@ const Products = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Products')
- const actionItems = {
- items: [
- {
- label: 'New Product',
- key: 'newProduct',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newProduct') {
- setNewProductOpen(true)
- }
- }
- }
const getFilterDropdown = ({
setSelectedKeys,
@@ -332,9 +306,11 @@ const Products = () => {
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewProductOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewProductOpen(false)
- tableRef.current?.reload()
- }}
- reset={newProductOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/Products/ProductInfo.jsx b/src/components/Dashboard/Management/Products/ProductInfo.jsx
index 43ecd564..3ffc1773 100644
--- a/src/components/Dashboard/Management/Products/ProductInfo.jsx
+++ b/src/components/Dashboard/Management/Products/ProductInfo.jsx
@@ -80,6 +80,7 @@ const ProductInfo = () => {
{
- const [newTaxRateOpen, setNewTaxRateOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('taxRate')
@@ -28,37 +25,17 @@ const TaxRates = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('TaxRates')
- const actionItems = {
- items: [
- {
- label: 'New Tax Rate',
- key: 'newTaxRate',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newTaxRate') {
- setNewTaxRateOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewTaxRateOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewTaxRateOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newTaxRateOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/TaxRates/TaxRateInfo.jsx b/src/components/Dashboard/Management/TaxRates/TaxRateInfo.jsx
index b9f79f62..7952968e 100644
--- a/src/components/Dashboard/Management/TaxRates/TaxRateInfo.jsx
+++ b/src/components/Dashboard/Management/TaxRates/TaxRateInfo.jsx
@@ -78,6 +78,7 @@ const TaxRateInfo = () => {
{
- const [newUserGroupOpen, setNewUserGroupOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('userGroup')
@@ -28,37 +25,17 @@ const UserGroups = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('UserGroups')
- const actionItems = {
- items: [
- {
- label: 'New User Group',
- key: 'newUserGroup',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newUserGroup') {
- setNewUserGroupOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewUserGroupOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewUserGroupOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newUserGroupOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/UserGroups/UserGroupInfo.jsx b/src/components/Dashboard/Management/UserGroups/UserGroupInfo.jsx
index 7a8a5c40..21f9d4ce 100644
--- a/src/components/Dashboard/Management/UserGroups/UserGroupInfo.jsx
+++ b/src/components/Dashboard/Management/UserGroups/UserGroupInfo.jsx
@@ -84,6 +84,7 @@ const UserGroupInfo = () => {
{
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Users')
- const actionItems = {
- items: [
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- }
- }
- }
return (
-
-
-
+ tableRef.current?.reload()}
+ />
{
{
- const [newVendorOpen, setNewVendorOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('vendor')
@@ -28,37 +25,17 @@ const Vendors = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Vendors')
- const actionItems = {
- items: [
- {
- label: 'New Vendor',
- key: 'newVendor',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newVendor') {
- setNewVendorOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewVendorOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewVendorOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newVendorOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Management/Vendors/VendorInfo.jsx b/src/components/Dashboard/Management/Vendors/VendorInfo.jsx
index 318ad71f..63ca861f 100644
--- a/src/components/Dashboard/Management/Vendors/VendorInfo.jsx
+++ b/src/components/Dashboard/Management/Vendors/VendorInfo.jsx
@@ -78,6 +78,7 @@ const VendorInfo = () => {
{
- const [newProfileOpen, setNewProfileOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('FilamentProfiles')
const [columnVisibility, setColumnVisibility] =
@@ -26,37 +23,17 @@ const FilamentProfiles = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('FilamentProfiles')
- const actionItems = {
- items: [
- {
- label: 'New Filament Profile',
- key: 'newFilamentProfile',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newFilamentProfile') {
- setNewProfileOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
-
- setNewProfileOpen(false)}
- destroyOnHidden
- >
- {newProfileOpen && (
- {
- setNewProfileOpen(false)
- tableRef.current?.reload()
- }}
- />
- )}
-
>
)
}
diff --git a/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx b/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx
index 65ba07b1..47f04da6 100644
--- a/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx
+++ b/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx
@@ -115,6 +115,7 @@ const FilamentProfileInfo = () => {
{
- const [newGCodeFileOpen, setNewGCodeFileOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('gcodeFile')
@@ -31,37 +28,17 @@ const GCodeFiles = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('GCodeFiles')
- const actionItems = {
- items: [
- {
- label: 'New GCodeFile',
- key: 'newGCodeFile',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newGCodeFile') {
- setNewGCodeFileOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewGCodeFileOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewGCodeFileOpen(false)
- tableRef.current?.reload()
- }}
- reset={newGCodeFileOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Production/GCodeFiles/GCodeFileInfo.jsx b/src/components/Dashboard/Production/GCodeFiles/GCodeFileInfo.jsx
index e3ff1e55..83df2575 100644
--- a/src/components/Dashboard/Production/GCodeFiles/GCodeFileInfo.jsx
+++ b/src/components/Dashboard/Production/GCodeFiles/GCodeFileInfo.jsx
@@ -85,6 +85,7 @@ const GCodeFileInfo = () => {
{
{
- const [newJobOpen, setNewJobOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('job')
@@ -28,41 +25,18 @@ const Jobs = () => {
const [showSortSidebar, setShowSortSidebar] = useSortSidebarVisibility('Jobs')
- const actionItems = {
- items: [
- {
- label: 'New Print Job',
- key: 'newJob',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'newJob') {
- showNewJobModal()
- } else if (key === 'reloadList') {
- tableRef.current?.reload()
- }
- }
- }
- const showNewJobModal = () => {
- setNewJobOpen(true)
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewJobOpen(false)
- }}
- >
- {
- setNewJobOpen(false)
- tableRef.current?.reload()
- }}
- reset={newJobOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Production/Jobs/JobInfo.jsx b/src/components/Dashboard/Production/Jobs/JobInfo.jsx
index 5666fc69..0bfce988 100644
--- a/src/components/Dashboard/Production/Jobs/JobInfo.jsx
+++ b/src/components/Dashboard/Production/Jobs/JobInfo.jsx
@@ -91,6 +91,7 @@ const JobInfo = () => {
{
- const [newProfileOpen, setNewProfileOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('PrinterProfiles')
const [columnVisibility, setColumnVisibility] =
@@ -25,37 +22,17 @@ const PrinterProfiles = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('PrinterProfiles')
- const actionItems = {
- items: [
- {
- label: 'New Printer Profile',
- key: 'newPrinterProfile',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPrinterProfile') {
- setNewProfileOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
-
- setNewProfileOpen(false)}
- destroyOnHidden
- >
- {newProfileOpen && (
- {
- setNewProfileOpen(false)
- tableRef.current?.reload()
- }}
- />
- )}
-
>
)
}
diff --git a/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx b/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx
index 325a6e38..741651d6 100644
--- a/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx
+++ b/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx
@@ -93,6 +93,7 @@ const PrinterProfileInfo = () => {
{
- const [newPrinterOpen, setNewPrinterOpen] = useState(false)
const tableRef = useRef()
// View mode state (cards/list), persisted in sessionStorage via custom hook
@@ -34,37 +31,17 @@ const Printers = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Printers')
- const actionItems = {
- items: [
- {
- label: 'New Printer',
- key: 'newPrinter',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newPrinter') {
- setNewPrinterOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewPrinterOpen(false)
- }}
- destroyOnHidden
- >
- {
- setNewPrinterOpen(false)
- tableRef.current?.reload()
- }}
- reset={newPrinterOpen}
- />
-
>
)
diff --git a/src/components/Dashboard/Production/Printers/ControlPrinter.jsx b/src/components/Dashboard/Production/Printers/ControlPrinter.jsx
index b495fd85..224d6ff8 100644
--- a/src/components/Dashboard/Production/Printers/ControlPrinter.jsx
+++ b/src/components/Dashboard/Production/Printers/ControlPrinter.jsx
@@ -256,6 +256,7 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
{
{
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('SubJobs')
- const actionItems = {
- items: [
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
{
- const [newClientOpen, setNewClientOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('client')
@@ -28,37 +25,17 @@ const Clients = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Clients')
- const actionItems = {
- items: [
- {
- label: 'New Client',
- key: 'newClient',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newClient') {
- setNewClientOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- setNewClientOpen(false)}
- footer={null}
- destroyOnHidden={true}
- width={700}
- >
- {
- setNewClientOpen(false)
- tableRef.current?.reload()
- }}
- reset={!newClientOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Sales/Clients/ClientInfo.jsx b/src/components/Dashboard/Sales/Clients/ClientInfo.jsx
index 9f3bd754..98688ad4 100644
--- a/src/components/Dashboard/Sales/Clients/ClientInfo.jsx
+++ b/src/components/Dashboard/Sales/Clients/ClientInfo.jsx
@@ -78,6 +78,7 @@ const ClientInfo = () => {
{
{
- const [newListingOpen, setNewListingOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('listings')
@@ -29,37 +26,17 @@ const Listings = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Listings')
- const actionItems = {
- items: [
- {
- label: 'New Listing',
- key: 'newListing',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newListing') {
- setNewListingOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewListingOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewListingOpen(false)
- tableRef.current?.reload()
- }}
- reset={newListingOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Sales/Listings/ListingInfo.jsx b/src/components/Dashboard/Sales/Listings/ListingInfo.jsx
index 35c3c6ab..018faf34 100644
--- a/src/components/Dashboard/Sales/Listings/ListingInfo.jsx
+++ b/src/components/Dashboard/Sales/Listings/ListingInfo.jsx
@@ -89,6 +89,7 @@ const ListingInfo = () => {
{
- const [newMarketplaceOpen, setNewMarketplaceOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('marketplaces')
@@ -29,37 +26,17 @@ const Marketplaces = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Marketplaces')
- const actionItems = {
- items: [
- {
- label: 'New Marketplace',
- key: 'newMarketplace',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newMarketplace') {
- setNewMarketplaceOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewMarketplaceOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewMarketplaceOpen(false)
- tableRef.current?.reload()
- }}
- reset={newMarketplaceOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Sales/Marketplaces/MarketplaceInfo.jsx b/src/components/Dashboard/Sales/Marketplaces/MarketplaceInfo.jsx
index c91d703e..abdeb792 100644
--- a/src/components/Dashboard/Sales/Marketplaces/MarketplaceInfo.jsx
+++ b/src/components/Dashboard/Sales/Marketplaces/MarketplaceInfo.jsx
@@ -158,6 +158,7 @@ const MarketplaceInfo = () => {
{
- const [newSalesOrderOpen, setNewSalesOrderOpen] = useState(false)
const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('salesOrders')
@@ -29,37 +26,17 @@ const SalesOrders = () => {
const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('SalesOrders')
- const actionItems = {
- items: [
- {
- label: 'New Sales Order',
- key: 'newSalesOrder',
- icon:
- },
- { type: 'divider' },
- {
- label: 'Reload List',
- key: 'reloadList',
- icon:
- }
- ],
- onClick: ({ key }) => {
- if (key === 'reloadList') {
- tableRef.current?.reload()
- } else if (key === 'newSalesOrder') {
- setNewSalesOrderOpen(true)
- }
- }
- }
return (
<>
-
-
-
+ tableRef.current?.reload()}
+ />
{
useSortInUrl={true}
/>
- {
- setNewSalesOrderOpen(false)
- }}
- destroyOnHidden={true}
- >
- {
- setNewSalesOrderOpen(false)
- tableRef.current?.reload()
- }}
- reset={newSalesOrderOpen}
- />
-
>
)
}
diff --git a/src/components/Dashboard/Sales/SalesOrders/SalesOrderInfo.jsx b/src/components/Dashboard/Sales/SalesOrders/SalesOrderInfo.jsx
index ea2087cb..f4579d5c 100644
--- a/src/components/Dashboard/Sales/SalesOrders/SalesOrderInfo.jsx
+++ b/src/components/Dashboard/Sales/SalesOrders/SalesOrderInfo.jsx
@@ -107,6 +107,7 @@ const SalesOrderInfo = () => {
{
+ const { userProfile } = useContext(AuthContext)
+ const { currentObjectType } = useActions()
+ const modelType = type || currentObjectType
+ const model = modelType ? getModelByName(modelType) : null
+ const denied = model
+ ? !hasActionPermission(userProfile, model, 'edit')
+ : false
+ const editDisabled = disabled || denied
+
return isEditing ? (
{
- if (!disabled && !loading && formValid) {
+ if (!editDisabled && !loading && formValid) {
handleUpdate()
}
}}
@@ -30,7 +45,7 @@ const EditButtons = ({
type='primary'
onClick={handleUpdate}
loading={loading}
- disabled={loading || !formValid || disabled}
+ disabled={loading || !formValid || editDisabled}
/>
{
- if (!disabled && !loading) {
+ if (!editDisabled && !loading) {
startEditing()
}
}}
@@ -63,7 +78,7 @@ const EditButtons = ({
icon={}
onClick={startEditing}
loading={loading}
- disabled={disabled || loading}
+ disabled={editDisabled || loading}
/>
)
@@ -76,7 +91,8 @@ EditButtons.propTypes = {
startEditing: PropTypes.func.isRequired,
formValid: PropTypes.bool.isRequired,
disabled: PropTypes.any,
- loading: PropTypes.bool.isRequired
+ loading: PropTypes.bool.isRequired,
+ type: PropTypes.string
}
export default EditButtons
diff --git a/src/components/Dashboard/common/ObjectActions.jsx b/src/components/Dashboard/common/ObjectActions.jsx
index 00c629de..3022a609 100644
--- a/src/components/Dashboard/common/ObjectActions.jsx
+++ b/src/components/Dashboard/common/ObjectActions.jsx
@@ -1,36 +1,38 @@
-import { createElement, useContext } from 'react'
+import { createElement, useContext, useEffect, useRef } from 'react'
import { Dropdown, Button } from 'antd'
import { getModelByName } from '../../../database/ObjectModels'
import PropTypes from 'prop-types'
import { useNavigate, useLocation } from 'react-router-dom'
import { useActionsModal } from '../context/ActionsModalContext'
+import { useActions } from '../context/ActionsContext'
import KeyboardShortcut from './KeyboardShortcut'
import { AuthContext } from '../context/AuthContext'
import {
+ actionVisibleOnPage,
buildActionUrl,
+ getActionPermissionTarget,
+ resolveAction,
stripPageActionParams
} from '../../../utils/modelActions'
+import { hasActionPermission } from '../../../database/permissions'
-// Recursively filter actions based on visibleActions
function filterActionsByVisibility(actions, visibleActions) {
if (!visibleActions) return actions
return actions.filter((action) => {
if (action.type === 'divider') {
- return true // Always show dividers
+ return true
}
const actionKey = action.key || action.name
const isVisible = visibleActions[actionKey] !== false
- // If this action has children, filter them recursively
if (action.children && Array.isArray(action.children)) {
const filteredChildren = filterActionsByVisibility(
action.children,
visibleActions
)
action.children = filteredChildren
- // Show parent if it has visible children or if it's explicitly visible
return (
isVisible &&
(filteredChildren.length > 0 || visibleActions[actionKey] === true)
@@ -74,18 +76,21 @@ function cleanDividers(items) {
}
function isSameActionUrl(action, actionUrl, currentUrl, pathname, search) {
- if (action.type === 'modal') {
+ if (action.type === 'modal' || action.type === 'alias') {
return actionUrl === currentUrl
}
- // Compare the action URL to the current location with its action param
- // stripped. Default page actions (e.g. Info) match and stay hidden when
- // already on that page. Actions that set their own action param (edit,
- // cancelEdit, finishEdit, etc.) do not match and remain available —
- // visibility is controlled by action.visible (e.g. _isEditing).
return actionUrl === stripPageActionParams(pathname, search)
}
-// Recursively map actions to AntD Dropdown items
+function actionDenied(userProfile, model, action, parentDenied = false) {
+ if (parentDenied) return true
+ const { model: permissionModel, actionName } = getActionPermissionTarget(
+ action,
+ model
+ )
+ return !hasActionPermission(userProfile, permissionModel, actionName)
+}
+
function mapActionsToMenuItems(
actions,
currentUrlWithActions,
@@ -94,29 +99,36 @@ function mapActionsToMenuItems(
userProfile,
model,
pathname,
- search
+ search,
+ parentDenied = false
) {
return cleanDividers(
actions.map((action) => {
if (action.type === 'divider') {
return { type: 'divider' }
}
+ const displayAction = resolveAction(action)
const actionUrl = buildActionUrl(model, action, id, pathname, search)
+ const denied = actionDenied(userProfile, model, action, parentDenied)
- var disabled = isSameActionUrl(
- action,
- actionUrl,
- currentUrlWithActions,
- pathname,
- search
- )
+ var disabled =
+ denied ||
+ isSameActionUrl(
+ action,
+ actionUrl,
+ currentUrlWithActions,
+ pathname,
+ search
+ )
var visible = true
if (action.disabled) {
if (typeof action.disabled === 'function') {
- disabled = action.disabled({ ...objectData, _user: userProfile })
+ disabled =
+ denied ||
+ action.disabled({ ...objectData, _user: userProfile })
} else {
- disabled = action.disabled
+ disabled = denied || action.disabled
}
}
@@ -134,9 +146,11 @@ function mapActionsToMenuItems(
const item = {
key: action.key || action.name,
- label: action.label,
+ label: displayAction.label,
danger: action?.danger || false,
- icon: action.icon ? createElement(action.icon) : undefined,
+ icon: displayAction.icon
+ ? createElement(displayAction.icon)
+ : undefined,
disabled
}
if (action.children && Array.isArray(action.children)) {
@@ -148,7 +162,8 @@ function mapActionsToMenuItems(
userProfile,
model,
pathname,
- search
+ search,
+ denied
)
}
return item
@@ -159,7 +174,9 @@ function mapActionsToMenuItems(
const ObjectActions = ({
type,
id,
- objectData,
+ objectData = {},
+ pageName = 'info',
+ onReload,
disabled = false,
buttonProps = {},
visibleActions = {},
@@ -170,11 +187,23 @@ const ObjectActions = ({
const navigate = useNavigate()
const location = useLocation()
const { showActionsModal } = useActionsModal()
+ const { setOnModalOk } = useActions()
const { userProfile } = useContext(AuthContext)
+ const onReloadRef = useRef(onReload)
+ onReloadRef.current = onReload
+
+ useEffect(() => {
+ if (pageName !== 'list') return
+ setOnModalOk(() => () => onReloadRef.current?.())
+ return () => setOnModalOk(null)
+ }, [pageName, setOnModalOk])
+
+ const pageActions = actions.filter((action) =>
+ actionVisibleOnPage(action, pageName)
+ )
- // First filter by visibility, then by current URL
const visibilityFilteredActions = filterActionsByVisibility(
- actions,
+ pageActions,
visibleActions
)
@@ -200,7 +229,9 @@ const ObjectActions = ({
const currentUrlWithActions = location.pathname + location.search
- // Compose AntD Dropdown menu items
+ const openActionsModal = () =>
+ showActionsModal(id, type, objectData, pageName)
+
const menu = {
items: mapActionsToMenuItems(
filteredActions,
@@ -213,36 +244,35 @@ const ObjectActions = ({
location.search
),
onClick: (info) => {
- // Find the action by key
- const findAction = (acts, key) => {
+ const findMenuAction = (acts, key, parentDenied = false) => {
for (const act of acts) {
- if ((act.key || act.name) === key) return act
+ if (act.type === 'divider') continue
+ const denied = actionDenied(userProfile, model, act, parentDenied)
+ if ((act.key || act.name) === key) {
+ return denied ? null : act
+ }
if (act.children) {
- const found = findAction(act.children, key)
+ const found = findMenuAction(act.children, key, denied)
if (found) return found
}
}
return null
}
- const action = findAction(filteredActions, info.key)
- if (action) {
- navigate(
- buildActionUrl(model, action, id, location.pathname, location.search)
- )
- }
+ const action = findMenuAction(filteredActions, info.key)
+ if (!action) return
+ navigate(
+ buildActionUrl(model, action, id, location.pathname, location.search)
+ )
}
}
return (
- showActionsModal(id, type, objectData)}
- >
+
@@ -253,8 +283,10 @@ const ObjectActions = ({
ObjectActions.propTypes = {
type: PropTypes.string.isRequired,
- objectData: PropTypes.object.isRequired,
- id: PropTypes.string.isRequired,
+ objectData: PropTypes.object,
+ id: PropTypes.string,
+ pageName: PropTypes.string,
+ onReload: PropTypes.func,
disabled: PropTypes.bool,
buttonProps: PropTypes.object,
buttonLabel: PropTypes.string,
diff --git a/src/components/Dashboard/common/ObjectTable.jsx b/src/components/Dashboard/common/ObjectTable.jsx
index c50243ae..e7dc4c71 100644
--- a/src/components/Dashboard/common/ObjectTable.jsx
+++ b/src/components/Dashboard/common/ObjectTable.jsx
@@ -55,6 +55,7 @@ import {
getActiveFilterValues,
useTableStatePersistence
} from '../context/TableStateContext'
+import { hasActionPermission } from '../../../database/permissions'
const logger = loglevel.getLogger('DasboardTable')
logger.setLevel(config.logLevel)
@@ -432,15 +433,18 @@ const ObjectTable = forwardRef(
return (
{rowActions.map((action, index) => {
- var disabled = false
+ const denied = !hasActionPermission(userProfile, model, action.name)
+ var disabled = denied
if (action.disabled) {
if (typeof action.disabled === 'function') {
- disabled = action.disabled({
- ...objectData,
- _user: userProfile
- })
+ disabled =
+ denied ||
+ action.disabled({
+ ...objectData,
+ _user: userProfile
+ })
} else {
- disabled = action.disabled
+ disabled = denied || action.disabled
}
}
return (
@@ -457,6 +461,7 @@ const ObjectTable = forwardRef(
type={'text'}
size={'small'}
onClick={() => {
+ if (denied) return
if (
onRowAction &&
onRowAction(action, objectData) !== false
diff --git a/src/components/Dashboard/common/PermissionsMatrix.jsx b/src/components/Dashboard/common/PermissionsMatrix.jsx
index 20eb676f..9353a8b1 100644
--- a/src/components/Dashboard/common/PermissionsMatrix.jsx
+++ b/src/components/Dashboard/common/PermissionsMatrix.jsx
@@ -173,7 +173,10 @@ const getModelPaths = (model) => {
}
addPath(model?.url)
- ;(model?.actions || []).forEach((action) => addPath(action?.url))
+ ;(model?.actions || []).forEach((action) => {
+ if (action?.type === 'alias' || action?.type === 'callback') return
+ addPath(action?.url)
+ })
return [...new Set(paths.filter(Boolean))]
}
@@ -310,7 +313,13 @@ const PermissionsMatrix = ({
const { isElectron } = useContext(ElectronContext)
const isMobile = useMediaQuery({ maxWidth: 768 })
const models = useMemo(() => getPermissionMatrixModels(), [])
- const actions = useMemo(() => getPermissionMatrixActions(), [])
+ const actions = useMemo(
+ () =>
+ getPermissionMatrixActions().filter(
+ (action) => action.type !== 'alias' && action.type !== 'callback'
+ ),
+ []
+ )
const permissions = useMemo(
() => (value && typeof value === 'object' ? value : {}),
[value]
diff --git a/src/components/Dashboard/common/UserProfilePopover.jsx b/src/components/Dashboard/common/UserProfilePopover.jsx
index 9afc5bc7..70743364 100644
--- a/src/components/Dashboard/common/UserProfilePopover.jsx
+++ b/src/components/Dashboard/common/UserProfilePopover.jsx
@@ -140,6 +140,7 @@ const UserProfilePopover = ({ onClose }) => {
{userProfile?._id && (
{
if (actionName) {
const action = findAction(model, actionName)
- if (action?.type === 'modal') return
+ if (action?.type === 'modal' || action?.type === 'alias') return
}
const params = new URLSearchParams(location.search)
@@ -112,7 +113,7 @@ const ActionsProvider = ({ children }) => {
const action = findAction(model, actionName)
if (!action) return
- if (action.type === 'modal') {
+ if (action.type === 'modal' || action.type === 'alias') {
lastHandledAction.current = actionKey
setModalAction(action)
return
@@ -154,19 +155,31 @@ const ActionsProvider = ({ children }) => {
? { ...currentObject, _user: userProfile }
: { _user: userProfile }
+ const resolvedModalAction =
+ modalAction?.type === 'alias' ? resolveAction(modalAction) : modalAction
+
const [modelWidth, setModelWidth] = useState(520)
useEffect(() => {
- if (modalAction?.modalWidth) {
- setModelWidth(modalAction.modalWidth)
+ if (resolvedModalAction?.modalWidth) {
+ setModelWidth(resolvedModalAction.modalWidth)
}
- }, [modalAction?.modalWidth])
+ }, [resolvedModalAction?.modalWidth])
const [modalCentered, setModalCentered] = useState(false)
useEffect(() => {
- if (modalAction?.modalCentered !== undefined) {
- setModalCentered(modalAction.modalCentered)
+ if (resolvedModalAction?.modalCentered !== undefined) {
+ setModalCentered(resolvedModalAction.modalCentered)
}
- }, [modalAction?.modalCentered])
+ }, [resolvedModalAction?.modalCentered])
+
+ const modalContentData =
+ modalAction?.type === 'alias'
+ ? typeof modalAction.objectData === 'function'
+ ? modalAction.objectData(modalObjectData)
+ : (modalAction.objectData ?? {})
+ : resolvedModalAction?.name === 'new'
+ ? {}
+ : modalObjectData
return (
{
}}
>
{
}
>
- {modalAction?.content && modalObjectData
- ? modalAction.content(modalObjectData, { onOk: handleModalOk })
+ {resolvedModalAction?.content
+ ? resolvedModalAction.content(modalContentData, {
+ onOk: handleModalOk
+ })
: null}
diff --git a/src/components/Dashboard/context/ActionsModalContext.jsx b/src/components/Dashboard/context/ActionsModalContext.jsx
index 3788a27d..5dc72caa 100644
--- a/src/components/Dashboard/context/ActionsModalContext.jsx
+++ b/src/components/Dashboard/context/ActionsModalContext.jsx
@@ -11,9 +11,13 @@ import PropTypes from 'prop-types'
import { useLocation, useNavigate } from 'react-router-dom'
import { getModelByName } from '../../../database/ObjectModels'
+import { hasActionPermission } from '../../../database/permissions'
import { AuthContext } from './AuthContext'
import {
+ actionVisibleOnPage,
buildActionUrl,
+ getActionPermissionTarget,
+ resolveAction,
stripActionParams
} from '../../../utils/modelActions'
import ElipsisText from '../common/ElipsisText'
@@ -24,7 +28,14 @@ const ActionsModalContext = createContext()
const stripActionParam = stripActionParams
// Flatten nested actions (including children) into a single list
-const flattenActions = (actions, parentLabel = '') => {
+const flattenActions = (
+ actions,
+ parentLabel = '',
+ userProfile,
+ model,
+ parentDenied = false,
+ pageName = 'info'
+) => {
if (!Array.isArray(actions)) return []
const flat = []
@@ -34,29 +45,52 @@ const flattenActions = (actions, parentLabel = '') => {
return
}
+ if (!actionVisibleOnPage(action, pageName)) {
+ return
+ }
+
+ const { model: permissionModel, actionName } = getActionPermissionTarget(
+ action,
+ model
+ )
+ const denied =
+ parentDenied ||
+ !hasActionPermission(userProfile, permissionModel, actionName)
+
+ const displayAction = resolveAction(action)
const hasUrl =
typeof action.url === 'function' ||
action.type === 'page' ||
- action.type === 'modal'
+ action.type === 'modal' ||
+ action.type === 'alias'
const hasChildren =
Array.isArray(action.children) && action.children.length > 0
- const currentLabel = action.label || action.name || ''
+ const currentLabel = displayAction.label || action.name || ''
const fullLabel = parentLabel
? `${parentLabel} / ${currentLabel}`
: currentLabel
- // Only push actions that are actually runnable
if (hasUrl) {
flat.push({
- ...action,
+ ...displayAction,
key: action.key || action.name || fullLabel,
- fullLabel
+ fullLabel,
+ permissionDenied: denied
})
}
if (hasChildren) {
- flat.push(...flattenActions(action.children, fullLabel))
+ flat.push(
+ ...flattenActions(
+ action.children,
+ fullLabel,
+ userProfile,
+ model,
+ denied,
+ pageName
+ )
+ )
}
})
@@ -74,13 +108,14 @@ const ActionsModalProvider = ({ children }) => {
const [context, setContext] = useState({
id: null,
type: null,
- objectData: null
+ objectData: null,
+ pageName: 'info'
})
const inputRef = useRef(null)
- const showActionsModal = (id, type, objectData = null) => {
- setContext({ id, type, objectData })
+ const showActionsModal = (id, type, objectData = null, pageName = 'info') => {
+ setContext({ id, type, objectData, pageName })
setQuery('')
setVisible(true)
}
@@ -110,10 +145,17 @@ const ActionsModalProvider = ({ children }) => {
const ModelIcon = model?.icon || null
const modelLabel = model?.label || model?.name || ''
- const flattenedActions = useMemo(
- () => flattenActions(model?.actions || []),
- [model]
- )
+ const flattenedActions = useMemo(() => {
+ const pageName = context.pageName || 'info'
+ return flattenActions(
+ model?.actions || [],
+ '',
+ userProfile,
+ model,
+ false,
+ pageName
+ )
+ }, [model, userProfile, context.pageName])
const currentUrlWithoutActions = stripActionParam(
location.pathname,
@@ -146,6 +188,10 @@ const ActionsModalProvider = ({ children }) => {
}
}
+ if (action.permissionDenied) {
+ disabled = true
+ }
+
return disabled
}
diff --git a/src/components/Dashboard/context/ApiServerContext.jsx b/src/components/Dashboard/context/ApiServerContext.jsx
index b664d07e..e9ba4a74 100644
--- a/src/components/Dashboard/context/ApiServerContext.jsx
+++ b/src/components/Dashboard/context/ApiServerContext.jsx
@@ -1032,7 +1032,9 @@ const ApiServerProvider = ({ children }) => {
console.error(error.response.data.method)
const code = error.response.data.code || 'UNKNOWN'
if (code == 'UNAUTHORIZED') {
- setUnauthenticated()
+ if (token) {
+ setUnauthenticated()
+ }
return
}
if (code == 'FORBIDDEN') {
@@ -1056,7 +1058,7 @@ const ApiServerProvider = ({ children }) => {
setRetryCallback(() => callback)
setShowErrorModal(true)
},
- [setUnauthenticated]
+ [setUnauthenticated, token]
)
const handleRetry = () => {
diff --git a/src/components/Dashboard/context/AuthContext.jsx b/src/components/Dashboard/context/AuthContext.jsx
index f7cb529c..8fb38610 100644
--- a/src/components/Dashboard/context/AuthContext.jsx
+++ b/src/components/Dashboard/context/AuthContext.jsx
@@ -23,7 +23,7 @@ import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import config from '../../../config'
import loglevel from 'loglevel'
-import { ElectronContext } from './ElectronContext'
+import { ElectronContext, isElectron as detectIsElectron } from './ElectronContext'
import { useLocation, useNavigate } from 'react-router-dom'
import {
getAuthCookies,
@@ -59,14 +59,43 @@ const AuthProvider = ({ children }) => {
const [messageApi, contextHolder] = message.useMessage()
const [notificationApi, notificationContextHolder] =
notification.useNotification()
- const [authenticated, setAuthenticated] = useState(false)
+ const [initialWebAuth] = useState(() => {
+ if (detectIsElectron()) {
+ return { retrieved: false }
+ }
+ try {
+ if (validateAuthCookies()) {
+ const session = getAuthCookies()
+ return {
+ retrieved: true,
+ token: session.token,
+ expiresAt: session.expiresAt,
+ user: session.user,
+ authenticated: Boolean(session.token)
+ }
+ }
+ } catch (error) {
+ console.error('Error reading initial auth session:', error)
+ }
+ return {
+ retrieved: true,
+ token: null,
+ expiresAt: null,
+ user: null,
+ authenticated: false
+ }
+ })
+ const [authenticated, setAuthenticated] = useState(
+ Boolean(initialWebAuth.authenticated)
+ )
const [initialized, setInitialized] = useState(false)
- const [retreivedTokenFromCookies, setRetreivedTokenFromCookies] =
- useState(false)
+ const [retreivedTokenFromCookies, setRetreivedTokenFromCookies] = useState(
+ Boolean(initialWebAuth.retrieved)
+ )
const [loading, setLoading] = useState(false)
- const [token, setToken] = useState(null)
- const [expiresAt, setExpiresAt] = useState(null)
- const [userProfile, setUserProfile] = useState(null)
+ const [token, setToken] = useState(initialWebAuth.token ?? null)
+ const [expiresAt, setExpiresAt] = useState(initialWebAuth.expiresAt ?? null)
+ const [userProfile, setUserProfile] = useState(initialWebAuth.user ?? null)
const [profileImageUrl, setProfileImageUrl] = useState(null)
const profileImageUrlRef = useRef(null)
const processedAuthCodeRef = useRef(null)
@@ -83,6 +112,13 @@ const AuthProvider = ({ children }) => {
} = useContext(ElectronContext)
const location = useLocation()
const navigate = useNavigate()
+ const sessionRef = useRef({
+ token,
+ expiresAt,
+ userProfile,
+ authenticated
+ })
+ sessionRef.current = { token, expiresAt, userProfile, authenticated }
var redirectType = 'web'
@@ -158,7 +194,7 @@ const AuthProvider = ({ children }) => {
if (isElectron) return
if (!areCookiesEnabled()) {
messageApi.warning(
- 'Cookies are disabled. Login state may not persist between tabs.'
+ 'Browser storage is disabled. Login state may not persist between tabs.'
)
}
}, [messageApi, isElectron])
@@ -192,35 +228,31 @@ const AuthProvider = ({ children }) => {
setUserProfile(null)
setShowUnauthorizedModal(true)
}
- } else {
- // First validate existing cookies to clean up expired ones
- if (validateAuthCookies()) {
- const {
- token: storedToken,
- expiresAt: storedExpiresAt,
- user: storedUser
- } = getAuthCookies()
+ } else if (validateAuthCookies()) {
+ const {
+ token: storedToken,
+ expiresAt: storedExpiresAt,
+ user: storedUser
+ } = getAuthCookies()
- if (!cancelled) {
- setToken(storedToken)
- setUserProfile(storedUser)
- setExpiresAt(storedExpiresAt)
- setAuthenticated(true)
+ if (!cancelled) {
+ setToken(storedToken)
+ setUserProfile(storedUser)
+ setExpiresAt(storedExpiresAt)
+ setAuthenticated(true)
- if (storedToken && storedUser) {
- getUserInfo(storedToken, () => cancelled)
- }
+ if (storedToken) {
+ getUserInfo(storedToken, () => cancelled)
}
- } else if (!cancelled) {
- setAuthenticated(false)
- setUserProfile(null)
- setShowUnauthorizedModal(true)
}
+ } else if (!cancelled && !sessionRef.current.token) {
+ setAuthenticated(false)
+ setUserProfile(null)
+ setShowUnauthorizedModal(true)
}
} catch (error) {
console.error('Error loading persisted auth session:', error)
- await clearPersistedSession()
- if (!cancelled) {
+ if (!cancelled && !sessionRef.current.token) {
setAuthenticated(false)
setUserProfile(null)
setShowUnauthorizedModal(true)
@@ -243,11 +275,11 @@ const AuthProvider = ({ children }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps -- run only on mount to load persisted session; deps are stable in behavior
}, [])
- // Set up cookie synchronization between tabs
+ // Sync auth from other tabs. Only treat a missing token as logout — never
+ // drop a valid in-memory session because another tab is still booting.
useEffect(() => {
if (isElectron) return
const cleanupCookieSync = setupCookieSync(() => {
- // When cookies change in another tab, re-validate and update state
try {
if (validateAuthCookies()) {
const {
@@ -255,27 +287,34 @@ const AuthProvider = ({ children }) => {
expiresAt: newExpiresAt,
user: newUser
} = getAuthCookies()
+ const current = sessionRef.current
+ const expiresChanged =
+ String(newExpiresAt ?? '') !== String(current.expiresAt ?? '')
+ const userChanged =
+ newUser != null &&
+ JSON.stringify(newUser) !== JSON.stringify(current.userProfile)
if (
- newToken !== token ||
- newExpiresAt !== expiresAt ||
- JSON.stringify(newUser) !== JSON.stringify(userProfile)
+ newToken !== current.token ||
+ expiresChanged ||
+ userChanged
) {
setToken(newToken)
setExpiresAt(newExpiresAt)
- setUserProfile(newUser)
+ if (newUser) setUserProfile(newUser)
setAuthenticated(true)
+ setShowUnauthorizedModal(false)
logger.debug('Auth state synchronized from another tab')
}
} else {
- // Cookies are invalid, clear state
- setToken(null)
- setExpiresAt(null)
- setUserProfile(null)
- setAuthenticated(false)
- setShowUnauthorizedModal(true)
- logger.debug(
- 'Auth state cleared due to invalid cookies from another tab'
- )
+ const { token: storedToken } = getAuthCookies()
+ if (!storedToken && sessionRef.current.token) {
+ setToken(null)
+ setExpiresAt(null)
+ setUserProfile(null)
+ setAuthenticated(false)
+ setShowUnauthorizedModal(true)
+ logger.debug('Auth state cleared due to logout in another tab')
+ }
}
} catch (error) {
console.error('Error syncing auth state:', error)
@@ -283,7 +322,7 @@ const AuthProvider = ({ children }) => {
})
return cleanupCookieSync
- }, [token, expiresAt, userProfile, isElectron])
+ }, [isElectron])
// Persist userProfile changes to cookies/electron storage so updates (e.g. from
// WebSocket or profile edits) are saved for session restoration
@@ -535,16 +574,19 @@ const AuthProvider = ({ children }) => {
}
}, [token, messageApi, persistSession])
- const setUnauthenticated = () => {
+ const setUnauthenticated = useCallback(() => {
+ const hadSession = Boolean(sessionRef.current.token)
setToken(null)
setExpiresAt(null)
setUserProfile(null)
- clearPersistedSession()
setAuthenticated(false)
+ if (hadSession) {
+ clearPersistedSession()
+ }
if (showSessionExpiredModal == false) {
setShowUnauthorizedModal(true)
}
- }
+ }, [clearPersistedSession, showSessionExpiredModal])
const refreshToken = useCallback(async () => {
try {
diff --git a/src/database/ObjectModels.js b/src/database/ObjectModels.js
index b4a74897..f772d26b 100644
--- a/src/database/ObjectModels.js
+++ b/src/database/ObjectModels.js
@@ -245,10 +245,12 @@ export function getPermissionMatrixActions() {
;(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,
- label: action.label || action.name
+ type: action.type,
+ label: action.name === 'new' ? 'New' : action.label || action.name
})
}
})
@@ -258,7 +260,11 @@ export function getPermissionMatrixActions() {
export function modelHasPermissionAction(model, actionName) {
return (model?.actions || []).some(
- (action) => action?.name === actionName && action.type !== 'divider'
+ (action) =>
+ action?.name === actionName &&
+ action.type !== 'divider' &&
+ action.type !== 'alias' &&
+ action.type !== 'callback'
)
}
diff --git a/src/database/models/AppPassword.js b/src/database/models/AppPassword.js
index 4657e6ea..d0361ab2 100644
--- a/src/database/models/AppPassword.js
+++ b/src/database/models/AppPassword.js
@@ -4,11 +4,15 @@ const AppPasswordInfo = lazy(
() =>
import('../../components/Dashboard/Management/AppPasswords/AppPasswordInfo')
)
+const NewAppPassword = lazy(
+ () => import('../../components/Dashboard/Management/AppPasswords/NewAppPassword')
+)
const RegenerateAppPasswordSecret = lazy(
() =>
import('../../components/Dashboard/Management/AppPasswords/RegenerateAppPasswordSecret')
)
import AppPasswordIcon from '../../components/Icons/AppPasswordIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -23,6 +27,17 @@ export const AppPassword = {
prefix: 'APP',
icon: AppPasswordIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New App Password',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewAppPassword, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Client.js b/src/database/models/Client.js
index 17ea3099..1c380cd3 100644
--- a/src/database/models/Client.js
+++ b/src/database/models/Client.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const ClientInfo = lazy(
() => import('../../components/Dashboard/Sales/Clients/ClientInfo')
)
+const NewClient = lazy(
+ () => import('../../components/Dashboard/Sales/Clients/NewClient')
+)
import ClientIcon from '../../components/Icons/ClientIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const Client = {
prefix: 'CLI',
icon: ClientIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Client',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewClient, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Courier.js b/src/database/models/Courier.js
index 3e8cc113..0a8c4d13 100644
--- a/src/database/models/Courier.js
+++ b/src/database/models/Courier.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const CourierInfo = lazy(
() => import('../../components/Dashboard/Management/Couriers/CourierInfo')
)
+const NewCourier = lazy(
+ () => import('../../components/Dashboard/Management/Couriers/NewCourier')
+)
import CourierIcon from '../../components/Icons/CourierIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const Courier = {
prefix: 'COR',
icon: CourierIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Courier',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewCourier, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/CourierService.js b/src/database/models/CourierService.js
index e5b186d5..9de98067 100644
--- a/src/database/models/CourierService.js
+++ b/src/database/models/CourierService.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const CourierServiceInfo = lazy(
() => import('../../components/Dashboard/Management/CourierServices/CourierServiceInfo')
)
+const NewCourierService = lazy(
+ () => import('../../components/Dashboard/Management/CourierServices/NewCourierService')
+)
import CourierServiceIcon from '../../components/Icons/CourierServiceIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const CourierService = {
prefix: 'COS',
icon: CourierServiceIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Courier Service',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewCourierService, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/DocumentJob.js b/src/database/models/DocumentJob.js
index 35c864ff..ddeb5ede 100644
--- a/src/database/models/DocumentJob.js
+++ b/src/database/models/DocumentJob.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const DocumentJobInfo = lazy(
() => import('../../components/Dashboard/Management/DocumentJobs/DocumentJobInfo')
)
+const NewDocumentJob = lazy(
+ () => import('../../components/Dashboard/Management/DocumentJobs/NewDocumentJob')
+)
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -18,6 +22,17 @@ export const DocumentJob = {
prefix: 'DJB',
icon: DocumentJobIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 900,
+ label: 'New Document Job',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewDocumentJob, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/DocumentPrinter.js b/src/database/models/DocumentPrinter.js
index bcdcda95..7554efc2 100644
--- a/src/database/models/DocumentPrinter.js
+++ b/src/database/models/DocumentPrinter.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const DocumentPrinterInfo = lazy(
() => import('../../components/Dashboard/Management/DocumentPrinters/DocumentPrinterInfo')
)
+const NewDocumentPrinter = lazy(
+ () => import('../../components/Dashboard/Management/DocumentPrinters/NewDocumentPrinter')
+)
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -17,6 +21,17 @@ export const DocumentPrinter = {
prefix: 'DPR',
icon: DocumentPrinterIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Document Printer',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewDocumentPrinter, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/DocumentSize.js b/src/database/models/DocumentSize.js
index f1d74656..ca4745a2 100644
--- a/src/database/models/DocumentSize.js
+++ b/src/database/models/DocumentSize.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const DocumentSizeInfo = lazy(
() => import('../../components/Dashboard/Management/DocumentSizes/DocumentSizeInfo')
)
+const NewDocumentSize = lazy(
+ () => import('../../components/Dashboard/Management/DocumentSizes/NewDocumentSize')
+)
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -17,6 +21,17 @@ export const DocumentSize = {
prefix: 'DSZ',
icon: DocumentSizeIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Document Size',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewDocumentSize, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/DocumentTemplate.js b/src/database/models/DocumentTemplate.js
index 0c339da6..bd2a5a07 100644
--- a/src/database/models/DocumentTemplate.js
+++ b/src/database/models/DocumentTemplate.js
@@ -4,7 +4,11 @@ const DocumentTemplateInfo = lazy(
() =>
import('../../components/Dashboard/Management/DocumentTemplates/DocumentTemplateInfo')
)
+const NewDocumentTemplate = lazy(
+ () => import('../../components/Dashboard/Management/DocumentTemplates/NewDocumentTemplate')
+)
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -19,6 +23,17 @@ export const DocumentTemplate = {
prefix: 'DTP',
icon: DocumentTemplateIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Document Template',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewDocumentTemplate, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'design',
label: 'Design',
diff --git a/src/database/models/Filament.js b/src/database/models/Filament.js
index dff1d7eb..35eebbc6 100644
--- a/src/database/models/Filament.js
+++ b/src/database/models/Filament.js
@@ -3,15 +3,15 @@ import { createElement, lazy } from 'react'
const FilamentInfo = lazy(
() => import('../../components/Dashboard/Management/Filaments/FilamentInfo')
)
-const NewFilamentSku = lazy(
- () => import('../../components/Dashboard/Management/FilamentSkus/NewFilamentSku')
+const NewFilament = lazy(
+ () => import('../../components/Dashboard/Management/Filaments/NewFilament')
)
import EditIcon from '../../components/Icons/EditIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
import FilamentIcon from '../../components/Icons/FilamentIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
import BinIcon from '../../components/Icons/BinIcon'
export const Filament = {
@@ -22,6 +22,17 @@ export const Filament = {
prefix: 'FIL',
icon: FilamentIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Filament',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewFilament, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -65,16 +76,13 @@ export const Filament = {
{ type: 'divider' },
{
name: 'newFilamentSku',
- type: 'modal',
- modalWidth: 700,
- label: 'New Filament SKU',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'filamentSku',
+ aliasAction: 'new',
visible: (objectData) => {
return !(objectData?._isEditing && objectData?._isEditing == true)
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewFilamentSku, { defaultValues: { filament: objectData }, onOk, reset: true })
- }
+ objectData: (objectData) => ({ filament: objectData })
},
{ type: 'divider' },
{
diff --git a/src/database/models/FilamentProfile.js b/src/database/models/FilamentProfile.js
index 477ce5eb..41712544 100644
--- a/src/database/models/FilamentProfile.js
+++ b/src/database/models/FilamentProfile.js
@@ -4,7 +4,11 @@ const FilamentProfileInfo = lazy(
() =>
import('../../components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo')
)
+const NewFilamentProfile = lazy(
+ () => import('../../components/Dashboard/Production/FilamentProfiles/NewFilamentProfile')
+)
import FilamentProfileIcon from '../../components/Icons/FilamentProfileIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -19,6 +23,17 @@ export const FilamentProfile = {
prefix: 'FPF',
icon: FilamentProfileIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Filament Profile',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewFilamentProfile, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/FilamentSku.js b/src/database/models/FilamentSku.js
index 3aced3df..1e9fa6b7 100644
--- a/src/database/models/FilamentSku.js
+++ b/src/database/models/FilamentSku.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const FilamentSkuInfo = lazy(
() => import('../../components/Dashboard/Management/FilamentSkus/FilamentSkuInfo')
)
+const NewFilamentSku = lazy(
+ () => import('../../components/Dashboard/Management/FilamentSkus/NewFilamentSku')
+)
import FilamentSkuIcon from '../../components/Icons/FilamentSkuIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const FilamentSku = {
prefix: 'FSU',
icon: FilamentSkuIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Filament SKU',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewFilamentSku, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/FilamentStock.js b/src/database/models/FilamentStock.js
index 2358474d..8add1289 100644
--- a/src/database/models/FilamentStock.js
+++ b/src/database/models/FilamentStock.js
@@ -4,7 +4,11 @@ const FilamentStockInfo = lazy(
() =>
import('../../components/Dashboard/Inventory/FilamentStocks/FilamentStockInfo')
)
+const NewFilamentStock = lazy(
+ () => import('../../components/Dashboard/Inventory/FilamentStocks/NewFilamentStock')
+)
import FilamentStockIcon from '../../components/Icons/FilamentStockIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
export const FilamentStock = {
@@ -16,6 +20,17 @@ export const FilamentStock = {
readOnly: true,
icon: FilamentStockIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Filament Stock',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewFilamentStock, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/GCodeFile.js b/src/database/models/GCodeFile.js
index e1c861b8..4ef683af 100644
--- a/src/database/models/GCodeFile.js
+++ b/src/database/models/GCodeFile.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const GCodeFileInfo = lazy(
() => import('../../components/Dashboard/Production/GCodeFiles/GCodeFileInfo')
)
+const NewGCodeFile = lazy(
+ () => import('../../components/Dashboard/Production/GCodeFiles/NewGCodeFile')
+)
import DownloadIcon from '../../components/Icons/DownloadIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -19,6 +23,17 @@ export const GCodeFile = {
prefix: 'GCF',
icon: GCodeFileIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New G-Code File',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewGCodeFile, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'preview',
label: 'Preview',
diff --git a/src/database/models/Host.js b/src/database/models/Host.js
index 2fa6d591..49182249 100644
--- a/src/database/models/Host.js
+++ b/src/database/models/Host.js
@@ -3,10 +3,14 @@ import { createElement, lazy } from 'react'
const HostInfo = lazy(
() => import('../../components/Dashboard/Management/Hosts/HostInfo')
)
+const NewHost = lazy(
+ () => import('../../components/Dashboard/Management/Hosts/NewHost')
+)
const HostOTP = lazy(
() => import('../../components/Dashboard/Management/Hosts/HostOtp')
)
import HostIcon from '../../components/Icons/HostIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -22,6 +26,17 @@ export const Host = {
prefix: 'HST',
icon: HostIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Host',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewHost, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Invoice.js b/src/database/models/Invoice.js
index e9cb406f..1239e3cd 100644
--- a/src/database/models/Invoice.js
+++ b/src/database/models/Invoice.js
@@ -3,22 +3,22 @@ import { createElement, lazy } from 'react'
const InvoiceInfo = lazy(
() => import('../../components/Dashboard/Finance/Invoices/InvoiceInfo')
)
+const NewInvoice = lazy(
+ () => import('../../components/Dashboard/Finance/Invoices/NewInvoice')
+)
const PostInvoice = lazy(
() => import('../../components/Dashboard/Finance/Invoices/PostInvoice')
)
const AcknowledgeInvoice = lazy(
() => import('../../components/Dashboard/Finance/Invoices/AcknowledgeInvoice')
)
-const NewPayment = lazy(
- () => import('../../components/Dashboard/Finance/Payments/NewPayment')
-)
import InvoiceIcon from '../../components/Icons/InvoiceIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import EditIcon from '../../components/Icons/EditIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
import BinIcon from '../../components/Icons/BinIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
export const Invoice = {
name: 'invoice',
@@ -28,6 +28,17 @@ export const Invoice = {
prefix: 'INV',
icon: InvoiceIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Invoice',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewInvoice, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -88,24 +99,17 @@ export const Invoice = {
{ type: 'divider' },
{
name: 'newPayment',
- type: 'modal',
- modalWidth: 700,
- label: 'New Payment',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'payment',
+ aliasAction: 'new',
disabled: (objectData) => {
const allowedStates = ['acknowledged', 'partiallyPaid', 'overdue']
return !allowedStates.includes(objectData?.state?.type)
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewPayment, {
- defaultValues: {
- invoice: objectData,
- amount: objectData?.grandTotalAmount
- },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({
+ invoice: objectData,
+ amount: objectData?.grandTotalAmount
+ })
},
{ type: 'divider' },
{
diff --git a/src/database/models/Job.js b/src/database/models/Job.js
index a12121c1..73f63754 100644
--- a/src/database/models/Job.js
+++ b/src/database/models/Job.js
@@ -3,10 +3,14 @@ import { createElement, lazy } from 'react'
const JobInfo = lazy(
() => import('../../components/Dashboard/Production/Jobs/JobInfo')
)
+const NewJob = lazy(
+ () => import('../../components/Dashboard/Production/Jobs/NewJob')
+)
const DeployJob = lazy(
() => import('../../components/Dashboard/Production/Jobs/DeployJob')
)
import JobIcon from '../../components/Icons/JobIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -22,6 +26,17 @@ export const Job = {
prefix: 'JOB',
icon: JobIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Job',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewJob, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Listing.js b/src/database/models/Listing.js
index badb5e76..3021eb6e 100644
--- a/src/database/models/Listing.js
+++ b/src/database/models/Listing.js
@@ -3,9 +3,8 @@ import { createElement, lazy } from 'react'
const ListingInfo = lazy(
() => import('../../components/Dashboard/Sales/Listings/ListingInfo')
)
-const NewListingVarient = lazy(
- () =>
- import('../../components/Dashboard/Sales/ListingVarients/NewListingVarient')
+const NewListing = lazy(
+ () => import('../../components/Dashboard/Sales/Listings/NewListing')
)
const PublishListing = lazy(
() => import('../../components/Dashboard/Sales/Listings/PublishListing')
@@ -14,12 +13,12 @@ const UnpublishListing = lazy(
() => import('../../components/Dashboard/Sales/Listings/UnpublishListing')
)
import ListingIcon from '../../components/Icons/ListingIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
import BinIcon from '../../components/Icons/BinIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
export const Listing = {
name: 'listing',
@@ -29,6 +28,17 @@ export const Listing = {
prefix: 'LST',
icon: ListingIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Listing',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewListing, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -72,17 +82,10 @@ export const Listing = {
{ type: 'divider' },
{
name: 'newListingVarient',
- type: 'modal',
- modalWidth: 700,
- label: 'New Listing Varient',
- icon: PlusIcon,
- content: (objectData, { onOk } = {}) => {
- return createElement(NewListingVarient, {
- defaultValues: { listing: objectData },
- onOk,
- reset: true
- })
- }
+ type: 'alias',
+ objectType: 'listingVarient',
+ aliasAction: 'new',
+ objectData: (objectData) => ({ listing: objectData })
},
{ type: 'divider' },
{
diff --git a/src/database/models/ListingVarient.js b/src/database/models/ListingVarient.js
index ed3973af..fd8bfd65 100644
--- a/src/database/models/ListingVarient.js
+++ b/src/database/models/ListingVarient.js
@@ -3,6 +3,9 @@ import { createElement, lazy } from 'react'
const ListingVarientInfo = lazy(
() => import('../../components/Dashboard/Sales/ListingVarients/ListingVarientInfo')
)
+const NewListingVarient = lazy(
+ () => import('../../components/Dashboard/Sales/ListingVarients/NewListingVarient')
+)
const PublishListingVarient = lazy(
() => import('../../components/Dashboard/Sales/ListingVarients/PublishListingVarient')
)
@@ -10,6 +13,7 @@ const UnpublishListingVarient = lazy(
() => import('../../components/Dashboard/Sales/ListingVarients/UnpublishListingVarient')
)
import ListingVarientIcon from '../../components/Icons/ListingVarientIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -24,6 +28,17 @@ export const ListingVarient = {
prefix: 'LVR',
icon: ListingVarientIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Listing Varient',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewListingVarient, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Marketplace.js b/src/database/models/Marketplace.js
index d83d0827..b217a5f7 100644
--- a/src/database/models/Marketplace.js
+++ b/src/database/models/Marketplace.js
@@ -3,6 +3,9 @@ import { createElement, lazy } from 'react'
const MarketplaceInfo = lazy(
() => import('../../components/Dashboard/Sales/Marketplaces/MarketplaceInfo')
)
+const NewMarketplace = lazy(
+ () => import('../../components/Dashboard/Sales/Marketplaces/NewMarketplace')
+)
const SyncListings = lazy(
() => import('../../components/Dashboard/Sales/Marketplaces/SyncListings')
)
@@ -10,6 +13,7 @@ const SyncOrders = lazy(
() => import('../../components/Dashboard/Sales/Marketplaces/SyncOrders')
)
import MarketplaceIcon from '../../components/Icons/MarketplaceIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -26,6 +30,17 @@ export const Marketplace = {
prefix: 'MKT',
icon: MarketplaceIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Marketplace',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewMarketplace, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Material.js b/src/database/models/Material.js
index 7f35e6fc..95febbe8 100644
--- a/src/database/models/Material.js
+++ b/src/database/models/Material.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const MaterialInfo = lazy(
() => import('../../components/Dashboard/Management/Materials/MaterialInfo')
)
+const NewMaterial = lazy(
+ () => import('../../components/Dashboard/Management/Materials/NewMaterial')
+)
import MaterialIcon from '../../components/Icons/MaterialIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const Material = {
prefix: 'MAT',
icon: MaterialIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Material',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewMaterial, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/NoteType.js b/src/database/models/NoteType.js
index 66c3d227..d4721e9c 100644
--- a/src/database/models/NoteType.js
+++ b/src/database/models/NoteType.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const NoteTypeInfo = lazy(
() => import('../../components/Dashboard/Management/NoteTypes/NoteTypeInfo')
)
+const NewNoteType = lazy(
+ () => import('../../components/Dashboard/Management/NoteTypes/NewNoteType')
+)
import NoteTypeIcon from '../../components/Icons/NoteTypeIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -17,6 +21,17 @@ export const NoteType = {
prefix: 'NTY',
icon: NoteTypeIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Note Type',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewNoteType, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/OrderItem.js b/src/database/models/OrderItem.js
index f4c616ec..b8df8101 100644
--- a/src/database/models/OrderItem.js
+++ b/src/database/models/OrderItem.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const OrderItemInfo = lazy(
() => import('../../components/Dashboard/Inventory/OrderItems/OrderItemInfo')
)
+const NewOrderItem = lazy(
+ () => import('../../components/Dashboard/Inventory/OrderItems/NewOrderItem')
+)
import OrderItemIcon from '../../components/Icons/OrderItemIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const OrderItem = {
prefix: 'ODI',
icon: OrderItemIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Order Item',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewOrderItem, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Part.js b/src/database/models/Part.js
index 7e89a318..a8255ad5 100644
--- a/src/database/models/Part.js
+++ b/src/database/models/Part.js
@@ -3,15 +3,15 @@ import { createElement, lazy } from 'react'
const PartInfo = lazy(
() => import('../../components/Dashboard/Management/Parts/PartInfo')
)
-const NewPartSku = lazy(
- () => import('../../components/Dashboard/Management/PartSkus/NewPartSku')
+const NewPart = lazy(
+ () => import('../../components/Dashboard/Management/Parts/NewPart')
)
import EditIcon from '../../components/Icons/EditIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import PartIcon from '../../components/Icons/PartIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
export const Part = {
name: 'part',
@@ -21,6 +21,17 @@ export const Part = {
prefix: 'PRT',
icon: PartIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Part',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPart, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -64,16 +75,13 @@ export const Part = {
{ type: 'divider' },
{
name: 'newPartSku',
- type: 'modal',
- modalWidth: 700,
- label: 'New Part SKU',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'partSku',
+ aliasAction: 'new',
visible: (objectData) => {
return !(objectData?._isEditing && objectData?._isEditing == true)
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewPartSku, { defaultValues: { part: objectData }, onOk, reset: true })
- }
+ objectData: (objectData) => ({ part: objectData })
}
],
pages: [
diff --git a/src/database/models/PartSku.js b/src/database/models/PartSku.js
index 0d34cf33..9bdd1fa7 100644
--- a/src/database/models/PartSku.js
+++ b/src/database/models/PartSku.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const PartSkuInfo = lazy(
() => import('../../components/Dashboard/Management/PartSkus/PartSkuInfo')
)
+const NewPartSku = lazy(
+ () => import('../../components/Dashboard/Management/PartSkus/NewPartSku')
+)
import PartSkuIcon from '../../components/Icons/PartSkuIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const PartSku = {
prefix: 'PSU',
icon: PartSkuIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Part SKU',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPartSku, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/PartStock.js b/src/database/models/PartStock.js
index baf15d96..129b9384 100644
--- a/src/database/models/PartStock.js
+++ b/src/database/models/PartStock.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const PartStockInfo = lazy(
() => import('../../components/Dashboard/Inventory/PartStocks/PartStockInfo')
)
+const NewPartStock = lazy(
+ () => import('../../components/Dashboard/Inventory/PartStocks/NewPartStock')
+)
import PartStockIcon from '../../components/Icons/PartStockIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
export const PartStock = {
@@ -15,6 +19,17 @@ export const PartStock = {
readOnly: true,
icon: PartStockIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Part Stock',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPartStock, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Payment.js b/src/database/models/Payment.js
index 6f736644..e986657c 100644
--- a/src/database/models/Payment.js
+++ b/src/database/models/Payment.js
@@ -3,6 +3,9 @@ import { createElement, lazy } from 'react'
const PaymentInfo = lazy(
() => import('../../components/Dashboard/Finance/Payments/PaymentInfo')
)
+const NewPayment = lazy(
+ () => import('../../components/Dashboard/Finance/Payments/NewPayment')
+)
const PostPayment = lazy(
() => import('../../components/Dashboard/Finance/Payments/PostPayment')
)
@@ -16,6 +19,7 @@ const CancelPayment = lazy(
() => import('../../components/Dashboard/Finance/Payments/CancelPayment')
)
import PaymentIcon from '../../components/Icons/PaymentIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import EditIcon from '../../components/Icons/EditIcon'
@@ -30,6 +34,17 @@ export const Payment = {
prefix: 'PAY',
icon: PaymentIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Payment',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPayment, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/PermissionSetting.js b/src/database/models/PermissionSetting.js
index b38510da..c7015e08 100644
--- a/src/database/models/PermissionSetting.js
+++ b/src/database/models/PermissionSetting.js
@@ -4,7 +4,11 @@ const PermissionSettingInfo = lazy(
() =>
import('../../components/Dashboard/Management/PermissionSettings/PermissionSettingInfo')
)
+const NewPermissionSetting = lazy(
+ () => import('../../components/Dashboard/Management/PermissionSettings/NewPermissionSetting')
+)
import PermissionSettingIcon from '../../components/Icons/PermissionSettingIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -20,6 +24,17 @@ export const PermissionSetting = {
endpoint: 'permissionsettings',
icon: PermissionSettingIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Permission Setting',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPermissionSetting, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Printer.js b/src/database/models/Printer.js
index fa8fc48a..de9d6fae 100644
--- a/src/database/models/Printer.js
+++ b/src/database/models/Printer.js
@@ -3,9 +3,8 @@ import { createElement, lazy } from 'react'
const PrinterInfo = lazy(
() => import('../../components/Dashboard/Production/Printers/PrinterInfo')
)
-const NewPrinterProfile = lazy(
- () =>
- import('../../components/Dashboard/Production/PrinterProfiles/NewPrinterProfile')
+const NewPrinter = lazy(
+ () => import('../../components/Dashboard/Production/Printers/NewPrinter')
)
const LoadFilamentStock = lazy(
() =>
@@ -27,6 +26,7 @@ const RestartMoonraker = lazy(
import('../../components/Dashboard/Production/Printers/RestartMoonraker')
)
import PrinterIcon from '../../components/Icons/PrinterIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import ReloadIcon from '../../components/Icons/ReloadIcon'
import EditIcon from '../../components/Icons/EditIcon'
@@ -38,7 +38,6 @@ import StopCircleIcon from '../../components/Icons/StopCircleIcon'
import FilamentStockIcon from '../../components/Icons/FilamentStockIcon'
import ControlIcon from '../../components/Icons/ControlIcon'
import JobIcon from '../../components/Icons/JobIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
export const Printer = {
name: 'printer',
@@ -48,6 +47,17 @@ export const Printer = {
prefix: 'PRN',
icon: PrinterIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Printer',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPrinter, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -98,17 +108,10 @@ export const Printer = {
{ type: 'divider' },
{
name: 'newPrinterProfile',
- type: 'modal',
- modalWidth: 700,
- label: 'New Printer Profile',
- icon: PlusIcon,
- content: (objectData, { onOk } = {}) => {
- return createElement(NewPrinterProfile, {
- defaultValues: { printer: objectData },
- onOk,
- reset: true
- })
- }
+ type: 'alias',
+ objectType: 'printerProfile',
+ aliasAction: 'new',
+ objectData: (objectData) => ({ printer: objectData })
},
{ type: 'divider' },
{
diff --git a/src/database/models/PrinterProfile.js b/src/database/models/PrinterProfile.js
index cdbd7041..fc4ac001 100644
--- a/src/database/models/PrinterProfile.js
+++ b/src/database/models/PrinterProfile.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const PrinterProfileInfo = lazy(
() => import('../../components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo')
)
+const NewPrinterProfile = lazy(
+ () => import('../../components/Dashboard/Production/PrinterProfiles/NewPrinterProfile')
+)
import PrinterProfileIcon from '../../components/Icons/PrinterProfileIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -283,6 +287,17 @@ export const PrinterProfile = {
prefix: 'PPF',
icon: PrinterProfileIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Printer Profile',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPrinterProfile, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Product.js b/src/database/models/Product.js
index 80a5eccd..413f4100 100644
--- a/src/database/models/Product.js
+++ b/src/database/models/Product.js
@@ -3,15 +3,15 @@ import { createElement, lazy } from 'react'
const ProductInfo = lazy(
() => import('../../components/Dashboard/Management/Products/ProductInfo')
)
-const NewProductSku = lazy(
- () => import('../../components/Dashboard/Management/ProductSkus/NewProductSku')
+const NewProduct = lazy(
+ () => import('../../components/Dashboard/Management/Products/NewProduct')
)
import ProductIcon from '../../components/Icons/ProductIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
export const Product = {
name: 'product',
@@ -21,6 +21,17 @@ export const Product = {
prefix: 'PRD',
icon: ProductIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Product',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewProduct, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -66,16 +77,13 @@ export const Product = {
},
{
name: 'newProductSku',
- type: 'modal',
- modalWidth: 700,
- label: 'New Product SKU',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'productSku',
+ aliasAction: 'new',
visible: (objectData) => {
return !(objectData?._isEditing && objectData?._isEditing == true)
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewProductSku, { defaultValues: { product: objectData }, onOk, reset: true })
- }
+ objectData: (objectData) => ({ product: objectData })
}
],
pages: [
diff --git a/src/database/models/ProductCategory.js b/src/database/models/ProductCategory.js
index 069623a6..4de32e4f 100644
--- a/src/database/models/ProductCategory.js
+++ b/src/database/models/ProductCategory.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const ProductCategoryInfo = lazy(
() => import('../../components/Dashboard/Management/ProductCategories/ProductCategoryInfo')
)
+const NewProductCategory = lazy(
+ () => import('../../components/Dashboard/Management/ProductCategories/NewProductCategory')
+)
import ProductCategoryIcon from '../../components/Icons/ProductCategoryIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -19,6 +23,17 @@ export const ProductCategory = {
endpoint: 'productcategories',
icon: ProductCategoryIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Product Category',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewProductCategory, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/ProductSku.js b/src/database/models/ProductSku.js
index 7e23b5c0..0c2ab10e 100644
--- a/src/database/models/ProductSku.js
+++ b/src/database/models/ProductSku.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const ProductSkuInfo = lazy(
() => import('../../components/Dashboard/Management/ProductSkus/ProductSkuInfo')
)
+const NewProductSku = lazy(
+ () => import('../../components/Dashboard/Management/ProductSkus/NewProductSku')
+)
import ProductSkuIcon from '../../components/Icons/ProductSkuIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const ProductSku = {
prefix: 'SKU',
icon: ProductSkuIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Product SKU',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewProductSku, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/ProductStock.js b/src/database/models/ProductStock.js
index 83c8727c..0d1069b1 100644
--- a/src/database/models/ProductStock.js
+++ b/src/database/models/ProductStock.js
@@ -3,10 +3,14 @@ import { createElement, lazy } from 'react'
const ProductStockInfo = lazy(
() => import('../../components/Dashboard/Inventory/ProductStocks/ProductStockInfo')
)
+const NewProductStock = lazy(
+ () => import('../../components/Dashboard/Inventory/ProductStocks/NewProductStock')
+)
const PostProductStock = lazy(
() => import('../../components/Dashboard/Inventory/ProductStocks/PostProductStock')
)
import ProductStockIcon from '../../components/Icons/ProductStockIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import { getModelByName } from '../ObjectModels.js'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
@@ -22,6 +26,17 @@ export const ProductStock = {
prefix: 'PDS',
icon: ProductStockIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Product Stock',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewProductStock, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/PurchaseOrder.js b/src/database/models/PurchaseOrder.js
index f9a721d8..124121f6 100644
--- a/src/database/models/PurchaseOrder.js
+++ b/src/database/models/PurchaseOrder.js
@@ -3,14 +3,8 @@ import { createElement, lazy } from 'react'
const PurchaseOrderInfo = lazy(
() => import('../../components/Dashboard/Inventory/PurchaseOrders/PurchaseOrderInfo')
)
-const NewOrderItem = lazy(
- () => import('../../components/Dashboard/Inventory/OrderItems/NewOrderItem')
-)
-const NewShipment = lazy(
- () => import('../../components/Dashboard/Inventory/Shipments/NewShipment')
-)
-const NewInvoice = lazy(
- () => import('../../components/Dashboard/Finance/Invoices/NewInvoice')
+const NewPurchaseOrder = lazy(
+ () => import('../../components/Dashboard/Inventory/PurchaseOrders/NewPurchaseOrder')
)
const PostPurchaseOrder = lazy(
() => import('../../components/Dashboard/Inventory/PurchaseOrders/PostPurchaseOrder')
@@ -22,8 +16,8 @@ const CancelPurchaseOrder = lazy(
() => import('../../components/Dashboard/Inventory/PurchaseOrders/CancelPurchaseOrder')
)
import PurchaseOrderIcon from '../../components/Icons/PurchaseOrderIcon'
-import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import PlusIcon from '../../components/Icons/PlusIcon'
+import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import EditIcon from '../../components/Icons/EditIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -37,6 +31,17 @@ export const PurchaseOrder = {
prefix: 'POR',
icon: PurchaseOrderIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Purchase Order',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewPurchaseOrder, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -97,48 +102,36 @@ export const PurchaseOrder = {
{ type: 'divider' },
{
name: 'newOrderItem',
- type: 'modal',
- modalWidth: 700,
- label: 'New Order Item',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'orderItem',
+ aliasAction: 'new',
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewOrderItem, {
- defaultValues: {
- order: { _id: objectData._id },
- orderType: 'purchaseOrder',
- syncAmount: 'itemCost'
- },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({
+ order: { _id: objectData._id },
+ orderType: 'purchaseOrder',
+ syncAmount: 'itemCost'
+ })
},
{
name: 'newShipment',
- type: 'modal',
- modalWidth: 700,
- label: 'New Shipment',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'shipment',
+ aliasAction: 'new',
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewShipment, {
- defaultValues: { orderType: 'purchaseOrder', order: { _id: objectData._id } },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({
+ orderType: 'purchaseOrder',
+ order: { _id: objectData._id }
+ })
},
{
name: 'newInvoice',
- type: 'modal',
- modalWidth: 700,
- label: 'New Invoice',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'invoice',
+ aliasAction: 'new',
disabled: (objectData) => {
const allowedStates = [
'received',
@@ -148,13 +141,7 @@ export const PurchaseOrder = {
]
return !allowedStates.includes(objectData?.state?.type)
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewInvoice, {
- defaultValues: { orderType: 'purchaseOrder', order: objectData },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({ orderType: 'purchaseOrder', order: objectData })
},
{
type: 'divider'
diff --git a/src/database/models/SalesOrder.js b/src/database/models/SalesOrder.js
index 8e803913..55d4518c 100644
--- a/src/database/models/SalesOrder.js
+++ b/src/database/models/SalesOrder.js
@@ -3,14 +3,8 @@ import { createElement, lazy } from 'react'
const SalesOrderInfo = lazy(
() => import('../../components/Dashboard/Sales/SalesOrders/SalesOrderInfo')
)
-const NewOrderItem = lazy(
- () => import('../../components/Dashboard/Inventory/OrderItems/NewOrderItem')
-)
-const NewShipment = lazy(
- () => import('../../components/Dashboard/Inventory/Shipments/NewShipment')
-)
-const NewInvoice = lazy(
- () => import('../../components/Dashboard/Finance/Invoices/NewInvoice')
+const NewSalesOrder = lazy(
+ () => import('../../components/Dashboard/Sales/SalesOrders/NewSalesOrder')
)
const PostSalesOrder = lazy(
() => import('../../components/Dashboard/Sales/SalesOrders/PostSalesOrder')
@@ -22,8 +16,8 @@ const CancelSalesOrder = lazy(
() => import('../../components/Dashboard/Sales/SalesOrders/CancelSalesOrder')
)
import SalesOrderIcon from '../../components/Icons/SalesOrderIcon'
-import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import PlusIcon from '../../components/Icons/PlusIcon'
+import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import EditIcon from '../../components/Icons/EditIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
@@ -37,6 +31,17 @@ export const SalesOrder = {
prefix: 'SOR',
icon: SalesOrderIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Sales Order',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewSalesOrder, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
@@ -97,53 +102,38 @@ export const SalesOrder = {
{ type: 'divider' },
{
name: 'newOrderItem',
- type: 'modal',
- modalWidth: 700,
- label: 'New Order Item',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'orderItem',
+ aliasAction: 'new',
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewOrderItem, {
- defaultValues: {
- order: { _id: objectData._id },
- orderType: 'salesOrder',
- syncAmount: 'itemPrice'
- },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({
+ order: { _id: objectData._id },
+ orderType: 'salesOrder',
+ syncAmount: 'itemPrice'
+ })
},
{
name: 'newShipment',
- type: 'modal',
- modalWidth: 700,
+ type: 'alias',
+ objectType: 'shipment',
+ aliasAction: 'new',
modalCentered: false,
- label: 'New Shipment',
- icon: PlusIcon,
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewShipment, {
- defaultValues: {
- orderType: 'salesOrder',
- order: { _id: objectData._id }
- },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({
+ orderType: 'salesOrder',
+ order: { _id: objectData._id }
+ })
},
{
name: 'newInvoice',
- type: 'modal',
- modalWidth: 700,
+ type: 'alias',
+ objectType: 'invoice',
+ aliasAction: 'new',
modalCentered: false,
- label: 'New Invoice',
- icon: PlusIcon,
disabled: (objectData) => {
const allowedStates = [
'delivered',
@@ -155,13 +145,7 @@ export const SalesOrder = {
]
return !allowedStates.includes(objectData?.state?.type)
},
- content: (objectData, { onOk } = {}) => {
- return createElement(NewInvoice, {
- defaultValues: { orderType: 'salesOrder', order: objectData },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({ orderType: 'salesOrder', order: objectData })
},
{ type: 'divider' },
{
diff --git a/src/database/models/Shipment.js b/src/database/models/Shipment.js
index 49b42d31..dac7f0dc 100644
--- a/src/database/models/Shipment.js
+++ b/src/database/models/Shipment.js
@@ -3,6 +3,9 @@ import { createElement, lazy } from 'react'
const ShipmentInfo = lazy(
() => import('../../components/Dashboard/Inventory/Shipments/ShipmentInfo')
)
+const NewShipment = lazy(
+ () => import('../../components/Dashboard/Inventory/Shipments/NewShipment')
+)
const ShipShipment = lazy(
() => import('../../components/Dashboard/Inventory/Shipments/ShipShipment')
)
@@ -13,6 +16,7 @@ const CancelShipment = lazy(
() => import('../../components/Dashboard/Inventory/Shipments/CancelShipment')
)
import ShipmentIcon from '../../components/Icons/ShipmentIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import BinIcon from '../../components/Icons/BinIcon'
@@ -27,6 +31,17 @@ export const Shipment = {
prefix: 'SHP',
icon: ShipmentIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Shipment',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewShipment, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/StockAudit.js b/src/database/models/StockAudit.js
index 9e54c586..7a7f9cc0 100644
--- a/src/database/models/StockAudit.js
+++ b/src/database/models/StockAudit.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const StockAuditInfo = lazy(
() => import('../../components/Dashboard/Inventory/StockAudits/StockAuditInfo')
)
+const NewStockAudit = lazy(
+ () => import('../../components/Dashboard/Inventory/StockAudits/NewStockAudit')
+)
import StockAuditIcon from '../../components/Icons/StockAuditIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -17,6 +21,17 @@ export const StockAudit = {
prefix: 'SAU',
icon: StockAuditIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 800,
+ label: 'New Stock Audit',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewStockAudit, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/StockLocation.js b/src/database/models/StockLocation.js
index 0fe6d8c7..600ed04a 100644
--- a/src/database/models/StockLocation.js
+++ b/src/database/models/StockLocation.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const StockLocationInfo = lazy(
() => import('../../components/Dashboard/Inventory/StockLocations/StockLocationInfo')
)
+const NewStockLocation = lazy(
+ () => import('../../components/Dashboard/Inventory/StockLocations/NewStockLocation')
+)
import StockLocationIcon from '../../components/Icons/StockLocationIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -17,6 +21,17 @@ export const StockLocation = {
prefix: 'SLN',
icon: StockLocationIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 640,
+ label: 'New Stock Location',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewStockLocation, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/StockTransfer.js b/src/database/models/StockTransfer.js
index 6137cfc2..313a72fd 100644
--- a/src/database/models/StockTransfer.js
+++ b/src/database/models/StockTransfer.js
@@ -3,10 +3,14 @@ import { createElement, lazy } from 'react'
const StockTransferInfo = lazy(
() => import('../../components/Dashboard/Inventory/StockTransfers/StockTransferInfo')
)
+const NewStockTransfer = lazy(
+ () => import('../../components/Dashboard/Inventory/StockTransfers/NewStockTransfer')
+)
const PostStockTransfer = lazy(
() => import('../../components/Dashboard/Inventory/StockTransfers/PostStockTransfer')
)
import StockTransferIcon from '../../components/Icons/StockTransferIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -21,6 +25,17 @@ export const StockTransfer = {
prefix: 'STT',
icon: StockTransferIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 740,
+ label: 'New Stock Transfer',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewStockTransfer, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/TaxRate.js b/src/database/models/TaxRate.js
index 5c62c3ac..85f37f13 100644
--- a/src/database/models/TaxRate.js
+++ b/src/database/models/TaxRate.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const TaxRateInfo = lazy(
() => import('../../components/Dashboard/Management/TaxRates/TaxRateInfo')
)
+const NewTaxRate = lazy(
+ () => import('../../components/Dashboard/Management/TaxRates/NewTaxRate')
+)
import TaxRateIcon from '../../components/Icons/TaxRateIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const TaxRate = {
prefix: 'TXR',
icon: TaxRateIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Tax Rate',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewTaxRate, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/TaxRecord.js b/src/database/models/TaxRecord.js
index b0f17173..ea592bbd 100644
--- a/src/database/models/TaxRecord.js
+++ b/src/database/models/TaxRecord.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const TaxRecordInfo = lazy(
() => import('../../components/Dashboard/Finance/TaxRecords/TaxRecordInfo')
)
+const NewTaxRecord = lazy(
+ () => import('../../components/Dashboard/Finance/TaxRecords/NewTaxRecord')
+)
import TaxRecordIcon from '../../components/Icons/TaxRecordIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const TaxRecord = {
prefix: 'TXR',
icon: TaxRecordIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Tax Record',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewTaxRecord, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/User.js b/src/database/models/User.js
index 61ac11fe..2efc1fe8 100644
--- a/src/database/models/User.js
+++ b/src/database/models/User.js
@@ -3,16 +3,11 @@ import { createElement, lazy } from 'react'
const UserInfo = lazy(
() => import('../../components/Dashboard/Management/Users/UserInfo')
)
-const NewAppPassword = lazy(
- () =>
- import('../../components/Dashboard/Management/AppPasswords/NewAppPassword')
-)
import PersonIcon from '../../components/Icons/PersonIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
-import PlusIcon from '../../components/Icons/PlusIcon'
import { calculateUserPermissions } from '../permissions.js'
export const User = {
@@ -65,21 +60,13 @@ export const User = {
},
{
name: 'newAppPassword',
- type: 'modal',
- modalWidth: 680,
- label: 'New App Password',
- icon: PlusIcon,
+ type: 'alias',
+ objectType: 'appPassword',
+ aliasAction: 'new',
disabled: (objectData) => {
return objectData?._user?._id != objectData?._id
},
- content: (objectData, { onOk } = {}) => {
- console.log('newAppPassword objectData', objectData)
- return createElement(NewAppPassword, {
- defaultValues: { user: objectData._user },
- onOk,
- reset: true
- })
- }
+ objectData: (objectData) => ({ user: objectData })
}
],
pages: [
diff --git a/src/database/models/UserGroup.js b/src/database/models/UserGroup.js
index 81ab6708..189fecd0 100644
--- a/src/database/models/UserGroup.js
+++ b/src/database/models/UserGroup.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const UserGroupInfo = lazy(
() => import('../../components/Dashboard/Management/UserGroups/UserGroupInfo')
)
+const NewUserGroup = lazy(
+ () => import('../../components/Dashboard/Management/UserGroups/NewUserGroup')
+)
import PersonGroupIcon from '../../components/Icons/PersonGroupIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -19,6 +23,17 @@ export const UserGroup = {
prefix: 'UGP',
icon: PersonGroupIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New User Group',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewUserGroup, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/models/Vendor.js b/src/database/models/Vendor.js
index 3475eee1..27363b3c 100644
--- a/src/database/models/Vendor.js
+++ b/src/database/models/Vendor.js
@@ -3,7 +3,11 @@ import { createElement, lazy } from 'react'
const VendorInfo = lazy(
() => import('../../components/Dashboard/Management/Vendors/VendorInfo')
)
+const NewVendor = lazy(
+ () => import('../../components/Dashboard/Management/Vendors/NewVendor')
+)
import VendorIcon from '../../components/Icons/VendorIcon'
+import PlusIcon from '../../components/Icons/PlusIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
@@ -18,6 +22,17 @@ export const Vendor = {
prefix: 'VEN',
icon: VendorIcon,
actions: [
+ {
+ name: 'new',
+ type: 'modal',
+ pageName: 'list',
+ modalWidth: 700,
+ label: 'New Vendor',
+ icon: PlusIcon,
+ content: (objectData, { onOk } = {}) => {
+ return createElement(NewVendor, { defaultValues: objectData, onOk, reset: true })
+ }
+ },
{
name: 'info',
type: 'page',
diff --git a/src/database/permissions.js b/src/database/permissions.js
index 52cbf461..7698c0ca 100644
--- a/src/database/permissions.js
+++ b/src/database/permissions.js
@@ -36,3 +36,34 @@ export const calculateUserPermissions = (objectData = {}) =>
export const calculateUserGroupPermissions = (objectData = {}) =>
applyPermissionSettingsList(objectData.permissionSettings)
+
+const PERMISSION_ACTION_ALIASES = {
+ cancelEdit: 'edit',
+ finishEdit: 'edit'
+}
+
+export const getPermissionActionName = (actionName) =>
+ PERMISSION_ACTION_ALIASES[actionName] || actionName
+
+const isTopLevelModelAction = (model, actionName) =>
+ (model?.actions || []).some(
+ (action) =>
+ action?.name === actionName &&
+ action.type !== 'divider' &&
+ action.type !== 'alias' &&
+ action.type !== 'callback'
+ )
+
+export const hasActionPermission = (userProfile, model, actionName) => {
+ if (!actionName) return true
+
+ const permissionAction = getPermissionActionName(actionName)
+ const isControlled =
+ Boolean(PERMISSION_ACTION_ALIASES[actionName]) ||
+ isTopLevelModelAction(model, actionName)
+
+ if (!isControlled) return true
+
+ const modelName = typeof model === 'string' ? model : model?.name
+ return userProfile?.permissions?.[modelName]?.[permissionAction] === true
+}
diff --git a/src/utils/cookies.js b/src/utils/cookies.js
index 74403756..1e63f2d1 100644
--- a/src/utils/cookies.js
+++ b/src/utils/cookies.js
@@ -6,16 +6,62 @@ const COOKIE_OPTIONS = {
maxAge: 7 * 24 * 60 * 60 // 7 days in seconds
}
+const AUTH_STORAGE_KEY = 'farmcontrol.auth'
+const LEGACY_AUTH_COOKIE_NAMES = ['authToken', 'authExpiresAt', 'user']
+
const getAuthExpiryTime = (expiresAt) => {
const numericExpiry = Number(expiresAt)
if (Number.isFinite(numericExpiry) && numericExpiry > 0) return numericExpiry
return new Date(expiresAt).getTime()
}
-const getAuthCookieMaxAge = (expiresAt) => {
- const expiryTime = getAuthExpiryTime(expiresAt)
- if (!Number.isFinite(expiryTime)) return COOKIE_OPTIONS.maxAge
- return Math.max(Math.floor((expiryTime - Date.now()) / 1000), 1)
+const toStoredUser = (user) => {
+ if (!user || typeof user !== 'object') return user ?? null
+ const stored = { ...user }
+ delete stored.access_token
+ delete stored.refresh_token
+ delete stored.id_token
+ return stored
+}
+
+const parseStoredSession = (raw) => {
+ if (!raw) return { token: null, expiresAt: null, user: null }
+ const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw
+ return {
+ token: parsed.access_token || parsed.token || null,
+ expiresAt: parsed.expires_at || parsed.expiresAt || null,
+ user: parsed.user || null
+ }
+}
+
+const getLegacyAuthCookies = () => {
+ const userCookie = getCookie('user')
+ let user = null
+ if (userCookie) {
+ try {
+ user = JSON.parse(userCookie)
+ } catch (error) {
+ console.error('Error parsing legacy auth user cookie:', error)
+ }
+ }
+ return {
+ token: getCookie('authToken'),
+ expiresAt: getCookie('authExpiresAt'),
+ user
+ }
+}
+
+const clearLegacyAuthCookies = () => {
+ LEGACY_AUTH_COOKIE_NAMES.forEach((name) => removeCookie(name))
+}
+
+const serializeAuthSession = (authData, fallbackUser = null) => {
+ const payload = {
+ access_token: authData.access_token,
+ expires_at: getAuthExpiryTime(authData.expires_at),
+ user: toStoredUser(authData.user) ?? fallbackUser ?? null
+ }
+ return JSON.stringify(payload)
}
/**
@@ -126,6 +172,16 @@ export const removeCookie = (name, options = {}) => {
* @returns {boolean} - True if cookies are enabled
*/
export const areCookiesEnabled = () => {
+ try {
+ const key = '__farmcontrol_auth_test__'
+ window.localStorage.setItem(key, '1')
+ const enabled = window.localStorage.getItem(key) === '1'
+ window.localStorage.removeItem(key)
+ if (enabled) return true
+ } catch (e) {
+ console.error('Error checking if localStorage is enabled:', e)
+ }
+
try {
setCookie('test', 'test')
const enabled = getCookie('test') === 'test'
@@ -143,9 +199,9 @@ export const areCookiesEnabled = () => {
*/
export const validateAuthCookies = () => {
try {
- const { token, expiresAt, user } = getAuthCookies()
+ const { token, expiresAt } = getAuthCookies()
- if (!token || !expiresAt || !user) {
+ if (!token || !expiresAt) {
return false
}
@@ -153,15 +209,13 @@ export const validateAuthCookies = () => {
const expirationTime = getAuthExpiryTime(expiresAt)
if (!Number.isFinite(expirationTime) || expirationTime <= now) {
- // Cookies are expired, clean them up
clearAuthCookies()
return false
}
return true
} catch (error) {
- console.error('Error validating auth cookies:', error)
- clearAuthCookies()
+ console.error('Error validating auth session:', error)
return false
}
}
@@ -173,9 +227,9 @@ export const validateAuthCookies = () => {
*/
export const checkAuthCookiesExpiry = (minutesBeforeExpiry = 5) => {
try {
- const { token, expiresAt, user } = getAuthCookies()
+ const { token, expiresAt } = getAuthCookies()
- if (!token || !expiresAt || !user) {
+ if (!token || !expiresAt) {
return { isExpiringSoon: false, timeRemaining: 0 }
}
@@ -200,40 +254,19 @@ export const checkAuthCookiesExpiry = (minutesBeforeExpiry = 5) => {
*/
export const setupCookieSync = (onAuthChange) => {
const handleStorageChange = (event) => {
- // Check if auth-related cookies changed
if (
- event.key === 'authToken' ||
- event.key === 'authExpiresAt' ||
- event.key === 'user'
+ event.key === AUTH_STORAGE_KEY ||
+ event.key === null ||
+ LEGACY_AUTH_COOKIE_NAMES.includes(event.key)
) {
- // Small delay to ensure cookies are updated
- setTimeout(() => {
- onAuthChange()
- }, 100)
+ onAuthChange()
}
}
- // Listen for storage events (for cross-tab communication)
window.addEventListener('storage', handleStorageChange)
- // Also listen for cookie changes using a polling mechanism
- let lastCookieState = document.cookie
- const cookieCheckInterval = setInterval(() => {
- const currentCookieState = document.cookie
- if (currentCookieState !== lastCookieState) {
- lastCookieState = currentCookieState
- // Check if auth cookies changed
- const authCookies = getAuthCookies()
- if (authCookies.token || authCookies.expiresAt || authCookies.user) {
- onAuthChange()
- }
- }
- }, 1000)
-
- // Return cleanup function
return () => {
window.removeEventListener('storage', handleStorageChange)
- clearInterval(cookieCheckInterval)
}
}
@@ -244,53 +277,22 @@ export const setupCookieSync = (onAuthChange) => {
*/
export const setAuthCookies = (authData) => {
try {
- if (!authData) {
+ if (!authData?.access_token || !authData?.expires_at) {
console.warn('Auth data is required')
return false
}
- let success = true
- const maxAge = getAuthCookieMaxAge(authData.expires_at)
-
- if (authData.access_token) {
- success =
- success &&
- setCookie('authToken', authData.access_token, {
- maxAge
- })
+ const existing = getAuthCookies()
+ const serialized = serializeAuthSession(authData, existing.user)
+ if (window.localStorage.getItem(AUTH_STORAGE_KEY) === serialized) {
+ return true
}
- if (authData.expires_at) {
- success =
- success &&
- setCookie('authExpiresAt', authData.expires_at, {
- maxAge
- })
- }
-
- if (authData.user) {
- const userObject = {
- ...authData.user,
- access_token: undefined,
- refresh_token: undefined,
- id_token: undefined
- }
- success =
- success &&
- setCookie('user', JSON.stringify(userObject), {
- maxAge
- })
- }
-
- if (!success) {
- console.warn('Some cookies failed to set, clearing all auth cookies')
- clearAuthCookies()
- }
-
- return success
+ window.localStorage.setItem(AUTH_STORAGE_KEY, serialized)
+ clearLegacyAuthCookies()
+ return true
} catch (error) {
- console.error('Error setting auth cookies:', error)
- clearAuthCookies()
+ console.error('Error setting auth session:', error)
return false
}
}
@@ -300,18 +302,26 @@ export const setAuthCookies = (authData) => {
* @returns {Object} - Object containing auth data from cookies
*/
export const getAuthCookies = () => {
- return {
- token: getCookie('authToken'),
- expiresAt: getCookie('authExpiresAt'),
- user: getCookie('user') ? JSON.parse(getCookie('user')) : null
+ try {
+ const raw = window.localStorage.getItem(AUTH_STORAGE_KEY)
+ if (raw) {
+ return parseStoredSession(raw)
+ }
+ } catch (error) {
+ console.error('Error reading auth session from localStorage:', error)
}
+
+ return getLegacyAuthCookies()
}
/**
* Clear authentication cookies
*/
export const clearAuthCookies = () => {
- removeCookie('authToken')
- removeCookie('authExpiresAt')
- removeCookie('user')
+ try {
+ window.localStorage.removeItem(AUTH_STORAGE_KEY)
+ } catch (error) {
+ console.error('Error clearing auth session from localStorage:', error)
+ }
+ clearLegacyAuthCookies()
}
diff --git a/src/utils/modelActions.js b/src/utils/modelActions.js
index 866787c5..57ad7cfa 100644
--- a/src/utils/modelActions.js
+++ b/src/utils/modelActions.js
@@ -1,7 +1,54 @@
+import { getModelByName } from '../database/ObjectModels'
+
export function getObjectIdParamName(modelName) {
return `${modelName}Id`
}
+export function actionVisibleOnPage(action, pageName) {
+ if (!action) return false
+ if (action.type === 'divider') return true
+ if (Array.isArray(action.pages) && action.pages.length > 0) {
+ return action.pages.includes(pageName)
+ }
+ if (action.type !== 'page' && action.pageName) {
+ return action.pageName === pageName
+ }
+ if (action.name === 'new') return pageName === 'list'
+ return pageName !== 'list'
+}
+
+export function resolveAction(action) {
+ if (!action || action.type !== 'alias') return action
+ const targetModel = getModelByName(action.objectType)
+ const target = findAction(targetModel, action.aliasAction)
+ if (!target) return action
+ return {
+ ...target,
+ ...action,
+ type: 'alias',
+ label: action.label || target.label,
+ icon: action.icon || target.icon,
+ modalWidth: action.modalWidth ?? target.modalWidth,
+ modalCentered: action.modalCentered ?? target.modalCentered,
+ content: target.content
+ }
+}
+
+export function getActionPermissionTarget(action, sourceModel) {
+ if (action?.type === 'alias') {
+ const targetModel = getModelByName(action.objectType)
+ const resolved = resolveAction(action)
+ return {
+ model: targetModel || action.objectType,
+ actionName: action.aliasAction || resolved?.name
+ }
+ }
+ return {
+ model: sourceModel,
+ actionName: action?.name
+ }
+}
+
export function getObjectIdFromSearch(modelName, search) {
const params = new URLSearchParams(search)
return params.get(getObjectIdParamName(modelName))