diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml
index 05804beac..416287fea 100644
--- a/.github/workflows/pre-merge.yml
+++ b/.github/workflows/pre-merge.yml
@@ -5,6 +5,7 @@ on:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- dev
+ - main
push:
branches:
- dev
@@ -63,7 +64,7 @@ jobs:
env:
PROD_CYPRESS_EMAIL: ${{ secrets.PROD_CYPRESS_EMAIL }}
PROD_CYPRESS_PASSWORD: ${{ secrets.PROD_CYPRESS_PASSWORD }}
- VITE_ENVIRONMENT: "production"
+ VITE_ENVIRONMENT: 'production'
with:
build: yarn build
start: yarn dev --logLevel=warn
@@ -162,25 +163,25 @@ jobs:
needs: [run-tests, download_and_merge]
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - uses: actions/download-artifact@v4
- with:
- name: coverage_unit_report
-
- - uses: actions/download-artifact@v4
- with:
- name: coverage_e2e_report
-
- - name: Extract E2E Coverage Report
- run: |
- unzip coverage.zip -d coverage_e2e
- pwd
- find ./
-
- - name: SonarCloud Scan
- uses: sonarsource/sonarcloud-github-action@v2.3.0
- env:
- SONAR_TOKEN: ${{ secrets.SONAR_CLOUD_TOKEN }}
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - uses: actions/download-artifact@v4
+ with:
+ name: coverage_unit_report
+
+ - uses: actions/download-artifact@v4
+ with:
+ name: coverage_e2e_report
+
+ - name: Extract E2E Coverage Report
+ run: |
+ unzip coverage.zip -d coverage_e2e
+ pwd
+ find ./
+
+ - name: SonarCloud Scan
+ uses: sonarsource/sonarcloud-github-action@v2.3.0
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_CLOUD_TOKEN }}
diff --git a/src/helpers/extract-api-error.js b/src/helpers/extract-api-error.js
new file mode 100644
index 000000000..04553710e
--- /dev/null
+++ b/src/helpers/extract-api-error.js
@@ -0,0 +1,34 @@
+/**
+ * Extracts the first error message from an API response.
+ * For generic errors, returns the detail message.
+ * For field validation errors, returns "field: error message".
+ *
+ * @param {Object} httpResponse - The HTTP response object.
+ * @param {Object} httpResponse.body - The response body.
+ * @returns {string} The formatted error message.
+ */
+export const extractApiError = (httpResponse) => {
+ const errorBody = httpResponse.body
+
+ if (errorBody.detail) {
+ return errorBody.detail
+ }
+
+ const findFirstError = (obj) => {
+ for (const [key, value] of Object.entries(obj)) {
+ if (Array.isArray(value)) {
+ return `${key}: ${value[0]}`
+ }
+ if (typeof value === 'object' && value !== null) {
+ const nestedError = findFirstError(value)
+ if (nestedError) {
+ const cleanFieldName = nestedError.replace(/^[^:]+\./, '')
+ return cleanFieldName
+ }
+ }
+ }
+ return null
+ }
+
+ return findFirstError(errorBody) || 'Unknown error occurred'
+}
diff --git a/src/router/routes/domains-routes/index.js b/src/router/routes/domains-routes/index.js
index df93394fd..685cc3d99 100644
--- a/src/router/routes/domains-routes/index.js
+++ b/src/router/routes/domains-routes/index.js
@@ -3,6 +3,7 @@ import * as DomainServices from '@/services/domains-services'
import * as DomainServicesV4 from '@/services/domains-services/v4'
import * as DigitalCertificatesServices from '@/services/digital-certificates-services'
import * as EdgeApplicationServices from '@/services/edge-application-services'
+import * as EdgeFirewallServicesV4 from '@/services/edge-firewall-services/v4'
/** @type {import('vue-router').RouteRecordRaw} */
export const domainsRoutes = {
@@ -36,6 +37,8 @@ export const domainsRoutes = {
createDomainService: DomainServices.createDomainService,
listDigitalCertificatesService: DigitalCertificatesServices.listDigitalCertificatesService,
listEdgeApplicationsService: EdgeApplicationServices.listEdgeApplicationsService,
+ listEdgeFirewallService: EdgeFirewallServicesV4.listEdgeFirewallService,
+ loadEdgeFirewallService: EdgeFirewallServicesV4.loadEdgeFirewallService,
clipboardWrite: Helpers.clipboardWrite
},
meta: {
@@ -60,6 +63,8 @@ export const domainsRoutes = {
listDigitalCertificatesService: DigitalCertificatesServices.listDigitalCertificatesService,
listEdgeApplicationsService: EdgeApplicationServices.listEdgeApplicationsService,
loadDomainService: DomainServices.loadDomainService,
+ listEdgeFirewallService: EdgeFirewallServicesV4.listEdgeFirewallService,
+ loadEdgeFirewallService: EdgeFirewallServicesV4.loadEdgeFirewallService,
updatedRedirect: 'list-domains',
clipboardWrite: Helpers.clipboardWrite
},
diff --git a/src/services/edge-firewall-services/v4/index.js b/src/services/edge-firewall-services/v4/index.js
index cb42c72aa..0cafe796c 100644
--- a/src/services/edge-firewall-services/v4/index.js
+++ b/src/services/edge-firewall-services/v4/index.js
@@ -1,5 +1,6 @@
import { listEdgeFirewallService } from './list-edge-firewall-service'
import { cloneEdgeFirewallService } from './clone-edge-firewall-service'
+import { loadEdgeFirewallService } from './load-edge-firewall-service'
/**
* @typedef {Object} ExportedServicesType - The type of the exported services
@@ -9,4 +10,4 @@ import { cloneEdgeFirewallService } from './clone-edge-firewall-service'
/**
* @type {ExportedServicesType}
*/
-export { listEdgeFirewallService, cloneEdgeFirewallService }
+export { listEdgeFirewallService, cloneEdgeFirewallService, loadEdgeFirewallService }
diff --git a/src/services/edge-firewall-services/v4/load-edge-firewall-service.js b/src/services/edge-firewall-services/v4/load-edge-firewall-service.js
new file mode 100644
index 000000000..eba4efdbe
--- /dev/null
+++ b/src/services/edge-firewall-services/v4/load-edge-firewall-service.js
@@ -0,0 +1,38 @@
+import { extractApiError } from '@/helpers/extract-api-error'
+import { AxiosHttpClientAdapter, parseHttpResponse } from '@/services/axios/AxiosHttpClientAdapter'
+import { makeEdgeFirewallBaseUrl } from './make-edge-firewall-base-url'
+
+export const loadEdgeFirewallService = async ({ id }) => {
+ let httpResponse = await AxiosHttpClientAdapter.request({
+ url: `${makeEdgeFirewallBaseUrl()}/${id}`,
+ method: 'GET'
+ })
+
+ httpResponse = adapt(httpResponse)
+
+ return parseHttpResponse(httpResponse)
+}
+
+const adapt = ({ body, statusCode }) => {
+ if (statusCode !== 200) {
+ throw new Error(extractApiError({ body })).message
+ }
+
+ const payload = body.data
+ const parsedBody = {
+ id: payload.id,
+ name: payload.name,
+ isActive: payload.active,
+ edgeFunctionsEnabled: payload.modules.edge_functions_enabled,
+ networkProtectionEnabled: payload.modules.network_protection_enabled,
+ wafEnabled: payload.modules.waf_enabled,
+ debugRules: payload.debug_rules,
+ domains: payload.domains || [],
+ ddosProtectionUnmetered: true
+ }
+
+ return {
+ body: parsedBody,
+ statusCode
+ }
+}
diff --git a/src/templates/form-fields-inputs/fieldDropdownLazyLoader.vue b/src/templates/form-fields-inputs/fieldDropdownLazyLoader.vue
new file mode 100644
index 000000000..16d7f2df6
--- /dev/null
+++ b/src/templates/form-fields-inputs/fieldDropdownLazyLoader.vue
@@ -0,0 +1,364 @@
+
+