shutro-erp 0.3.6 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account_asset/.kosh/bindings.js +1 -1
- package/dist/account_asset/.kosh/schema.d.ts +530 -8
- package/dist/account_asset/i18n/bn.d.ts +2 -0
- package/dist/account_asset/i18n/bn.js +97 -0
- package/dist/account_asset/index.js +2 -0
- package/dist/account_asset/module.d.ts +4899 -1445
- package/dist/account_budget/.kosh/bindings.js +1 -1
- package/dist/account_budget/.kosh/schema.d.ts +1130 -56
- package/dist/account_budget/i18n/bn.d.ts +2 -0
- package/dist/account_budget/i18n/bn.js +63 -0
- package/dist/account_budget/index.js +14 -0
- package/dist/account_budget/module.d.ts +17958 -4532
- package/dist/account_budget/module.js +15 -0
- package/dist/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +530 -8
- package/dist/account_portal/i18n/bn.d.ts +2 -0
- package/dist/account_portal/i18n/bn.js +6 -0
- package/dist/account_portal/index.js +2 -0
- package/dist/account_portal/module.d.ts +5167 -1693
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +530 -8
- package/dist/accounting/closing.js +1 -0
- package/dist/accounting/fiscal.d.ts +578 -0
- package/dist/accounting/fiscal.js +401 -0
- package/dist/accounting/followups.d.ts +618 -0
- package/dist/accounting/followups.js +420 -0
- package/dist/accounting/i18n/bn.d.ts +2 -0
- package/dist/accounting/i18n/bn.js +425 -0
- package/dist/accounting/index.d.ts +2 -0
- package/dist/accounting/index.js +649 -2
- package/dist/accounting/module.d.ts +4998 -1451
- package/dist/accounting/module.js +124 -18
- package/dist/accounting/statements.d.ts +878 -0
- package/dist/accounting/statements.js +728 -0
- package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
- package/dist/accounting/web/BankReconcilePage.js +138 -0
- package/dist/accounting/web/FollowupsPage.d.ts +8 -0
- package/dist/accounting/web/FollowupsPage.js +54 -0
- package/dist/accounting/web/PostingPreview.d.ts +8 -0
- package/dist/accounting/web/PostingPreview.js +26 -0
- package/dist/accounting/web/index.d.ts +3 -0
- package/dist/accounting/web/index.js +9 -0
- package/dist/accounting/web/messages.js +140 -0
- package/dist/approvals/.kosh/bindings.js +1 -1
- package/dist/approvals/.kosh/schema.d.ts +272 -4
- package/dist/approvals/demo.d.ts +7 -0
- package/dist/approvals/demo.js +41 -0
- package/dist/approvals/i18n/bn.d.ts +2 -0
- package/dist/approvals/i18n/bn.js +133 -0
- package/dist/approvals/index.d.ts +19 -1
- package/dist/approvals/index.js +477 -7
- package/dist/approvals/mails.d.ts +7 -2
- package/dist/approvals/mails.js +8 -3
- package/dist/approvals/module.d.ts +2930 -1
- package/dist/approvals/module.js +468 -7
- package/dist/approvals/web/Config.d.ts +12 -0
- package/dist/approvals/web/Config.js +60 -0
- package/dist/approvals/web/Matrix.d.ts +9 -0
- package/dist/approvals/web/Matrix.js +26 -0
- package/dist/approvals/web/index.d.ts +3 -1
- package/dist/approvals/web/index.js +8 -1
- package/dist/approvals/web/messages.js +92 -0
- package/dist/approvals_purchase/.kosh/bindings.js +15 -0
- package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
- package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
- package/dist/approvals_purchase/i18n/bn.js +5 -0
- package/dist/approvals_purchase/index.d.ts +3 -0
- package/dist/approvals_purchase/index.js +47 -0
- package/dist/approvals_purchase/module.d.ts +12670 -0
- package/dist/approvals_purchase/module.js +84 -0
- package/dist/attendance/.kosh/bindings.js +1 -1
- package/dist/attendance/.kosh/schema.d.ts +59 -1
- package/dist/attendance/i18n/bn.d.ts +2 -0
- package/dist/attendance/i18n/bn.js +147 -0
- package/dist/attendance/index.js +3 -1
- package/dist/attendance/module.d.ts +452 -8
- package/dist/automation/engine.js +1 -1
- package/dist/calendar/.kosh/bindings.js +1 -1
- package/dist/calendar/.kosh/schema.d.ts +2 -1
- package/dist/calendar/i18n/bn.d.ts +2 -0
- package/dist/calendar/i18n/bn.js +80 -0
- package/dist/calendar/index.js +77 -0
- package/dist/calendar/module.d.ts +26 -0
- package/dist/calendar/module.js +14 -4
- package/dist/cli/apps.js +25 -5
- package/dist/cli/init.js +14 -4
- package/dist/cli/templates.d.ts +1 -1
- package/dist/cli/templates.js +34 -5
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +2 -1
- package/dist/contacts/i18n/bn.d.ts +2 -0
- package/dist/contacts/i18n/bn.js +67 -0
- package/dist/contacts/index.js +3 -0
- package/dist/contacts/module.d.ts +42 -0
- package/dist/contacts/module.js +6 -1
- package/dist/crm/.kosh/bindings.js +1 -1
- package/dist/crm/.kosh/schema.d.ts +2 -1
- package/dist/crm/i18n/bn.d.ts +2 -0
- package/dist/crm/i18n/bn.js +80 -0
- package/dist/crm/index.js +22 -0
- package/dist/crm/module.d.ts +20 -0
- package/dist/crm/module.js +4 -2
- package/dist/documents/.kosh/bindings.js +1 -1
- package/dist/documents/.kosh/schema.d.ts +2 -1
- package/dist/documents/i18n/bn.d.ts +2 -0
- package/dist/documents/i18n/bn.js +83 -0
- package/dist/documents/index.js +128 -1
- package/dist/documents/module.d.ts +20 -0
- package/dist/documents/module.js +1 -0
- package/dist/event/.kosh/bindings.js +1 -1
- package/dist/event/.kosh/schema.d.ts +2 -1
- package/dist/event/i18n/bn.d.ts +2 -0
- package/dist/event/i18n/bn.js +101 -0
- package/dist/event/index.js +66 -0
- package/dist/event/module.d.ts +20 -0
- package/dist/event/module.js +8 -1
- package/dist/event_account/.kosh/bindings.js +1 -1
- package/dist/event_account/.kosh/schema.d.ts +530 -8
- package/dist/event_account/i18n/bn.d.ts +2 -0
- package/dist/event_account/i18n/bn.js +5 -0
- package/dist/event_account/index.js +2 -0
- package/dist/event_account/module.d.ts +4905 -1431
- package/dist/expense/.kosh/bindings.js +1 -1
- package/dist/expense/.kosh/schema.d.ts +323 -2
- package/dist/expense/i18n/bn.d.ts +2 -0
- package/dist/expense/i18n/bn.js +155 -0
- package/dist/expense/index.js +8 -1
- package/dist/expense/module.d.ts +2715 -694
- package/dist/expense/module.js +3 -1
- package/dist/expense_account/.kosh/bindings.js +1 -1
- package/dist/expense_account/.kosh/schema.d.ts +587 -8
- package/dist/expense_account/i18n/bn.d.ts +2 -0
- package/dist/expense_account/i18n/bn.js +15 -0
- package/dist/expense_account/index.js +2 -0
- package/dist/expense_account/module.d.ts +8094 -2619
- package/dist/helpdesk/.kosh/bindings.js +1 -1
- package/dist/helpdesk/.kosh/schema.d.ts +2 -1
- package/dist/helpdesk/i18n/bn.d.ts +2 -0
- package/dist/helpdesk/i18n/bn.js +127 -0
- package/dist/helpdesk/index.js +2 -0
- package/dist/helpdesk/module.d.ts +20 -0
- package/dist/hr/.kosh/bindings.js +1 -1
- package/dist/hr/.kosh/schema.d.ts +59 -1
- package/dist/hr/demo.js +11 -1
- package/dist/hr/i18n/bn.d.ts +2 -0
- package/dist/hr/i18n/bn.js +126 -0
- package/dist/hr/index.d.ts +1 -1
- package/dist/hr/index.js +158 -12
- package/dist/hr/module.d.ts +932 -59
- package/dist/hr/module.js +114 -17
- package/dist/{mrp → indent}/.kosh/bindings.js +2 -2
- package/dist/indent/.kosh/schema.d.ts +2084 -0
- package/dist/indent/demo.d.ts +7 -0
- package/dist/indent/demo.js +48 -0
- package/dist/indent/i18n/bn.d.ts +2 -0
- package/dist/indent/i18n/bn.js +143 -0
- package/dist/indent/index.d.ts +3 -0
- package/dist/indent/index.js +450 -0
- package/dist/{mrp → indent}/module.d.ts +7164 -3075
- package/dist/indent/module.js +792 -0
- package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/indent_purchase/.kosh/bindings.js +15 -0
- package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
- package/dist/indent_purchase/i18n/bn.d.ts +2 -0
- package/dist/indent_purchase/i18n/bn.js +13 -0
- package/dist/indent_purchase/index.d.ts +3 -0
- package/dist/indent_purchase/index.js +61 -0
- package/dist/indent_purchase/module.d.ts +27950 -0
- package/dist/indent_purchase/module.js +163 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +530 -8
- package/dist/l10n_bd/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd/i18n/bn.js +69 -0
- package/dist/l10n_bd/index.js +2 -0
- package/dist/l10n_bd/module.d.ts +5167 -1693
- package/dist/l10n_bd_payroll/.kosh/bindings.js +1 -1
- package/dist/l10n_bd_payroll/.kosh/schema.d.ts +587 -8
- package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
- package/dist/l10n_bd_payroll/index.js +2 -0
- package/dist/l10n_bd_payroll/module.d.ts +5910 -1548
- package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
- package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
- package/dist/{mrp_account → l10n_bd_pos}/.kosh/schema.d.ts +693 -651
- package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd_pos/i18n/bn.js +32 -0
- package/dist/l10n_bd_pos/index.d.ts +3 -0
- package/dist/l10n_bd_pos/index.js +111 -0
- package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +7402 -7647
- package/dist/l10n_bd_pos/module.js +43 -0
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +530 -8
- package/dist/l10n_in/i18n/bn.d.ts +2 -0
- package/dist/l10n_in/i18n/bn.js +95 -0
- package/dist/l10n_in/index.js +2 -0
- package/dist/l10n_in/module.d.ts +6703 -1652
- package/dist/l10n_in/module.js +25 -5
- package/dist/l10n_in/web/GstSettings.js +2 -2
- package/dist/mail/inbound/handle.js +2 -4
- package/dist/mail/inbound/models.js +5 -3
- package/dist/mail/index.d.ts +12 -1
- package/dist/mail/index.js +139 -2
- package/dist/mail/send.d.ts +56 -0
- package/dist/mail/send.js +394 -0
- package/dist/mail/web/SendButton.d.ts +9 -0
- package/dist/mail/web/SendButton.js +71 -0
- package/dist/mail/web/SendSelected.d.ts +8 -0
- package/dist/mail/web/SendSelected.js +33 -0
- package/dist/mail/web/index.d.ts +2 -0
- package/dist/mail/web/index.js +6 -0
- package/dist/mail/web/messages.js +36 -0
- package/dist/maintenance/.kosh/bindings.js +1 -1
- package/dist/maintenance/.kosh/schema.d.ts +2 -1
- package/dist/maintenance/i18n/bn.d.ts +2 -0
- package/dist/maintenance/i18n/bn.js +132 -0
- package/dist/maintenance/index.js +85 -0
- package/dist/maintenance/module.d.ts +25 -0
- package/dist/maintenance/module.js +27 -9
- package/dist/maintenance_stock/.kosh/bindings.js +1 -1
- package/dist/maintenance_stock/.kosh/schema.d.ts +298 -2
- package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
- package/dist/maintenance_stock/i18n/bn.js +21 -0
- package/dist/maintenance_stock/index.js +2 -0
- package/dist/maintenance_stock/module.d.ts +5302 -1256
- package/dist/maintenance_stock/module.js +1 -0
- package/dist/modules-sdk/apps.d.ts +10 -0
- package/dist/modules-sdk/apps.js +32 -0
- package/dist/modules-sdk/index.d.ts +1 -1
- package/dist/modules-sdk/manifest.d.ts +68 -2
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +530 -8
- package/dist/payment/i18n/bn.d.ts +2 -0
- package/dist/payment/i18n/bn.js +59 -0
- package/dist/payment/index.js +85 -0
- package/dist/payment/module.d.ts +5134 -1660
- package/dist/payment/module.js +17 -3
- package/dist/payment/settle.js +1 -0
- package/dist/payroll/.kosh/bindings.js +1 -1
- package/dist/payroll/.kosh/schema.d.ts +59 -1
- package/dist/payroll/i18n/bn.d.ts +2 -0
- package/dist/payroll/i18n/bn.js +206 -0
- package/dist/payroll/index.js +2 -0
- package/dist/payroll/module.d.ts +936 -48
- package/dist/payroll_account/.kosh/bindings.js +1 -1
- package/dist/payroll_account/.kosh/schema.d.ts +587 -8
- package/dist/payroll_account/i18n/bn.d.ts +2 -0
- package/dist/payroll_account/i18n/bn.js +10 -0
- package/dist/payroll_account/index.js +2 -0
- package/dist/payroll_account/module.d.ts +7534 -3192
- package/dist/permissions/approvals.d.ts +97 -4
- package/dist/permissions/approvals.js +780 -31
- package/dist/permissions/index.d.ts +1 -1
- package/dist/permissions/index.js +2 -2
- package/dist/permissions/models.js +177 -5
- package/dist/permissions/routes.d.ts +3 -0
- package/dist/permissions/routes.js +36 -2
- package/dist/permissions/web/ApprovalPanel.js +43 -5
- package/dist/permissions/web/messages.js +52 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +2 -1
- package/dist/portal/documents.d.ts +3 -0
- package/dist/portal/documents.js +21 -1
- package/dist/portal/i18n/bn.d.ts +2 -0
- package/dist/portal/i18n/bn.js +33 -0
- package/dist/portal/index.js +2 -0
- package/dist/portal/module.d.ts +20 -0
- package/dist/portal/routes-documents.js +76 -0
- package/dist/pos/.kosh/bindings.js +1 -1
- package/dist/pos/.kosh/schema.d.ts +531 -8
- package/dist/pos/i18n/bn.d.ts +2 -0
- package/dist/pos/i18n/bn.js +133 -0
- package/dist/pos/index.js +83 -1
- package/dist/pos/module.d.ts +6888 -1777
- package/dist/pos/module.js +49 -5
- package/dist/pos/routes.js +80 -7
- package/dist/pos/web/Register.js +2 -5
- package/dist/pos_stock/.kosh/bindings.js +1 -1
- package/dist/pos_stock/.kosh/schema.d.ts +626 -9
- package/dist/pos_stock/i18n/bn.d.ts +2 -0
- package/dist/pos_stock/i18n/bn.js +6 -0
- package/dist/pos_stock/index.js +2 -0
- package/dist/pos_stock/module.d.ts +10798 -3276
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +202 -1
- package/dist/product/i18n/bn.d.ts +2 -0
- package/dist/product/i18n/bn.js +175 -0
- package/dist/product/index.d.ts +1 -0
- package/dist/product/index.js +288 -1
- package/dist/product/module.d.ts +1725 -0
- package/dist/product/module.js +66 -6
- package/dist/product/pricelist.d.ts +575 -0
- package/dist/product/pricelist.js +257 -0
- package/dist/product/variants.d.ts +908 -0
- package/dist/product/variants.js +251 -0
- package/dist/production/.kosh/bindings.d.ts +22 -0
- package/dist/production/.kosh/bindings.js +15 -0
- package/dist/production/.kosh/schema.d.ts +2345 -0
- package/dist/{mrp → production}/demo.d.ts +1 -1
- package/dist/{mrp → production}/demo.js +5 -5
- package/dist/production/depth.d.ts +790 -0
- package/dist/production/depth.js +262 -0
- package/dist/production/i18n/bn.d.ts +2 -0
- package/dist/production/i18n/bn.js +350 -0
- package/dist/production/index.d.ts +6 -0
- package/dist/production/index.js +1256 -0
- package/dist/production/module.d.ts +17327 -0
- package/dist/production/module.js +1333 -0
- package/dist/production/plan.d.ts +921 -0
- package/dist/production/plan.js +511 -0
- package/dist/production/schedule.d.ts +656 -0
- package/dist/production/schedule.js +309 -0
- package/dist/production_account/.kosh/bindings.d.ts +22 -0
- package/dist/production_account/.kosh/bindings.js +15 -0
- package/dist/production_account/.kosh/schema.d.ts +3496 -0
- package/dist/production_account/i18n/bn.d.ts +2 -0
- package/dist/production_account/i18n/bn.js +93 -0
- package/dist/production_account/index.d.ts +4 -0
- package/dist/production_account/index.js +246 -0
- package/dist/production_account/module.d.ts +1192 -0
- package/dist/{mrp_account → production_account}/module.js +72 -18
- package/dist/production_account/overhead.d.ts +1195 -0
- package/dist/production_account/overhead.js +554 -0
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +65 -2
- package/dist/project/i18n/bn.d.ts +2 -0
- package/dist/project/i18n/bn.js +383 -0
- package/dist/project/index.js +123 -0
- package/dist/project/module.d.ts +20 -0
- package/dist/project/module.js +73 -14
- package/dist/project_account/.kosh/bindings.js +1 -1
- package/dist/project_account/.kosh/schema.d.ts +530 -8
- package/dist/project_account/i18n/bn.d.ts +2 -0
- package/dist/project_account/i18n/bn.js +6 -0
- package/dist/project_account/index.js +2 -0
- package/dist/project_account/module.d.ts +4926 -1452
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +65 -2
- package/dist/project_portal/i18n/bn.d.ts +2 -0
- package/dist/project_portal/i18n/bn.js +6 -0
- package/dist/project_portal/index.js +2 -0
- package/dist/project_portal/module.d.ts +40 -0
- package/dist/project_purchase/.kosh/bindings.js +1 -1
- package/dist/project_purchase/.kosh/schema.d.ts +1126 -53
- package/dist/project_purchase/i18n/bn.d.ts +2 -0
- package/dist/project_purchase/i18n/bn.js +4 -0
- package/dist/project_purchase/index.js +2 -0
- package/dist/project_purchase/module.d.ts +17912 -4446
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +813 -3
- package/dist/purchase/comparison.d.ts +993 -0
- package/dist/purchase/comparison.js +415 -0
- package/dist/purchase/extras.d.ts +1509 -0
- package/dist/purchase/extras.js +445 -0
- package/dist/purchase/i18n/bn.d.ts +2 -0
- package/dist/purchase/i18n/bn.js +413 -0
- package/dist/purchase/index.d.ts +5 -0
- package/dist/purchase/index.js +1280 -4
- package/dist/purchase/module.d.ts +7139 -398
- package/dist/purchase/module.js +295 -11
- package/dist/purchase/request.d.ts +696 -0
- package/dist/purchase/request.js +446 -0
- package/dist/purchase/tender.d.ts +1208 -0
- package/dist/purchase/tender.js +507 -0
- package/dist/purchase/vendorprice.d.ts +340 -0
- package/dist/purchase/vendorprice.js +153 -0
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +1130 -57
- package/dist/purchase_account/i18n/bn.d.ts +2 -0
- package/dist/purchase_account/i18n/bn.js +22 -0
- package/dist/purchase_account/index.js +19 -0
- package/dist/purchase_account/module.d.ts +12276 -2247
- package/dist/purchase_account/module.js +241 -9
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +813 -3
- package/dist/purchase_portal/i18n/bn.d.ts +2 -0
- package/dist/purchase_portal/i18n/bn.js +5 -0
- package/dist/purchase_portal/index.js +2 -0
- package/dist/purchase_portal/module.d.ts +6849 -353
- package/dist/purchase_stock/.kosh/bindings.js +1 -1
- package/dist/purchase_stock/.kosh/schema.d.ts +910 -4
- package/dist/purchase_stock/i18n/bn.d.ts +2 -0
- package/dist/purchase_stock/i18n/bn.js +19 -0
- package/dist/purchase_stock/index.d.ts +1 -1
- package/dist/purchase_stock/index.js +29 -0
- package/dist/purchase_stock/module.d.ts +12410 -1864
- package/dist/purchase_stock/module.js +81 -9
- package/dist/purchase_stock/scorecard.d.ts +22 -0
- package/dist/purchase_stock/scorecard.js +77 -0
- package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
- package/dist/purchase_stock/web/Scorecard.js +22 -0
- package/dist/purchase_stock/web/index.d.ts +11 -0
- package/dist/purchase_stock/web/index.js +16 -0
- package/dist/purchase_stock/web/messages.d.ts +2 -0
- package/dist/purchase_stock/web/messages.js +27 -0
- package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
- package/dist/purchase_stock_account/.kosh/schema.d.ts +1286 -58
- package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
- package/dist/purchase_stock_account/i18n/bn.js +8 -0
- package/dist/purchase_stock_account/index.js +18 -0
- package/dist/purchase_stock_account/module.d.ts +7 -37995
- package/dist/purchase_stock_account/module.js +24 -3
- package/dist/recruitment/.kosh/bindings.js +1 -1
- package/dist/recruitment/.kosh/schema.d.ts +59 -1
- package/dist/recruitment/i18n/bn.d.ts +2 -0
- package/dist/recruitment/i18n/bn.js +93 -0
- package/dist/recruitment/index.js +64 -0
- package/dist/recruitment/module.d.ts +458 -8
- package/dist/recruitment/module.js +11 -3
- package/dist/reporting/documents.d.ts +5 -0
- package/dist/reporting/documents.js +11 -1
- package/dist/reporting/index.d.ts +1 -1
- package/dist/reporting/index.js +1 -1
- package/dist/reporting/web/CalendarView.d.ts +18 -5
- package/dist/reporting/web/CalendarView.js +163 -29
- package/dist/reporting/web/messages.js +18 -0
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +642 -16
- package/dist/sale_account/i18n/bn.d.ts +2 -0
- package/dist/sale_account/i18n/bn.js +48 -0
- package/dist/sale_account/index.d.ts +1 -1
- package/dist/sale_account/index.js +102 -4
- package/dist/sale_account/module.d.ts +8254 -2212
- package/dist/sale_account/module.js +535 -46
- package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
- package/dist/sale_crm/.kosh/bindings.js +15 -0
- package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +389 -567
- package/dist/sale_crm/i18n/bn.d.ts +2 -0
- package/dist/sale_crm/i18n/bn.js +9 -0
- package/dist/sale_crm/index.d.ts +7 -0
- package/dist/sale_crm/index.js +104 -0
- package/dist/sale_crm/module.d.ts +5609 -0
- package/dist/sale_crm/module.js +73 -0
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +291 -4
- package/dist/sale_portal/i18n/bn.d.ts +2 -0
- package/dist/sale_portal/i18n/bn.js +7 -0
- package/dist/sale_portal/index.js +10 -0
- package/dist/sale_portal/module.d.ts +2564 -294
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +354 -5
- package/dist/sale_project/i18n/bn.d.ts +2 -0
- package/dist/sale_project/i18n/bn.js +12 -0
- package/dist/sale_project/index.js +2 -0
- package/dist/sale_project/module.d.ts +6249 -2402
- package/dist/sale_stock/.kosh/bindings.js +1 -1
- package/dist/sale_stock/.kosh/schema.d.ts +387 -5
- package/dist/sale_stock/i18n/bn.d.ts +2 -0
- package/dist/sale_stock/i18n/bn.js +15 -0
- package/dist/sale_stock/index.js +2 -0
- package/dist/sale_stock/module.d.ts +8057 -1759
- package/dist/sale_stock/module.js +20 -3
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +291 -4
- package/dist/sales/i18n/bn.d.ts +2 -0
- package/dist/sales/i18n/bn.js +128 -0
- package/dist/sales/index.js +120 -5
- package/dist/sales/module.d.ts +3567 -633
- package/dist/sales/module.js +306 -11
- package/dist/server/api/duplicate.d.ts +14 -0
- package/dist/server/api/duplicate.js +75 -0
- package/dist/server/api/explain.d.ts +70 -0
- package/dist/server/api/explain.js +111 -0
- package/dist/server/api/metadata.d.ts +2 -0
- package/dist/server/api/metadata.js +9 -0
- package/dist/server/api/openapi.js +15 -0
- package/dist/server/api/rest.d.ts +1 -0
- package/dist/server/api/rest.js +76 -12
- package/dist/server/api/views.js +1 -1
- package/dist/server/apps.d.ts +16 -1
- package/dist/server/apps.js +164 -2
- package/dist/server/auth/base.js +2 -0
- package/dist/server/auth/service.d.ts +8 -0
- package/dist/server/auth/service.js +19 -0
- package/dist/server/events.d.ts +13 -0
- package/dist/server/events.js +22 -0
- package/dist/server/i18n.d.ts +27 -0
- package/dist/server/i18n.js +143 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/server.js +6 -0
- package/dist/settings/company.d.ts +3 -1
- package/dist/settings/company.js +26 -5
- package/dist/settings/routes.d.ts +10 -0
- package/dist/settings/routes.js +19 -3
- package/dist/settings/web/AppsPage.d.ts +3 -2
- package/dist/settings/web/AppsPage.js +26 -8
- package/dist/settings/web/CompaniesPage.js +91 -6
- package/dist/settings/web/messages.js +64 -0
- package/dist/sign/.kosh/bindings.js +1 -1
- package/dist/sign/.kosh/schema.d.ts +2 -1
- package/dist/sign/i18n/bn.d.ts +2 -0
- package/dist/sign/i18n/bn.js +97 -0
- package/dist/sign/index.d.ts +15 -0
- package/dist/sign/index.js +129 -1
- package/dist/sign/module.d.ts +40 -0
- package/dist/sign/module.js +11 -2
- package/dist/stock/.kosh/bindings.js +1 -1
- package/dist/stock/.kosh/schema.d.ts +298 -2
- package/dist/stock/i18n/bn.d.ts +2 -0
- package/dist/stock/i18n/bn.js +311 -0
- package/dist/stock/index.d.ts +3 -1
- package/dist/stock/index.js +442 -3
- package/dist/stock/ledger.d.ts +78 -0
- package/dist/stock/ledger.js +582 -0
- package/dist/stock/module.d.ts +5280 -2044
- package/dist/stock/module.js +222 -23
- package/dist/stock/replenish.js +16 -1
- package/dist/stock/returns.d.ts +157 -0
- package/dist/stock/returns.js +163 -0
- package/dist/stock/web/Ledger.d.ts +9 -0
- package/dist/stock/web/Ledger.js +108 -0
- package/dist/stock/web/Operations.d.ts +8 -0
- package/dist/stock/web/Operations.js +33 -0
- package/dist/stock/web/ReturnButton.d.ts +7 -0
- package/dist/stock/web/ReturnButton.js +62 -0
- package/dist/stock/web/index.d.ts +3 -0
- package/dist/stock/web/index.js +9 -0
- package/dist/stock/web/messages.js +154 -0
- package/dist/stock_account/.kosh/bindings.js +1 -1
- package/dist/stock_account/.kosh/schema.d.ts +682 -9
- package/dist/stock_account/i18n/bn.d.ts +2 -0
- package/dist/stock_account/i18n/bn.js +73 -0
- package/dist/stock_account/index.d.ts +1 -0
- package/dist/stock_account/index.js +131 -3
- package/dist/stock_account/landed.d.ts +429 -0
- package/dist/stock_account/landed.js +335 -0
- package/dist/stock_account/module.d.ts +11247 -3363
- package/dist/stock_account/module.js +135 -6
- package/dist/stock_account/web/LandedPreview.d.ts +7 -0
- package/dist/stock_account/web/LandedPreview.js +23 -0
- package/dist/stock_account/web/index.d.ts +11 -0
- package/dist/stock_account/web/index.js +16 -0
- package/dist/stock_account/web/messages.d.ts +2 -0
- package/dist/stock_account/web/messages.js +27 -0
- package/dist/todo/i18n/bn.d.ts +2 -0
- package/dist/todo/i18n/bn.js +66 -0
- package/dist/todo/index.js +59 -0
- package/dist/todo/module.d.ts +5 -0
- package/dist/todo/module.js +5 -3
- package/dist/trade_finance/.kosh/bindings.js +1 -1
- package/dist/trade_finance/.kosh/schema.d.ts +2 -1
- package/dist/trade_finance/i18n/bn.d.ts +2 -0
- package/dist/trade_finance/i18n/bn.js +162 -0
- package/dist/trade_finance/index.js +93 -0
- package/dist/trade_finance/module.d.ts +26 -0
- package/dist/trade_finance/module.js +27 -8
- package/dist/trade_finance_account/.kosh/bindings.js +1 -1
- package/dist/trade_finance_account/.kosh/schema.d.ts +530 -8
- package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_account/i18n/bn.js +27 -0
- package/dist/trade_finance_account/index.js +2 -0
- package/dist/trade_finance_account/module.d.ts +4906 -1432
- package/dist/trade_finance_account/module.js +1 -0
- package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
- package/dist/trade_finance_purchase/.kosh/schema.d.ts +813 -3
- package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_purchase/i18n/bn.js +6 -0
- package/dist/trade_finance_purchase/index.js +2 -0
- package/dist/trade_finance_purchase/module.d.ts +6909 -413
- package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
- package/dist/trade_finance_sale/.kosh/schema.d.ts +291 -4
- package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_sale/i18n/bn.js +6 -0
- package/dist/trade_finance_sale/index.js +2 -0
- package/dist/trade_finance_sale/module.d.ts +2601 -331
- package/dist/ui/api.d.ts +2 -0
- package/dist/ui/app.d.ts +9 -0
- package/dist/ui/app.js +24 -4
- package/dist/ui/components/AppIcon.js +2 -2
- package/dist/ui/components/Explain.d.ts +69 -0
- package/dist/ui/components/Explain.js +62 -0
- package/dist/ui/context.d.ts +8 -1
- package/dist/ui/context.js +34 -1
- package/dist/ui/i18n/messages.d.ts +36 -0
- package/dist/ui/i18n/messages.js +72 -0
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/registry.d.ts +14 -0
- package/dist/ui/registry.js +10 -0
- package/dist/ui/views/FormView.d.ts +6 -0
- package/dist/ui/views/FormView.js +47 -10
- package/dist/ui/views/ListView.d.ts +8 -0
- package/dist/ui/views/ListView.js +10 -3
- package/dist/ui/views/StatsRow.js +2 -1
- package/dist/views/extend.js +12 -0
- package/dist/views/types.d.ts +13 -2
- package/dist/views/validate.js +8 -1
- package/dist/website/.kosh/bindings.js +1 -1
- package/dist/website/.kosh/schema.d.ts +2 -1
- package/dist/website/i18n/bn.d.ts +2 -0
- package/dist/website/i18n/bn.js +113 -0
- package/dist/website/index.js +36 -0
- package/dist/website/module.d.ts +20 -0
- package/dist/website/module.js +29 -5
- package/dist/website_crm/.kosh/bindings.js +1 -1
- package/dist/website_crm/.kosh/schema.d.ts +2 -1
- package/dist/website_crm/i18n/bn.d.ts +2 -0
- package/dist/website_crm/i18n/bn.js +5 -0
- package/dist/website_crm/index.js +2 -0
- package/dist/website_crm/module.d.ts +40 -0
- package/dist/website_sale/.kosh/bindings.js +1 -1
- package/dist/website_sale/.kosh/schema.d.ts +642 -17
- package/dist/website_sale/i18n/bn.d.ts +2 -0
- package/dist/website_sale/i18n/bn.js +132 -0
- package/dist/website_sale/index.js +83 -1
- package/dist/website_sale/module.d.ts +18705 -5550
- package/dist/website_sale/module.js +32 -10
- package/dist/website_sale/shop.js +22 -9
- package/dist/website_sale_stock/.kosh/bindings.js +1 -1
- package/dist/website_sale_stock/.kosh/schema.d.ts +737 -18
- package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
- package/dist/website_sale_stock/i18n/bn.js +4 -0
- package/dist/website_sale_stock/index.js +2 -0
- package/dist/website_sale_stock/module.d.ts +10 -24997
- package/dist/website_sale_stock/module.js +7 -3
- package/package.json +36 -8
- package/dist/mrp/index.d.ts +0 -3
- package/dist/mrp/index.js +0 -393
- package/dist/mrp/module.js +0 -757
- package/dist/mrp_account/index.d.ts +0 -3
- package/dist/mrp_account/index.js +0 -22
- /package/dist/{mrp → approvals_purchase}/.kosh/bindings.d.ts +0 -0
- /package/dist/{mrp_account → indent}/.kosh/bindings.d.ts +0 -0
|
@@ -594,6 +594,10 @@ export class AuthService {
|
|
|
594
594
|
twoFactorEnabled,
|
|
595
595
|
administrator,
|
|
596
596
|
administratorNeedsSecondFactor: administrator && !(session.secondFactor && twoFactorEnabled),
|
|
597
|
+
developer: administrator ||
|
|
598
|
+
(await model(env, 'auth.user_group').search({
|
|
599
|
+
where: { user: session.user, group: 'base.developer' },
|
|
600
|
+
})).length > 0,
|
|
597
601
|
twoFactorSetupRequired: !twoFactorEnabled && (await this.policy()).twoFactor === 'everyone',
|
|
598
602
|
};
|
|
599
603
|
});
|
|
@@ -702,6 +706,21 @@ export class AuthService {
|
|
|
702
706
|
});
|
|
703
707
|
}
|
|
704
708
|
/** Turns 2FA off (password and a current code required). */
|
|
709
|
+
/**
|
|
710
|
+
* A step-up check (RFC 0008 §5.4): the user's current authenticator code, asked again for a dangerous action
|
|
711
|
+
* (removing an app with its data). Recovery codes do not count. @throws {HttpProblem} 409 when two-factor is off,
|
|
712
|
+
* 422 when the code does not match
|
|
713
|
+
*/
|
|
714
|
+
async confirmSecondFactor(user, code) {
|
|
715
|
+
await this.#system('2fa step-up', async (env) => {
|
|
716
|
+
const credentials = await model(env, 'auth.credential').search({ where: { user } });
|
|
717
|
+
const [row] = await fetch(credentials, ['totpSecret', 'totpEnabled']);
|
|
718
|
+
if (row?.['totpEnabled'] !== true || typeof row['totpSecret'] !== 'string')
|
|
719
|
+
throw new HttpProblem(409, 'two-factor-off', 'Two-factor authentication is off', 'This needs a code from your authenticator app.', 'Turn on two-factor sign-in in Settings › Your profile first.');
|
|
720
|
+
if (!verifyTotp(row['totpSecret'], code.trim()))
|
|
721
|
+
throw new HttpProblem(422, 'invalid-code', 'Invalid code', 'The code does not match.', 'Use the current code of the authenticator app.');
|
|
722
|
+
});
|
|
723
|
+
}
|
|
705
724
|
async disableTwoFactor(session, password, code) {
|
|
706
725
|
if ((await this.policy()).twoFactor === 'everyone')
|
|
707
726
|
throw new HttpProblem(409, 'two-factor-required', 'Two-factor sign-in is required', 'This installation requires two-factor sign-in of everyone: it cannot be turned off.');
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named events of state transitions (RFC 0023 E1, RFC 0006): `emitting(topic, transition)` returns the transition
|
|
3
|
+
* with an `after` hook that emits `topic` with `{ id }` for each record, once its own `after` ran — in the same
|
|
4
|
+
* transaction, through the outbox, so notifications, automations and webhooks take it by name. The module declares
|
|
5
|
+
* the topic in its manifest's `events`.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* transitions: {
|
|
9
|
+
* validate: emitting('stock.picking.done', { from: ['assigned'], to: 'done', after: … }),
|
|
10
|
+
* }
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function emitting<const T extends object>(topic: string, transition: T): T;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named events of state transitions (RFC 0023 E1, RFC 0006): `emitting(topic, transition)` returns the transition
|
|
3
|
+
* with an `after` hook that emits `topic` with `{ id }` for each record, once its own `after` ran — in the same
|
|
4
|
+
* transaction, through the outbox, so notifications, automations and webhooks take it by name. The module declares
|
|
5
|
+
* the topic in its manifest's `events`.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* transitions: {
|
|
9
|
+
* validate: emitting('stock.picking.done', { from: ['assigned'], to: 'done', after: … }),
|
|
10
|
+
* }
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function emitting(topic, transition) {
|
|
14
|
+
const own = transition.after;
|
|
15
|
+
const after = async (records) => {
|
|
16
|
+
await own?.(records);
|
|
17
|
+
const { env, ids } = records;
|
|
18
|
+
for (const id of ids)
|
|
19
|
+
await env.emit(topic, { id });
|
|
20
|
+
};
|
|
21
|
+
return { ...transition, after };
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translated metadata (RFC 0023 §3.1): modules ship dictionaries keyed by the English text (`i18n: { bn: () =>
|
|
3
|
+
* import('./i18n/bn.js') }`, each `export const bn = { 'Customer': 'গ্রাহক', … }`). The server merges every installed
|
|
4
|
+
* module's dictionaries at start and translates what it serves to the request's language (`Accept-Language`): the
|
|
5
|
+
* labels, help, descriptions, titles and options of views, menus, actions, apps, model metadata, searches, overviews
|
|
6
|
+
* and settings, and the message of a problem. English stays the key, so code never changes; a string without a
|
|
7
|
+
* translation is served in English.
|
|
8
|
+
*/
|
|
9
|
+
import type { FastifyInstance } from 'fastify';
|
|
10
|
+
/** language → English text → translation. */
|
|
11
|
+
export type Dictionaries = ReadonlyMap<string, ReadonlyMap<string, string>>;
|
|
12
|
+
/** Merges the modules' dictionaries (`i18n` loaders) per language; a module's own entries never lose to an empty one. */
|
|
13
|
+
export declare function loadDictionaries(modules: readonly {
|
|
14
|
+
readonly i18n?: Readonly<Record<string, () => Promise<unknown>>>;
|
|
15
|
+
}[]): Promise<Dictionaries>;
|
|
16
|
+
/** The dictionary of a Shutro language code (`bn_BD`, then `bn`), or none for English. */
|
|
17
|
+
export declare function dictionaryFor(dictionaries: Dictionaries, lang: string | null): ReadonlyMap<string, string> | null;
|
|
18
|
+
/**
|
|
19
|
+
* A copy of `value` with the people-facing strings translated (and `[value, label]` options' labels). A field's own
|
|
20
|
+
* label may have a context key, `<model>.<field>` (`res.partner.state` → রাজ্য where "State" is a region), looked up
|
|
21
|
+
* before the English text: in a served view's `fields` (model → field → description) and a model's metadata.
|
|
22
|
+
*/
|
|
23
|
+
export declare function translateValue(value: unknown, dict: ReadonlyMap<string, string>, key?: string, field?: string): unknown;
|
|
24
|
+
/** A problem's detail with the known messages in it translated (`project.project: A project …`). */
|
|
25
|
+
export declare function translateDetail(detail: string, dict: ReadonlyMap<string, string>): string;
|
|
26
|
+
/** Translates metadata responses and problems to the request's language. */
|
|
27
|
+
export declare function registerTranslation(app: FastifyInstance, dictionaries: Dictionaries): void;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/** The keys whose string values people read (as `pnpm i18n:extract` collects them). */
|
|
2
|
+
const TEXT_KEYS = new Set([
|
|
3
|
+
'label',
|
|
4
|
+
'description',
|
|
5
|
+
'help',
|
|
6
|
+
'title',
|
|
7
|
+
'summary',
|
|
8
|
+
'confirm',
|
|
9
|
+
'message',
|
|
10
|
+
'placeholder',
|
|
11
|
+
'category',
|
|
12
|
+
'text',
|
|
13
|
+
'header',
|
|
14
|
+
'footer',
|
|
15
|
+
'successMessage',
|
|
16
|
+
'name',
|
|
17
|
+
]);
|
|
18
|
+
/** Merges the modules' dictionaries (`i18n` loaders) per language; a module's own entries never lose to an empty one. */
|
|
19
|
+
export async function loadDictionaries(modules) {
|
|
20
|
+
const out = new Map();
|
|
21
|
+
for (const m of modules)
|
|
22
|
+
for (const [lang, load] of Object.entries(m.i18n ?? {})) {
|
|
23
|
+
const loaded = (await load());
|
|
24
|
+
const dict = (loaded?.[lang] ?? loaded?.['default'] ?? loaded);
|
|
25
|
+
const target = out.get(lang) ?? new Map();
|
|
26
|
+
for (const [source, text] of Object.entries(dict ?? {}))
|
|
27
|
+
if (typeof text === 'string' && text !== '' && !target.has(source))
|
|
28
|
+
target.set(source, text);
|
|
29
|
+
out.set(lang, target);
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
/** The dictionary of a Shutro language code (`bn_BD`, then `bn`), or none for English. */
|
|
34
|
+
export function dictionaryFor(dictionaries, lang) {
|
|
35
|
+
if (lang === null || lang === '' || lang.startsWith('en'))
|
|
36
|
+
return null;
|
|
37
|
+
return dictionaries.get(lang) ?? dictionaries.get(lang.split(/[_-]/)[0] ?? '') ?? null;
|
|
38
|
+
}
|
|
39
|
+
/** A model name (`sale.order`): what keys a served view's `fields` map by. */
|
|
40
|
+
const MODEL = /^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$/;
|
|
41
|
+
/**
|
|
42
|
+
* A copy of `value` with the people-facing strings translated (and `[value, label]` options' labels). A field's own
|
|
43
|
+
* label may have a context key, `<model>.<field>` (`res.partner.state` → রাজ্য where "State" is a region), looked up
|
|
44
|
+
* before the English text: in a served view's `fields` (model → field → description) and a model's metadata.
|
|
45
|
+
*/
|
|
46
|
+
export function translateValue(value, dict, key, field) {
|
|
47
|
+
if (typeof value === 'string') {
|
|
48
|
+
if (key === undefined || !TEXT_KEYS.has(key))
|
|
49
|
+
return value;
|
|
50
|
+
return ((key === 'label' && field !== undefined ? dict.get(field) : undefined) ??
|
|
51
|
+
dict.get(value) ??
|
|
52
|
+
value);
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(value)) {
|
|
55
|
+
// A selection's options: [value, label] pairs.
|
|
56
|
+
if (key === 'options' &&
|
|
57
|
+
value.every((o) => Array.isArray(o) && o.length === 2 && typeof o[1] === 'string'))
|
|
58
|
+
return value.map((o) => [o[0], dict.get(o[1]) ?? o[1]]);
|
|
59
|
+
return value.map((v) => translateValue(v, dict, key === 'options' ? undefined : key));
|
|
60
|
+
}
|
|
61
|
+
if (value !== null && typeof value === 'object') {
|
|
62
|
+
if (value instanceof Date)
|
|
63
|
+
return value;
|
|
64
|
+
const o = value;
|
|
65
|
+
const out = {};
|
|
66
|
+
// A model's metadata: `{ name: 'res.partner', fields: [{ key, label, … }] }`.
|
|
67
|
+
const model = typeof o['name'] === 'string' && MODEL.test(o['name']) ? o['name'] : null;
|
|
68
|
+
for (const [k, v] of Object.entries(o)) {
|
|
69
|
+
if (k === 'fields' && v !== null && typeof v === 'object' && !Array.isArray(v)) {
|
|
70
|
+
// A served view's fields: model → field → description.
|
|
71
|
+
const byModel = {};
|
|
72
|
+
for (const [m, fields] of Object.entries(v)) {
|
|
73
|
+
if (!MODEL.test(m) || fields === null || typeof fields !== 'object') {
|
|
74
|
+
byModel[m] = translateValue(fields, dict, m);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const translated = {};
|
|
78
|
+
for (const [f, d] of Object.entries(fields))
|
|
79
|
+
translated[f] = translateValue(d, dict, f, `${m}.${f}`);
|
|
80
|
+
byModel[m] = translated;
|
|
81
|
+
}
|
|
82
|
+
out[k] = byModel;
|
|
83
|
+
}
|
|
84
|
+
else if (k === 'fields' && Array.isArray(v) && model !== null)
|
|
85
|
+
out[k] = v.map((d) => d !== null &&
|
|
86
|
+
typeof d === 'object' &&
|
|
87
|
+
typeof d['key'] === 'string'
|
|
88
|
+
? translateValue(d, dict, undefined, `${model}.${String(d['key'])}`)
|
|
89
|
+
: translateValue(d, dict, k));
|
|
90
|
+
else
|
|
91
|
+
out[k] = translateValue(v, dict, k, k === 'label' ? field : undefined);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
/** A problem's detail with the known messages in it translated (`project.project: A project …`). */
|
|
98
|
+
export function translateDetail(detail, dict) {
|
|
99
|
+
let out = detail;
|
|
100
|
+
for (const [source, text] of dict)
|
|
101
|
+
if (source.length >= 12 && out.includes(source))
|
|
102
|
+
out = out.split(source).join(text);
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/** The routes that serve metadata, translated as a whole. */
|
|
106
|
+
const METADATA = [
|
|
107
|
+
'/api/v1/apps',
|
|
108
|
+
'/api/v1/menus',
|
|
109
|
+
'/api/v1/actions/',
|
|
110
|
+
'/api/v1/views',
|
|
111
|
+
'/api/v1/search/',
|
|
112
|
+
'/api/v1/meta/',
|
|
113
|
+
'/api/v1/reports/overview',
|
|
114
|
+
'/api/v1/settings/',
|
|
115
|
+
'/api/v1/models/', // only `/next` (transitions and their messages), below
|
|
116
|
+
];
|
|
117
|
+
/** `bn-BD,bn;q=0.9` → `bn_BD`. */
|
|
118
|
+
function languageOf(request) {
|
|
119
|
+
const header = request.headers['accept-language'];
|
|
120
|
+
const first = (Array.isArray(header) ? header[0] : header)?.split(',')[0]?.split(';')[0]?.trim();
|
|
121
|
+
return first === undefined || first === '' ? null : first.replace('-', '_');
|
|
122
|
+
}
|
|
123
|
+
/** Translates metadata responses and problems to the request's language. */
|
|
124
|
+
export function registerTranslation(app, dictionaries) {
|
|
125
|
+
if (dictionaries.size === 0)
|
|
126
|
+
return;
|
|
127
|
+
app.addHook('preSerialization', async (request, reply, payload) => {
|
|
128
|
+
const dict = dictionaryFor(dictionaries, languageOf(request));
|
|
129
|
+
if (dict === null || payload === null || typeof payload !== 'object')
|
|
130
|
+
return payload;
|
|
131
|
+
const url = request.url.split('?')[0] ?? '';
|
|
132
|
+
if (reply.statusCode >= 400) {
|
|
133
|
+
const p = payload;
|
|
134
|
+
return typeof p['detail'] === 'string'
|
|
135
|
+
? { ...p, detail: translateDetail(p['detail'], dict) }
|
|
136
|
+
: payload;
|
|
137
|
+
}
|
|
138
|
+
const metadata = request.method === 'GET' &&
|
|
139
|
+
METADATA.some((prefix) => url.startsWith(prefix)) &&
|
|
140
|
+
(!url.startsWith('/api/v1/models/') || url.endsWith('/next'));
|
|
141
|
+
return metadata ? translateValue(payload, dict) : payload;
|
|
142
|
+
});
|
|
143
|
+
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -23,7 +23,9 @@ export { type AuthOptions, AuthService, cookieOf, SESSION_COOKIE, type SecurityP
|
|
|
23
23
|
export { DEMO_PASSWORD, type DemoResult, installDemo } from './demo.js';
|
|
24
24
|
export { applyEnvironmentNames } from './env-names.js';
|
|
25
25
|
export { HttpProblem, type Problem, problemOf, ServerConfigError } from './errors.js';
|
|
26
|
+
export { emitting } from './events.js';
|
|
26
27
|
export { type AppHost, type AppHostOptions, createAppHost, startAppHost } from './host.js';
|
|
28
|
+
export { type Dictionaries, dictionaryFor, loadDictionaries, translateDetail, translateValue, } from './i18n.js';
|
|
27
29
|
export { type Authenticator, denyAll, isSuperuser, languageOf, type RequestIdentity, type RequestRunOptions, runOptionsOf, } from './identity.js';
|
|
28
30
|
export { imageVersions, registerImageRoutes } from './images.js';
|
|
29
31
|
export { migrate, orm, pg } from './orm.js';
|
package/dist/server/index.js
CHANGED
|
@@ -23,7 +23,9 @@ export { AuthService, cookieOf, SESSION_COOKIE, timeOf, } from './auth/service.j
|
|
|
23
23
|
export { DEMO_PASSWORD, installDemo } from './demo.js';
|
|
24
24
|
export { applyEnvironmentNames } from './env-names.js';
|
|
25
25
|
export { HttpProblem, problemOf, ServerConfigError } from './errors.js';
|
|
26
|
+
export { emitting } from './events.js';
|
|
26
27
|
export { createAppHost, startAppHost } from './host.js';
|
|
28
|
+
export { dictionaryFor, loadDictionaries, translateDetail, translateValue, } from './i18n.js';
|
|
27
29
|
export { denyAll, isSuperuser, languageOf, runOptionsOf, } from './identity.js';
|
|
28
30
|
export { imageVersions, registerImageRoutes } from './images.js';
|
|
29
31
|
export { migrate, orm, pg } from './orm.js';
|
package/dist/server/server.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import rateLimit from '@fastify/rate-limit';
|
|
7
7
|
import Fastify, {} from 'fastify';
|
|
8
8
|
import { Valkey } from 'iovalkey';
|
|
9
|
+
import { registerExplain } from './api/explain.js';
|
|
9
10
|
import { idempotencyTableStatements } from './api/idempotency.js';
|
|
10
11
|
import { publicApiModels } from './api/metadata.js';
|
|
11
12
|
import { Navigation } from './api/navigation.js';
|
|
@@ -19,6 +20,7 @@ import { enforceScopes } from './auth/scopes.js';
|
|
|
19
20
|
import { AuthService } from './auth/service.js';
|
|
20
21
|
import { applyEnvironmentNames } from './env-names.js';
|
|
21
22
|
import { HttpProblem, problemOf, ServerConfigError } from './errors.js';
|
|
23
|
+
import { loadDictionaries, registerTranslation } from './i18n.js';
|
|
22
24
|
import { denyAll, runOptionsOf } from './identity.js';
|
|
23
25
|
import { registerImageRoutes } from './images.js';
|
|
24
26
|
import { orm, pg } from './orm.js';
|
|
@@ -218,6 +220,8 @@ export async function createServer(options) {
|
|
|
218
220
|
baseUrl: options.oauth?.baseUrl ?? process.env['KOSH_BASE_URL'] ?? 'http://localhost:5173',
|
|
219
221
|
});
|
|
220
222
|
}
|
|
223
|
+
// Metadata and problems in the request's language, from the modules' dictionaries (RFC 0023 §3.1).
|
|
224
|
+
registerTranslation(app, await loadDictionaries(registry.loaded.modules));
|
|
221
225
|
// The generated REST API and its OpenAPI document (RFC 0002 §6.3–6.4).
|
|
222
226
|
for (const statement of idempotencyTableStatements())
|
|
223
227
|
await driver.query(statement);
|
|
@@ -235,6 +239,8 @@ export async function createServer(options) {
|
|
|
235
239
|
return openapi;
|
|
236
240
|
},
|
|
237
241
|
});
|
|
242
|
+
// What models, fields and buttons are, for Developer mode (RFC 0031 §3.1).
|
|
243
|
+
registerExplain(app, { registry, models });
|
|
238
244
|
new Navigation(registry.loaded, models).register(app);
|
|
239
245
|
views.register(app);
|
|
240
246
|
// Module routes (admin APIs, custom endpoints), in dependency order.
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* - `PATCH /api/v1/settings/company` `{ name?, numberGrouping?, accentColor?, details? }` (`accentColor`:
|
|
9
9
|
* `#rrggbb` or null; `details`: `{ field: value }`)
|
|
10
10
|
* - `GET /api/v1/settings/companies` every company with its currency and people, the currencies
|
|
11
|
-
* - `
|
|
11
|
+
* - `GET /api/v1/settings/companies` … and the details a new company may be given (`fields`)
|
|
12
|
+
* - `POST /api/v1/settings/companies` `{ name, currency, numberGrouping?, accentColor?, details? }`: a new company
|
|
13
|
+
* (administrators), with what each app set up for it (`defaults`)
|
|
12
14
|
*/
|
|
13
15
|
import { type ModuleContext } from '../server/index.js';
|
|
14
16
|
/** One of the company's details: a field an installed app adds. */
|
package/dist/settings/company.js
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* - `PATCH /api/v1/settings/company` `{ name?, numberGrouping?, accentColor?, details? }` (`accentColor`:
|
|
9
9
|
* `#rrggbb` or null; `details`: `{ field: value }`)
|
|
10
10
|
* - `GET /api/v1/settings/companies` every company with its currency and people, the currencies
|
|
11
|
-
* - `
|
|
11
|
+
* - `GET /api/v1/settings/companies` … and the details a new company may be given (`fields`)
|
|
12
|
+
* - `POST /api/v1/settings/companies` `{ name, currency, numberGrouping?, accentColor?, details? }`: a new company
|
|
13
|
+
* (administrators), with what each app set up for it (`defaults`)
|
|
12
14
|
*/
|
|
13
15
|
import { audit, HttpProblem, imageVersions, installDefaults, publicApiModels, } from '../server/index.js';
|
|
14
16
|
const model = (env, name) => env.model(name);
|
|
@@ -64,9 +66,11 @@ export function registerCompanyRoutes(context) {
|
|
|
64
66
|
},
|
|
65
67
|
// The superuser scope is audited: even a read writes its audit record.
|
|
66
68
|
{ write: true });
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
/**
|
|
70
|
+
* The company values of a body (`name`, `numberGrouping`, `accentColor`, `details`), checked: the same rules for a
|
|
71
|
+
* new company and a change.
|
|
72
|
+
*/
|
|
73
|
+
const companyValues = (body) => {
|
|
70
74
|
const values = {};
|
|
71
75
|
const invalid = (code, title, detail) => new HttpProblem(422, code, title, detail);
|
|
72
76
|
if (body['name'] !== undefined) {
|
|
@@ -109,6 +113,12 @@ export function registerCompanyRoutes(context) {
|
|
|
109
113
|
values[key] = typeof value === 'string' && value.trim() === '' ? null : value;
|
|
110
114
|
}
|
|
111
115
|
}
|
|
116
|
+
return values;
|
|
117
|
+
};
|
|
118
|
+
app.get('/api/v1/settings/company', async (request) => guarded(request, (su, company) => read(su, company)));
|
|
119
|
+
app.patch('/api/v1/settings/company', async (request) => {
|
|
120
|
+
const body = (request.body ?? {});
|
|
121
|
+
const values = companyValues(body);
|
|
112
122
|
return guarded(request, async (su, company) => {
|
|
113
123
|
if (Object.keys(values).length > 0)
|
|
114
124
|
await model(su, 'res.company').browse([company]).write(values);
|
|
@@ -122,6 +132,16 @@ export function registerCompanyRoutes(context) {
|
|
|
122
132
|
const currencyName = new Map(currencies.map((c) => [c['id'], String(c['name'])]));
|
|
123
133
|
return {
|
|
124
134
|
canCreate: env.administrator,
|
|
135
|
+
// What a new company may be given: the details a person changes (not those an app's own flow sets).
|
|
136
|
+
fields: detailFields()
|
|
137
|
+
.filter((f) => !f.readonly && !SHOWN_ONLY.has(f.key))
|
|
138
|
+
.map((f) => ({
|
|
139
|
+
key: f.key,
|
|
140
|
+
label: f.label,
|
|
141
|
+
kind: f.kind,
|
|
142
|
+
help: f.help,
|
|
143
|
+
options: f.options?.map((o) => ({ value: String(o[0]), label: String(o[1]) })) ?? null,
|
|
144
|
+
})),
|
|
125
145
|
companies: (await Promise.all(all.map(async (c) => ({
|
|
126
146
|
id: c['id'],
|
|
127
147
|
name: String(c['name']),
|
|
@@ -145,6 +165,7 @@ export function registerCompanyRoutes(context) {
|
|
|
145
165
|
const body = (request.body ?? {});
|
|
146
166
|
const name = String(body['name'] ?? '').trim();
|
|
147
167
|
const currency = Number(body['currency']);
|
|
168
|
+
const values = companyValues({ ...body, name });
|
|
148
169
|
if (name === '' || name.length > 200)
|
|
149
170
|
throw new HttpProblem(422, 'invalid-name', 'Invalid name', 'The company needs a name.');
|
|
150
171
|
if (!Number.isSafeInteger(currency) || currency <= 0)
|
|
@@ -155,7 +176,7 @@ export function registerCompanyRoutes(context) {
|
|
|
155
176
|
return env.asSuperuser({ reason: 'new company' }, async (su) => {
|
|
156
177
|
if ((await find(su, 'res.currency', { id: currency }, ['name'])).length === 0)
|
|
157
178
|
throw new HttpProblem(422, 'invalid-currency', 'Invalid currency', 'Choose its currency.');
|
|
158
|
-
const company = (await model(su, 'res.company').create([{ name, currency }]))
|
|
179
|
+
const company = (await model(su, 'res.company').create([{ ...values, name, currency }]))
|
|
159
180
|
.ids[0];
|
|
160
181
|
// The administrators and the person who made it can switch to it at once.
|
|
161
182
|
const admins = [...su.access.administratorGroups()];
|
|
@@ -40,6 +40,16 @@ export interface PlanInfo {
|
|
|
40
40
|
readonly unchanged: readonly string[];
|
|
41
41
|
readonly statements: readonly string[];
|
|
42
42
|
readonly empty: boolean;
|
|
43
|
+
/** Apps removed with their data (RFC 0008 §5.4), and what goes: each table or column with its rows. */
|
|
44
|
+
readonly uninstall: readonly {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly cascade: boolean;
|
|
47
|
+
}[];
|
|
48
|
+
readonly drops: readonly {
|
|
49
|
+
readonly table: string;
|
|
50
|
+
readonly column: string | null;
|
|
51
|
+
readonly rows: number;
|
|
52
|
+
}[];
|
|
43
53
|
}
|
|
44
54
|
/** Registers the App manager's routes. */
|
|
45
55
|
export declare function registerAppRoutes(context: ModuleContext): void;
|
package/dist/settings/routes.js
CHANGED
|
@@ -17,7 +17,7 @@ const NAME = /^[a-z][a-z0-9_]{0,63}$/;
|
|
|
17
17
|
function changeOf(body) {
|
|
18
18
|
const b = (body ?? {});
|
|
19
19
|
const out = {};
|
|
20
|
-
for (const key of ['install', 'enable', 'disable', 'upgrade']) {
|
|
20
|
+
for (const key of ['install', 'enable', 'disable', 'upgrade', 'uninstall']) {
|
|
21
21
|
const value = b[key];
|
|
22
22
|
if (value === undefined)
|
|
23
23
|
continue;
|
|
@@ -30,9 +30,10 @@ function changeOf(body) {
|
|
|
30
30
|
if ((out.install?.length ?? 0) +
|
|
31
31
|
(out.enable?.length ?? 0) +
|
|
32
32
|
(out.disable?.length ?? 0) +
|
|
33
|
-
(out.upgrade?.length ?? 0)
|
|
33
|
+
(out.upgrade?.length ?? 0) +
|
|
34
|
+
(out.uninstall?.length ?? 0) ===
|
|
34
35
|
0)
|
|
35
|
-
throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'Name at least one app to install, enable, disable or
|
|
36
|
+
throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'Name at least one app to install, enable, disable, upgrade or uninstall.');
|
|
36
37
|
return out;
|
|
37
38
|
}
|
|
38
39
|
/** Stable for the same change against the same installed set and schema. */
|
|
@@ -54,6 +55,8 @@ function planInfo(change, prepared) {
|
|
|
54
55
|
enable: plan.enable,
|
|
55
56
|
disable: plan.disable,
|
|
56
57
|
upgrade: plan.upgrade,
|
|
58
|
+
uninstall: plan.uninstall,
|
|
59
|
+
drops: prepared.drops,
|
|
57
60
|
unchanged: plan.unchanged,
|
|
58
61
|
statements: prepared.migration.statements.map((s) => s.sql),
|
|
59
62
|
empty: prepared.empty,
|
|
@@ -135,6 +138,17 @@ export function registerAppRoutes(context) {
|
|
|
135
138
|
throw new HttpProblem(409, 'plan-changed', 'The plan changed', 'The installed apps or the schema changed since this plan was made.', 'Review the new plan, then apply it.');
|
|
136
139
|
if (prepared.empty)
|
|
137
140
|
return { installed: [], enabled: [], disabled: [], migration: null };
|
|
141
|
+
// Removing data (RFC 0008 §5.4): the apps' names typed back, and a fresh code from the authenticator app.
|
|
142
|
+
if ((change.uninstall ?? []).length > 0) {
|
|
143
|
+
const expected = (change.uninstall ?? []).join(' ');
|
|
144
|
+
if (typeof body.confirm !== 'string' || body.confirm.trim() !== expected)
|
|
145
|
+
throw new HttpProblem(422, 'confirm-name', 'Type the app’s name', `Removing data needs the app’s name typed: ${expected}.`);
|
|
146
|
+
if (typeof body.code !== 'string' || body.code.trim() === '')
|
|
147
|
+
throw new HttpProblem(422, 'code-required', 'A code is needed', 'Removing data needs a code from your authenticator app.');
|
|
148
|
+
if (context.auth === undefined)
|
|
149
|
+
throw new HttpProblem(503, 'auth-unavailable', 'Sign-in unavailable', 'No sign-in here.');
|
|
150
|
+
await context.auth.confirmSecondFactor(uid, body.code);
|
|
151
|
+
}
|
|
138
152
|
const result = await applyApps(prepared, {
|
|
139
153
|
driver,
|
|
140
154
|
dir: apps.migrationsDir,
|
|
@@ -147,6 +161,8 @@ export function registerAppRoutes(context) {
|
|
|
147
161
|
installed: result.installed,
|
|
148
162
|
enabled: result.enabled,
|
|
149
163
|
disabled: result.disabled,
|
|
164
|
+
uninstalled: result.uninstalled,
|
|
165
|
+
snapshot: result.snapshot,
|
|
150
166
|
migration: result.migration === null
|
|
151
167
|
? null
|
|
152
168
|
: `${result.migration.version}_${result.migration.name}.sql`,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Settings → Apps (RFC 0008 §5.5): the App manager. A card per app with its icon, state and what it needs; search,
|
|
3
|
-
* category and state filters; Install, Enable and
|
|
4
|
-
* database changes and their SQL) and apply it after confirmation
|
|
3
|
+
* category and state filters; Install, Enable, Disable, Upgrade and Uninstall open the server's plan (what comes
|
|
4
|
+
* along, what goes, the database changes and their SQL) and apply it after confirmation — an uninstall, which removes
|
|
5
|
+
* the data, after the app's name is typed back and a code from the authenticator app is given. The server decides and checks everything; this
|
|
5
6
|
* page only shows what it says. After a change every cached query is refreshed: the menus and the launcher follow.
|
|
6
7
|
*/
|
|
7
8
|
import { type PageProps } from '../../ui/index.js';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Settings → Apps (RFC 0008 §5.5): the App manager. A card per app with its icon, state and what it needs; search,
|
|
4
|
-
* category and state filters; Install, Enable and
|
|
5
|
-
* database changes and their SQL) and apply it after confirmation
|
|
4
|
+
* category and state filters; Install, Enable, Disable, Upgrade and Uninstall open the server's plan (what comes
|
|
5
|
+
* along, what goes, the database changes and their SQL) and apply it after confirmation — an uninstall, which removes
|
|
6
|
+
* the data, after the app's name is typed back and a code from the authenticator app is given. The server decides and checks everything; this
|
|
6
7
|
* page only shows what it says. After a change every cached query is refreshed: the menus and the launcher follow.
|
|
7
8
|
*/
|
|
8
9
|
import { Alert, ApiError, AppIcon, Badge, Button, Card, Checkbox, Dialog, Input, Select, Spinner, } from '../../ui/index.js';
|
|
@@ -42,7 +43,12 @@ export function AppsPage({ api, label }) {
|
|
|
42
43
|
},
|
|
43
44
|
});
|
|
44
45
|
const apply = useMutation({
|
|
45
|
-
mutationFn: (p) => api.call('POST', '/api/v1/settings/apps/apply', {
|
|
46
|
+
mutationFn: ({ p, confirm, code }) => api.call('POST', '/api/v1/settings/apps/apply', {
|
|
47
|
+
change: { [p.kind]: [p.app.name] },
|
|
48
|
+
planId: p.plan.planId,
|
|
49
|
+
...(confirm === undefined ? {} : { confirm }),
|
|
50
|
+
...(code === undefined ? {} : { code }),
|
|
51
|
+
}),
|
|
46
52
|
onSuccess: async (result) => {
|
|
47
53
|
const labelOf = (name) => catalogue.data?.apps.find((a) => a.name === name)?.label ?? name;
|
|
48
54
|
const parts = [
|
|
@@ -50,6 +56,7 @@ export function AppsPage({ api, label }) {
|
|
|
50
56
|
...result.enabled.map((n) => t('doneEnabled', { name: labelOf(n) })),
|
|
51
57
|
...result.disabled.map((n) => t('doneDisabled', { name: labelOf(n) })),
|
|
52
58
|
...(result.upgraded ?? []).map((n) => t('doneUpgraded', { name: labelOf(n) })),
|
|
59
|
+
...(result.uninstalled ?? []).map((n) => t('doneUninstalled', { name: labelOf(n) })),
|
|
53
60
|
];
|
|
54
61
|
setPending(null);
|
|
55
62
|
setDone(parts.length === 0 ? t('nothingToDo') : t('done', { list: parts.join(', ') }));
|
|
@@ -99,26 +106,35 @@ export function AppsPage({ api, label }) {
|
|
|
99
106
|
? ''
|
|
100
107
|
: t('needs', { list: a.depends.map(labelOf).join(', ') }) }), a.installedVersion === null || a.state !== 'installed' ? null : (_jsx(Button, { size: "sm", variant: "primary", busy: plan.isPending &&
|
|
101
108
|
plan.variables?.kind === 'upgrade' &&
|
|
102
|
-
plan.variables.app.name === a.name, "aria-label": `${t('upgrade')} ${a.label}`, onClick: () => plan.mutate({ kind: 'upgrade', app: a }), children: t('upgrade') })), kind === null ? null : (_jsx(Button, { size: "sm", variant: kind === 'disable' ? 'secondary' : 'primary', busy: busy, "aria-label": `${t(kind)} ${a.label}`, onClick: () => plan.mutate({ kind, app: a }), children: t(kind) }))
|
|
109
|
+
plan.variables.app.name === a.name, "aria-label": `${t('upgrade')} ${a.label}`, onClick: () => plan.mutate({ kind: 'upgrade', app: a }), children: t('upgrade') })), kind === null ? null : (_jsx(Button, { size: "sm", variant: kind === 'disable' ? 'secondary' : 'primary', busy: busy, "aria-label": `${t(kind)} ${a.label}`, onClick: () => plan.mutate({ kind, app: a }), children: t(kind) })), a.state === 'available' || a.protected ? null : (_jsx(Button, { size: "sm", variant: "ghost", busy: plan.isPending &&
|
|
110
|
+
plan.variables?.kind === 'uninstall' &&
|
|
111
|
+
plan.variables.app.name === a.name, "aria-label": `${t('uninstall')} ${a.label}`, onClick: () => plan.mutate({ kind: 'uninstall', app: a }), children: t('uninstall') }))] })] }) }, a.name));
|
|
103
112
|
}) })), pending === null ? null : (_jsx(PlanDialog, { pending: pending, labelOf: labelOf, busy: apply.isPending, error: apply.error === null ? null : message(apply.error), onCancel: () => {
|
|
104
113
|
apply.reset();
|
|
105
114
|
setPending(null);
|
|
106
|
-
}, onConfirm: () => apply.mutate(pending) }))] }));
|
|
115
|
+
}, onConfirm: (confirm, code) => apply.mutate(confirm === undefined ? { p: pending } : { p: pending, confirm, code: code ?? '' }) }))] }));
|
|
107
116
|
}
|
|
108
117
|
function PlanDialog({ pending, labelOf, busy, error, onCancel, onConfirm, }) {
|
|
109
118
|
const { t } = useTranslation('settings');
|
|
110
119
|
const { kind, app, plan } = pending;
|
|
120
|
+
const formId = useId();
|
|
121
|
+
const [typed, setTyped] = useState('');
|
|
122
|
+
const [code, setCode] = useState('');
|
|
123
|
+
const removing = kind === 'uninstall';
|
|
124
|
+
const ready = !removing || (typed.trim() === app.name && code.trim() !== '');
|
|
111
125
|
const title = t(kind === 'install'
|
|
112
126
|
? 'planTitleInstall'
|
|
113
127
|
: kind === 'enable'
|
|
114
128
|
? 'planTitleEnable'
|
|
115
129
|
: kind === 'upgrade'
|
|
116
130
|
? 'planTitleUpgrade'
|
|
117
|
-
: '
|
|
131
|
+
: kind === 'uninstall'
|
|
132
|
+
? 'planTitleUninstall'
|
|
133
|
+
: 'planTitleDisable', { name: app.label });
|
|
118
134
|
return (_jsx(Dialog, { open: true, onOpenChange: (open) => {
|
|
119
135
|
if (!open && !busy)
|
|
120
136
|
onCancel();
|
|
121
|
-
}, title: title, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "secondary", onClick: onCancel, disabled: busy, children: t('cancel') }), _jsx(Button, { variant: kind === 'disable' ? 'danger' : 'primary', busy: busy, disabled: plan.empty, onClick: onConfirm, children: busy
|
|
137
|
+
}, title: title, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "secondary", onClick: onCancel, disabled: busy, children: t('cancel') }), _jsx(Button, { variant: kind === 'disable' || removing ? 'danger' : 'primary', busy: busy, disabled: plan.empty || !ready, onClick: () => (removing ? onConfirm(typed.trim(), code.trim()) : onConfirm()), children: busy
|
|
122
138
|
? t('applying')
|
|
123
139
|
: t(kind === 'install'
|
|
124
140
|
? 'confirmInstall'
|
|
@@ -126,7 +142,9 @@ function PlanDialog({ pending, labelOf, busy, error, onCancel, onConfirm, }) {
|
|
|
126
142
|
? 'confirmEnable'
|
|
127
143
|
: kind === 'upgrade'
|
|
128
144
|
? 'confirmUpgrade'
|
|
129
|
-
:
|
|
145
|
+
: removing
|
|
146
|
+
? 'confirmUninstall'
|
|
147
|
+
: 'confirmDisable') })] }), children: _jsxs("div", { className: "grid gap-3 text-sm", children: [plan.empty ? _jsx("p", { children: t('nothingToDo') }) : null, plan.install.length === 0 ? null : (_jsx(PlanList, { title: t('planInstall'), children: plan.install.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.reason === 'dependency' ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planNeeded')] })) : null] }, m.name))) })), plan.enable.length === 0 ? null : (_jsx(PlanList, { title: t('planEnable'), children: plan.enable.map((name) => (_jsx("li", { children: labelOf(name) }, name))) })), plan.disable.length === 0 ? null : (_jsx(PlanList, { title: t('planDisable'), children: plan.disable.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.cascade ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planCascade')] })) : null] }, m.name))) })), plan.upgrade.length === 0 ? null : (_jsx(PlanList, { title: t('planUpgrade'), children: plan.upgrade.map((u) => (_jsxs("li", { children: [labelOf(u.name), ' ', _jsxs("span", { className: "text-muted-foreground", children: [u.from, " \u2192 ", u.to] })] }, u.name))) })), plan.uninstall.length === 0 ? null : (_jsx(PlanList, { title: t('planUninstall'), children: plan.uninstall.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.cascade ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planCascade')] })) : null] }, m.name))) })), plan.drops.length === 0 ? null : (_jsxs("div", { children: [_jsx("h3", { className: "mb-1 font-medium", children: t('planDrops') }), _jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { children: _jsxs("tr", { className: "text-muted-foreground", children: [_jsx("th", { className: "text-start font-normal", children: t('planDropWhat') }), _jsx("th", { className: "text-end font-normal", children: t('planDropRows') })] }) }), _jsx("tbody", { children: plan.drops.map((d) => (_jsxs("tr", { children: [_jsx("td", { dir: "ltr", className: "text-start", children: d.column === null ? d.table : `${d.table}.${d.column}` }), _jsx("td", { className: "text-end tabular-nums", children: d.rows })] }, `${d.table}.${d.column ?? ''}`))) })] })] })), removing ? (_jsxs(_Fragment, { children: [_jsx(Alert, { children: t('planRemovesData') }), _jsxs("label", { htmlFor: `${formId}-name`, className: "grid gap-1", children: [_jsx("span", { children: t('typeName', { name: app.name }) }), _jsx(Input, { id: `${formId}-name`, autoComplete: "off", value: typed, onChange: (e) => setTyped(e.target.value) })] }), _jsxs("label", { htmlFor: `${formId}-code`, className: "grid gap-1", children: [_jsx("span", { children: t('authCode') }), _jsx(Input, { id: `${formId}-code`, inputMode: "numeric", autoComplete: "one-time-code", value: code, onChange: (e) => setCode(e.target.value) })] })] })) : null, kind === 'disable' ? _jsx(Alert, { tone: "warning", children: t('planKeepsData') }) : null, kind === 'install' ? _jsx("p", { className: "text-muted-foreground", children: t('planAccess') }) : null, _jsx("p", { className: "text-muted-foreground", children: plan.statements.length === 0
|
|
130
148
|
? t('planNoSchema')
|
|
131
149
|
: t('planSchema', { count: plan.statements.length }) }), plan.statements.length === 0 ? null : (_jsxs("details", { children: [_jsx("summary", { className: "cursor-pointer text-muted-foreground", children: t('planShowSql') }), _jsx("pre", { className: "mt-2 max-h-48 overflow-auto rounded-md bg-muted p-2 text-xs", dir: "ltr", children: plan.statements.map((sql) => `${sql};`).join('\n') })] })), error === null ? null : _jsx(Alert, { children: error })] }) }));
|
|
132
150
|
}
|