From 54e59b4b3e8450f2d27064843123744cc672bba3 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Mon, 13 Jul 2026 10:07:56 +0200 Subject: [PATCH] Add system status displays for Minio and Redis, and enhance backup configuration --- docs/app-store-release.md | 90 + scripts/playwright-pr-mapping.mjs | 13 +- scripts/run-playwright-full-slice.mjs | 2 +- .../department/pos/PosSelectedCustomer.vue | 22 +- .../PaginationOtherFiltersDropdown.vue | 59 +- .../InvoiceOrdersPagination.vue | 160 +- .../SuperUserDashboard/SubusersPagination.vue | 74 +- .../superuser/system/MinioDisplay.vue | 7 + .../superuser/system/RedisDisplay.vue | 7 + .../system/SystemDependencyDisplay.vue | 210 ++ src/components/pagination/departmentTabs.vue | 17 + .../token/SessionUser/Objects/Subusers.vue | 271 ++ .../superUser/modules/Backups/Backups.vue | 37 +- .../superUser/modules/Backups/Config.vue | 25 +- .../token/superUser/systemDatabase.vue | 5 + .../session/token/superUser/systemMinio.vue | 8 + .../session/token/superUser/systemRedis.vue | 8 + .../session/token/superUser/systemStatus.vue | 35 +- .../session/token/superUserObject.vue | 177 +- src/features/customer/CustomerRuleTooltip.vue | 400 +++ src/features/customer/customerProductRules.js | 47 +- .../customer/customerRuleProductCatalog.js | 74 + .../customer/customerRuleProductImpact.js | 167 ++ src/features/customer/customerRuleRegistry.js | 5 + src/i18n/generated/da-v2.json | 18 + src/i18n/generated/de-v2.json | 87 +- src/i18n/generated/en-v2.json | 87 +- src/i18n/generated/global-v2.json | 224 +- src/i18n/generated/no-v2.json | 18 + src/i18n/generated/sv-v2.json | 87 +- .../da/phrases/compat/support/index.json | 20 + .../phrases/compat/configuration/index.json | 50 +- .../compat/customer_rules/attributes.json | 15 + .../de/phrases/compat/pagination/index.json | 1 + .../de/phrases/compat/support/index.json | 20 + .../phrases/compat/system_status/index.json | 3 + .../phrases/compat/configuration/index.json | 50 +- .../compat/customer_rules/attributes.json | 15 + .../en/phrases/compat/pagination/index.json | 1 + .../en/phrases/compat/support/index.json | 20 + .../phrases/compat/system_status/index.json | 3 + .../global/shared/configuration/index.json | 50 +- .../shared/customer_rules/attributes.json | 15 + .../global/shared/pagination/index.json | 1 + .../source/global/shared/security/index.json | 137 + .../source/global/shared/support/index.json | 20 + .../global/shared/system_status/index.json | 5 + .../no/phrases/compat/support/index.json | 20 + .../phrases/compat/configuration/index.json | 50 +- .../compat/customer_rules/attributes.json | 15 + .../sv/phrases/compat/pagination/index.json | 1 + .../sv/phrases/compat/support/index.json | 20 + .../phrases/compat/system_status/index.json | 3 + src/router.js | 59 +- src/services/superuserReleases.js | 6 + src/services/superuserReplication.js | 38 - src/services/superuserSecurity.js | 33 + .../configuration/ConfigurationBackups.vue | 560 +++- .../ConfigurationReleaseManager.vue | 364 ++- .../roles/rolePermissionCatalog.js | 2 +- .../system/MinioOverview.vue | 15 + .../system/RedisOverview.vue | 15 + .../system/ReplicationManagement.vue | 2502 ----------------- .../system/SystemSecurity.vue | 1063 +++++++ .../user/UserCustomerRuleManager.vue | 9 +- .../userDashboard/bookings/MyBookingsBook.vue | 61 +- src/views/pages/SupportPage.vue | 179 ++ tests/e2e/coolify-infrastructure.spec.js | 1083 ------- tests/e2e/superuser-cron.spec.ts | 93 +- .../e2e/superuser-orders-date-filters.spec.ts | 43 +- tests/e2e/superuser-roles-permissions.spec.ts | 4 +- tests/e2e/superuser-security.spec.ts | 264 ++ tests/e2e/support/network.js | 58 +- tests/e2e/userBookWash.spec.ts | 39 + .../customer-rule-product-catalog.spec.js | 63 + tests/unit/customer-rule-registry.spec.js | 16 + tests/unit/customer-rule-tooltip.spec.js | 211 ++ .../playwright-full-slice-ownership.spec.js | 1 - tests/unit/playwright-pr-mapping.spec.js | 7 + tests/unit/role-permission-catalog.spec.js | 25 +- ...sion-token-initialization-contract.spec.js | 4 +- 81 files changed, 5814 insertions(+), 3979 deletions(-) create mode 100644 docs/app-store-release.md create mode 100644 src/components/displays/superuser/system/MinioDisplay.vue create mode 100644 src/components/displays/superuser/system/RedisDisplay.vue create mode 100644 src/components/displays/superuser/system/SystemDependencyDisplay.vue create mode 100644 src/components/session/token/superUser/systemMinio.vue create mode 100644 src/components/session/token/superUser/systemRedis.vue create mode 100644 src/features/customer/CustomerRuleTooltip.vue create mode 100644 src/features/customer/customerRuleProductCatalog.js create mode 100644 src/features/customer/customerRuleProductImpact.js create mode 100644 src/i18n/source/da/phrases/compat/support/index.json create mode 100644 src/i18n/source/de/phrases/compat/support/index.json create mode 100644 src/i18n/source/en/phrases/compat/support/index.json create mode 100644 src/i18n/source/global/shared/security/index.json create mode 100644 src/i18n/source/global/shared/support/index.json create mode 100644 src/i18n/source/no/phrases/compat/support/index.json create mode 100644 src/i18n/source/sv/phrases/compat/support/index.json delete mode 100644 src/services/superuserReplication.js create mode 100644 src/services/superuserSecurity.js create mode 100644 src/views/dashboards/superUserDashboard/system/MinioOverview.vue create mode 100644 src/views/dashboards/superUserDashboard/system/RedisOverview.vue delete mode 100644 src/views/dashboards/superUserDashboard/system/ReplicationManagement.vue create mode 100644 src/views/dashboards/superUserDashboard/system/SystemSecurity.vue create mode 100644 src/views/pages/SupportPage.vue delete mode 100644 tests/e2e/coolify-infrastructure.spec.js create mode 100644 tests/e2e/superuser-security.spec.ts create mode 100644 tests/unit/customer-rule-product-catalog.spec.js create mode 100644 tests/unit/customer-rule-tooltip.spec.js diff --git a/docs/app-store-release.md b/docs/app-store-release.md new file mode 100644 index 00000000..0b3ac355 --- /dev/null +++ b/docs/app-store-release.md @@ -0,0 +1,90 @@ +# Apple App Store Release Runbook + +This runbook covers the public iOS App Store release path for the Truck Wash +Capacitor app. + +## Account And App Record + +- Use the Truck Wash ApS Apple Developer account. The Account Holder must accept + the latest Apple agreements before builds can be uploaded. +- Create or verify the App Store Connect app record: + - Platform: iOS + - Name: Truck Wash Kundeportal + - Bundle ID: `io.truckwash.app` + - SKU: `truckwash-ios` + - Primary language: Danish + - Category: Business + - Price: Free + - Initial availability: Denmark +- Keep the GitHub environment `app-store-production` protected and store iOS + signing plus App Store Connect API secrets there. + +## Build And Upload + +1. Merge the release commit to `master`. +2. Confirm `Automated Tests` and `Frontend Release` are green for that commit. +3. Create a release tag such as `mobile-v1.0.0`. +4. The `Mobile Store Artifacts` workflow builds Android and iOS artifacts. For + iOS, it archives, exports, validates the IPA with App Store Connect, and + uploads it when the run is tag-triggered. +5. For a manual upload, dispatch `Mobile Store Artifacts` with + `upload_to_app_store=true`, `version_name`, and `version_code`. + +The iOS workflow expects these environment secrets: + +- `IOS_CERTIFICATE_BASE64` +- `IOS_CERTIFICATE_PASSWORD` +- `IOS_PROVISION_PROFILE_BASE64` +- `IOS_KEYCHAIN_PASSWORD` +- `APPLE_TEAM_ID` +- `APP_STORE_CONNECT_API_KEY_ID` +- `APP_STORE_CONNECT_ISSUER_ID` +- `APP_STORE_CONNECT_API_PRIVATE_KEY_BASE64` + +## Product Page Defaults + +- Support URL: `https://truckwash.io/support` +- Privacy URL: `https://truckwash.io/privacy-policy` +- Subtitle: `Book og start truckvask` +- Promotional text: `Administrer vask, koeretoejer, ordrer og fakturaer fra mobilen.` +- Keywords: `truck wash,lastbilvask,vask,booking,kundeportal` +- Expected age rating: 4+, subject to the App Store Connect questionnaire. + +Use real iOS simulator or device screenshots. Provide at least: + +- iPhone 6.9-inch portrait screenshots +- iPad 13-inch portrait screenshots + +Recommended screenshot scenes: dashboard, booking flow, self-service wash start, +vehicles/orders, and invoices/payment history. Do not include real customer +data, private tokens, or placeholder copy. + +## Privacy And Review Notes + +App Store Connect privacy labels must match the actual app and backend behavior. +Expected minimum disclosures include account/contact data, identifiers such as +customer number, vehicle/license plate data, order and invoice history, payment +state, approximate/precise location when used, and photos or attachments when +users upload them. Tracking should remain false unless analytics/ad tracking is +introduced. + +Review notes must include: + +- A demo account and password. +- OTP/2FA/passkey fallback instructions when enabled for the account. +- A clear statement that Stripe/card payments are for physical truck-wash + services consumed outside the app, so Apple in-app purchase is not used. +- Any hardware-dependent functionality that reviewers cannot reproduce, with a + short demo video if needed. +- Confirmation that the backend environment is online for the whole review + window. + +## TestFlight And Release + +1. Wait for App Store Connect processing to finish. +2. Distribute the processed build to internal TestFlight testers. +3. Run clean-device QA on iPhone and iPad. +4. Fix issues using the same marketing version and an incremented build number. +5. Submit for App Review with manual release after approval. +6. After approval, release to Denmark first and monitor crashes, support mail, + and App Store Connect feedback before expanding availability. diff --git a/scripts/playwright-pr-mapping.mjs b/scripts/playwright-pr-mapping.mjs index aaad3bd3..14e70f01 100644 --- a/scripts/playwright-pr-mapping.mjs +++ b/scripts/playwright-pr-mapping.mjs @@ -175,10 +175,21 @@ export const sourceMappings = [ }, { name: "system-status", - patterns: [/system[-/]?status/iu, /systemDatabase/iu, /replication/iu], + patterns: [/system[-/]?status/iu, /system(?:Database|Redis|Minio)/iu, /SystemDependencyDisplay/iu, /replication/iu], specs: ["tests/e2e/superuser-system-status.smoke.spec.js"], projects: chromiumProjects, }, + { + name: "superuser-security", + patterns: [ + /^src\/views\/dashboards\/superUserDashboard\/system\/SystemSecurity\.vue$/u, + /^src\/services\/superuserSecurity\.js$/u, + /superuser[-/]?security/iu, + /system\/security/iu, + ], + specs: ["tests/e2e/superuser-security.spec.ts"], + projects: chromiumProjects, + }, { name: "superuser-department-pricing", patterns: [ diff --git a/scripts/run-playwright-full-slice.mjs b/scripts/run-playwright-full-slice.mjs index e4140efa..2cc31379 100644 --- a/scripts/run-playwright-full-slice.mjs +++ b/scripts/run-playwright-full-slice.mjs @@ -80,7 +80,6 @@ export const ownedFilesByRole = { "pos.visual.spec.js", ], superuser: [ - "coolify-infrastructure.spec.js", "edge-gateways.fleet-outline.spec.js", "edge-gateways.routes.spec.js", "edge-gateways.smoke.spec.js", @@ -114,6 +113,7 @@ export const ownedFilesByRole = { "superuser-orders-date-filters.spec.ts", "superuser-products-layout.spec.ts", "superuser-roles-permissions.spec.ts", + "superuser-security.spec.ts", "superuser-system-status.smoke.spec.js", "superuser-users.spec.ts", "superuser-vehicles.smoke.spec.js", diff --git a/src/components/displays/department/pos/PosSelectedCustomer.vue b/src/components/displays/department/pos/PosSelectedCustomer.vue index 3a6523ad..667d040c 100644 --- a/src/components/displays/department/pos/PosSelectedCustomer.vue +++ b/src/components/displays/department/pos/PosSelectedCustomer.vue @@ -4,6 +4,7 @@ import { customer_id, customer_data, customer_attributes, + department_id, loadCustomerAttributes, hideDiscountsCatalog, hidePricesCatalog, @@ -20,17 +21,11 @@ import "bulma-switch/dist/css/bulma-switch.min.css"; import "bulma-block-list/src/block-list.scss"; import { SessionUser } from "@/components/session/token/SessionUser.vue"; import { useI18n } from "vue-i18n"; -import { - popperBox, - popper, - removePopperIfOpen, - showPopperWithContent, - showPopper, -} from "@/components/displays/PopperDefault.vue"; import RequiresPermission from "@/components/displays/permissionbased/RequiresPermission.vue"; import CustomerDiscountsDepartmentDisplay from "@/components/displays/department/pos/displays/CustomerDiscountsDepartmentDisplay.vue"; import ExpandableContentBox from "@/components/displays/boxes/ExpandableContentBox.vue"; import { getCustomerRuleDefinitions } from "@/features/customer/customerRuleRegistry.js"; +import CustomerRuleTooltip from "@/features/customer/CustomerRuleTooltip.vue"; const { t } = useI18n(); const emit = defineEmits(["update:activeTab"]); @@ -276,12 +271,15 @@ const customer_data_has_empty_details = () => { - {{ attribute.name }} + {{ attribute.name }} + { :class="{ 'is-active': isOpen }" :data-testid="testId" > - diff --git a/src/components/displays/pagination/models/SuperUserDashboard/InvoiceOrdersPagination.vue b/src/components/displays/pagination/models/SuperUserDashboard/InvoiceOrdersPagination.vue index 0aa30bb3..9e52eceb 100644 --- a/src/components/displays/pagination/models/SuperUserDashboard/InvoiceOrdersPagination.vue +++ b/src/components/displays/pagination/models/SuperUserDashboard/InvoiceOrdersPagination.vue @@ -323,6 +323,25 @@ const activeHiddenOrderFiltersCount = computed(() => hiddenOrderFilterDefinition return isActiveHiddenOrderFilterValue(value); }).length); +const hasActiveHiddenOrderFilters = computed(() => activeHiddenOrderFiltersCount.value > 0); + +const clearHiddenOrderFilters = () => { + if (!hasActiveHiddenOrderFilters.value) { + return; + } + + hiddenOrderFilterDefinitions.value.forEach((filterDefinition) => { + if (filterDefinition.type === "order") { + setOrder("created_at", filterDefinition.defaultValue); + return; + } + + setFilter(filterDefinition.filterKey, "*", false); + }); + + loadList(); +}; + const doesEndpointMatch = (matcher) => { // Check if the endpoint matches the current endpoint return endpoint.value === matcher; @@ -454,56 +473,67 @@ watch(orderDateEventSignature, () => { - -