---
src/composables/useModuleConfig.js | 98 +++++++++
.../configuration/ConfigurationEmail.vue | 186 +++++++-----------
.../configuration/ConfigurationOpenAI.vue | 53 +----
.../configuration/ConfigurationStripe.vue | 156 ++++++---------
tests/unit/use-module-config.spec.js | 149 ++++++++++++++
5 files changed, 382 insertions(+), 260 deletions(-)
create mode 100644 src/composables/useModuleConfig.js
create mode 100644 tests/unit/use-module-config.spec.js
diff --git a/src/composables/useModuleConfig.js b/src/composables/useModuleConfig.js
new file mode 100644
index 00000000..d471892b
--- /dev/null
+++ b/src/composables/useModuleConfig.js
@@ -0,0 +1,98 @@
+import { onMounted, ref } from "vue";
+import { SessionUser } from "@/components/session/token/SessionUser.vue";
+
+const TRUTHY_BOOL_LITERALS = new Set(["true", "1", "yes", "on"]);
+
+const coerceConfigBoolean = (raw) => {
+ if (raw === true || raw === 1) return true;
+ if (typeof raw === "string") {
+ return TRUTHY_BOOL_LITERALS.has(raw.trim().toLowerCase());
+ }
+ return false;
+};
+
+const normalizeEntries = (payload) => {
+ if (Array.isArray(payload)) {
+ return payload.map((entry) => ({
+ variable: entry?.variable,
+ value: entry?.value,
+ isSecret: entry?.isSecret === true,
+ isSet: entry?.isSet === true,
+ }));
+ }
+ return Object.values(payload ?? {}).map((entry) => ({
+ variable: entry?.variable,
+ value: entry?.value,
+ isSecret: entry?.isSecret === true,
+ isSet: entry?.isSet === true,
+ }));
+};
+
+/**
+ * Replaces the copy-pasted `getModuleConfig` / `getModuleConfigValue` /
+ * `module_config = ref([])` triple that 20+ `Configuration*.vue` pages
+ * each defined themselves.
+ *
+ * @param {string} moduleName - e.g. "stripe", "xlvask", "bird"
+ * @param {object} [options]
+ * @param {boolean} [options.coerceBooleans=true] - return `true`/`false` for `'true'`/`'false'` strings
+ * @param {boolean} [options.autoLoad=true] - load on mount
+ * @returns module_config, loading, error, refresh, getModuleConfigValue, getEntry, isVariableSet
+ */
+export const useModuleConfig = (moduleName, options = {}) => {
+ const { coerceBooleans = true, autoLoad = true } = options;
+
+ const module_config = ref([]);
+ const loading = ref(false);
+ const error = ref(null);
+
+ const getEntry = (variable) => module_config.value.find((entry) => entry.variable === variable);
+
+ const getModuleConfigValue = (variable) => {
+ const entry = getEntry(variable);
+ if (!entry) return "";
+ const raw = entry.value;
+ if (coerceBooleans) {
+ if (raw === "true" || raw === true) return true;
+ if (raw === "false" || raw === false) return false;
+ }
+ return raw ?? "";
+ };
+
+ const isVariableSet = (variable) => {
+ const entry = getEntry(variable);
+ if (!entry) return false;
+ if (entry.isSecret) return entry.isSet;
+ return entry.value !== null && entry.value !== undefined && entry.value !== "";
+ };
+
+ const load = async () => {
+ loading.value = true;
+ error.value = null;
+ try {
+ const response = await SessionUser.superUser.modules[moduleName].config.get_all();
+ module_config.value = normalizeEntries(response?.data?.data);
+ } catch (err) {
+ console.error(`useModuleConfig(${moduleName}): load failed`, err);
+ module_config.value = [];
+ error.value = err;
+ } finally {
+ loading.value = false;
+ }
+ };
+
+ if (autoLoad) {
+ onMounted(load);
+ }
+
+ return {
+ module_config,
+ loading,
+ error,
+ load,
+ getEntry,
+ getModuleConfigValue,
+ isVariableSet,
+ coerceConfigBoolean,
+ };
+};
diff --git a/src/views/dashboards/superUserDashboard/configuration/ConfigurationEmail.vue b/src/views/dashboards/superUserDashboard/configuration/ConfigurationEmail.vue
index 92b847fd..14774014 100644
--- a/src/views/dashboards/superUserDashboard/configuration/ConfigurationEmail.vue
+++ b/src/views/dashboards/superUserDashboard/configuration/ConfigurationEmail.vue
@@ -3,107 +3,64 @@ import PageTitle from "@/components/global/PageTitle.vue";
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
-import { ref } from 'vue';
-
-import ConfigurationSubPageWrapper
- from "@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue";
+import ConfigurationSubPageWrapper from "@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue";
import ConfigurationCategory from "@/components/displays/superuser/configuration/ConfigurationCategory.vue";
import ConfigurationSwitch from "@/components/displays/superuser/configuration/ConfigurationSwitch.vue";
import ConfigurationSelect from "@/components/displays/superuser/configuration/ConfigurationSelect.vue";
import ConfigurationSecretKey from "@/components/displays/superuser/configuration/ConfigurationSecretKey.vue";
import ConfigurationInput from "@/components/displays/superuser/configuration/ConfigurationInput.vue";
import Swal from "sweetalert2";
-import { useI18n } from 'vue-i18n';
+import { useI18n } from "vue-i18n";
+import { useModuleConfig } from "@/composables/useModuleConfig.js";
const { t } = useI18n();
-
-// Get the department from the route
-
-
-
-const module_config = ref([]);
-
-
-
-const getModuleConfig = async () => {
- await SessionUser.superUser.modules.email.config.get_all().then((response) => {
- let tmp_module_config = response.data.data;
- let tmp_module_config_array = [];
- for (const value of Object.values(tmp_module_config)) {
- console.log(`${value.variable}: ${value.value}`);
- tmp_module_config_array.push({
- variable: value.variable,
- value: value.value,
- });
- }
- module_config.value = tmp_module_config_array;
- console.log(module_config.value);
- }).catch((error) => {
- console.log(error);
- });
-};
-
-const getModuleConfigValue = (variable) => {
- const config = module_config.value.find((config) => config.variable === variable);
- // Log to the console, what the value was found
- if (config) {
- console.log(`Found value for ${variable}: ${config.value}`);
- } else {
- console.log(`No value found for ${variable}`);
- }
- return config ? config.value : '';
-};
-
-const load = async () => {
- await getModuleConfig();
-};
+const { module_config, getModuleConfigValue } = useModuleConfig("email");
const encryptionOptions = [
- { value: 'ssl', label: 'SSL' },
- { value: 'tls', label: 'TLS' },
- { value: 'starttls', label: 'STARTTLS' },
- { value: 'none', label: 'None' },
+ { value: "ssl", label: "SSL" },
+ { value: "tls", label: "TLS" },
+ { value: "starttls", label: "STARTTLS" },
+ { value: "none", label: "None" },
];
const showSendTestEmail = async () => {
await Swal.fire({
- title: t('configuration.email.send_test_email'),
- text: t('configuration.email.send_test_email_prompt'),
- input: 'email',
+ title: t("configuration.email.send_test_email"),
+ text: t("configuration.email.send_test_email_prompt"),
+ input: "email",
inputAttributes: {
- autocapitalize: 'off'
+ autocapitalize: "off",
},
showCancelButton: true,
- confirmButtonText: t('configuration.email.send'),
+ confirmButtonText: t("configuration.email.send"),
showLoaderOnConfirm: true,
preConfirm: (email) => {
- return SessionUser.superUser.modules.email.sendTestEmail(email)
- .then(() => {
- Swal.fire({
- title: t('configuration.email.test_email_sent'),
- text: t('configuration.email.test_email_sent_success'),
- icon: 'success',
- });
- })
- .catch(() => {
- Swal.fire({
- title: t('common.error'),
- text: t('configuration.email.test_email_error'),
- icon: 'error',
- });
+ return SessionUser.superUser.modules.email
+ .sendTestEmail(email)
+ .then(() => {
+ Swal.fire({
+ title: t("configuration.email.test_email_sent"),
+ text: t("configuration.email.test_email_sent_success"),
+ icon: "success",
});
+ })
+ .catch(() => {
+ Swal.fire({
+ title: t("common.error"),
+ text: t("configuration.email.test_email_error"),
+ icon: "error",
+ });
+ });
},
- allowOutsideClick: () => !Swal.isLoading()
+ allowOutsideClick: () => !Swal.isLoading(),
});
};
-
-load();
-
+
-
-
+
+
-
-
\ No newline at end of file
+
diff --git a/src/views/dashboards/superUserDashboard/configuration/ConfigurationOpenAI.vue b/src/views/dashboards/superUserDashboard/configuration/ConfigurationOpenAI.vue
index 39b6c98c..ddcdb788 100644
--- a/src/views/dashboards/superUserDashboard/configuration/ConfigurationOpenAI.vue
+++ b/src/views/dashboards/superUserDashboard/configuration/ConfigurationOpenAI.vue
@@ -3,57 +3,14 @@ import PageTitle from "@/components/global/PageTitle.vue";
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
-import { ref } from 'vue';
-import ConfigurationSubPageWrapper
- from "@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue";
+import ConfigurationSubPageWrapper from "@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue";
import ConfigurationCategory from "@/components/displays/superuser/configuration/ConfigurationCategory.vue";
import ConfigurationSwitch from "@/components/displays/superuser/configuration/ConfigurationSwitch.vue";
import ConfigurationSecretKey from "@/components/displays/superuser/configuration/ConfigurationSecretKey.vue";
+import { useModuleConfig } from "@/composables/useModuleConfig.js";
-// Get the department from the route
-
-
-
-const module_config = ref([]);
-
-
-
-const getModuleConfig = async () => {
- await SessionUser.superUser.modules.openai.config.get_all().then((response) => {
- let tmp_module_config = response.data.data;
- let tmp_module_config_array = [];
- for (const value of Object.values(tmp_module_config)) {
- console.log(`${value.variable}: ${value.value}`);
- tmp_module_config_array.push({
- variable: value.variable,
- value: value.value,
- });
- }
- module_config.value = tmp_module_config_array;
- console.log(module_config.value);
- }).catch((error) => {
- console.log(error);
- });
-};
-
-const getModuleConfigValue = (variable) => {
- const config = module_config.value.find((config) => config.variable === variable);
- // Log to the console, what the value was found
- if (config) {
- console.log(`Found value for ${variable}: ${config.value}`);
- } else {
- console.log(`No value found for ${variable}`);
- }
- return config ? config.value : '';
-};
-
-const load = async () => {
- await getModuleConfig();
-};
-
-load();
-
+const { module_config, getModuleConfigValue } = useModuleConfig("openai");
@@ -102,6 +59,4 @@ load();
-
\ No newline at end of file
+
diff --git a/src/views/dashboards/superUserDashboard/configuration/ConfigurationStripe.vue b/src/views/dashboards/superUserDashboard/configuration/ConfigurationStripe.vue
index 0e3914ab..39d474d6 100644
--- a/src/views/dashboards/superUserDashboard/configuration/ConfigurationStripe.vue
+++ b/src/views/dashboards/superUserDashboard/configuration/ConfigurationStripe.vue
@@ -3,10 +3,7 @@ import PageTitle from "@/components/global/PageTitle.vue";
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
-import { ref } from 'vue';
-
-import ConfigurationSubPageWrapper
- from "@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue";
+import ConfigurationSubPageWrapper from "@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue";
import ConfigurationCategory from "@/components/displays/superuser/configuration/ConfigurationCategory.vue";
import ConfigurationSwitch from "@/components/displays/superuser/configuration/ConfigurationSwitch.vue";
import "@/components/displays/superuser/configuration/ConfigurationSelect.vue";
@@ -14,95 +11,64 @@ import ConfigurationSecretKey from "@/components/displays/superuser/configuratio
import ConfigurationInput from "@/components/displays/superuser/configuration/ConfigurationInput.vue";
import ConfigurationInputNumber from "@/components/displays/superuser/configuration/ConfigurationInputNumber.vue";
import Swal from "sweetalert2";
-import { useI18n } from 'vue-i18n';
+import { useI18n } from "vue-i18n";
+import { useModuleConfig } from "@/composables/useModuleConfig.js";
+
const { t } = useI18n();
-
-// Get the department from the route
-
-
-
-const module_config = ref([]);
-
-
-
-const getModuleConfig = async () => {
- await SessionUser.superUser.modules.stripe.config.get_all().then((response) => {
- let tmp_module_config = response.data.data;
- let tmp_module_config_array = [];
- for (const value of Object.values(tmp_module_config)) {
- console.log(`${value.variable}: ${value.value}`);
- tmp_module_config_array.push({
- variable: value.variable,
- value: value.value,
- });
- }
- module_config.value = tmp_module_config_array;
- console.log(module_config.value);
- }).catch((error) => {
- console.log(error);
- });
-};
-
-const getModuleConfigValue = (variable) => {
- const config = module_config.value.find((config) => config.variable === variable);
- // Log to the console, what the value was found
- if (config) {
- console.log(`Found value for ${variable}: ${config.value}`);
- } else {
- console.log(`No value found for ${variable}`);
- }
- return config ? config.value : '';
-};
-
-const load = async () => {
- await getModuleConfig();
-};
-
-load();
+const { module_config, getModuleConfigValue } = useModuleConfig("stripe");
const showGetCustomers = async () => {
- await SessionUser.superUser.modules.stripe.functions.customers.list().then((response) => {
- console.log('Stripe customers: ', response.data.data);
- Swal.fire({
- title: t('configuration.stripe.customers'),
- html: '' + JSON.stringify(response.data.data, null, 2) + '
',
- showCloseButton: true,
- showCancelButton: false,
- focusConfirm: false,
+ await SessionUser.superUser.modules.stripe.functions.customers
+ .list()
+ .then((response) => {
+ console.log("Stripe customers: ", response.data.data);
+ Swal.fire({
+ title: t("configuration.stripe.customers"),
+ html: "" + JSON.stringify(response.data.data, null, 2) + "
",
+ showCloseButton: true,
+ showCancelButton: false,
+ focusConfirm: false,
+ });
+ })
+ .catch((error) => {
+ console.log(error);
});
- }).catch((error) => {
- console.log(error);
- });
};
const showGetProducts = async () => {
- await SessionUser.superUser.modules.stripe.functions.products.list().then((response) => {
- console.log('Stripe products: ', response.data.data);
- Swal.fire({
- title: t('configuration.stripe.products'),
- html: '' + JSON.stringify(response.data.data, null, 2) + '
',
- showCloseButton: true,
- showCancelButton: false,
- focusConfirm: false,
+ await SessionUser.superUser.modules.stripe.functions.products
+ .list()
+ .then((response) => {
+ console.log("Stripe products: ", response.data.data);
+ Swal.fire({
+ title: t("configuration.stripe.products"),
+ html: "" + JSON.stringify(response.data.data, null, 2) + "
",
+ showCloseButton: true,
+ showCancelButton: false,
+ focusConfirm: false,
+ });
+ })
+ .catch((error) => {
+ console.log(error);
});
- }).catch((error) => {
- console.log(error);
- });
};
const showGetPrices = async () => {
- await SessionUser.superUser.modules.stripe.functions.prices.list().then((response) => {
- console.log('Stripe prices: ', response.data.data);
- Swal.fire({
- title: t('configuration.stripe.prices'),
- html: '' + JSON.stringify(response.data.data, null, 2) + '
',
- showCloseButton: true,
- showCancelButton: false,
- focusConfirm: false,
+ await SessionUser.superUser.modules.stripe.functions.prices
+ .list()
+ .then((response) => {
+ console.log("Stripe prices: ", response.data.data);
+ Swal.fire({
+ title: t("configuration.stripe.prices"),
+ html: "" + JSON.stringify(response.data.data, null, 2) + "
",
+ showCloseButton: true,
+ showCancelButton: false,
+ focusConfirm: false,
+ });
+ })
+ .catch((error) => {
+ console.log(error);
});
- }).catch((error) => {
- console.log(error);
- });
};
@@ -120,15 +86,15 @@ const showGetPrices = async () => {
:description="$t('configuration.stripe.general_settings_desc')"
icon="fas fa-cogs"
>
-
+
{
- {{ $t('configuration.stripe.get_customers') }}
+ {{ $t("configuration.stripe.get_customers") }}