diff --git a/.github/workflows/deploy_to_ecs_prod.yml b/.github/workflows/deploy_to_ecs_prod.yml
index ef050ff76..85c6dae04 100644
--- a/.github/workflows/deploy_to_ecs_prod.yml
+++ b/.github/workflows/deploy_to_ecs_prod.yml
@@ -53,6 +53,7 @@ jobs:
VUE_APP_MIXPANEL_PROJECT_TOKEN: ${{ secrets.VUE_APP_MIXPANEL_PROJECT_TOKEN }}
VUE_APP_SENTRY_DSN: ${{ secrets.VUE_APP_SENTRY_DSN }}
VUE_APP_GOOGLE_API_KEY: ${{ secrets.VUE_APP_GOOGLE_API_KEY }}
+ NODE_OPTIONS: --openssl-legacy-provider
run: |
# Build a docker container and push it to ECR
docker build \
diff --git a/Dockerfile b/Dockerfile
index 44de8f7f2..45f3d19dc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,6 @@
# base stage
-FROM node:lts-alpine as base-stage
+# FROM node:lts-alpine as base-stage
+FROM node:16-alpine as base-stage
WORKDIR /app
COPY package.json ./
# install dependencies for npm run test:unit
diff --git a/src/App.vue b/src/App.vue
index 8462d2aa6..b7be5acff 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -173,7 +173,17 @@
this.createSession())
.then(() => this.logData());
diff --git a/src/services/Config/GlobalDefaultSettings.js b/src/services/Config/GlobalDefaultSettings.js
index c65493166..6a31ee0a8 100644
--- a/src/services/Config/GlobalDefaultSettings.js
+++ b/src/services/Config/GlobalDefaultSettings.js
@@ -16,6 +16,11 @@ export let settingsMetadata = {
description: "settings.menu.description.skipEnabled",
type: "checkbox",
},
+ firstTimeLanguagePickerPopup: {
+ title: "settings.menu.title.firstTimeLanguagePickerPopup",
+ description: "settings.menu.description.firstTimeLanguagePickerPopup",
+ type: "checkbox",
+ },
};
/**
@@ -51,6 +56,17 @@ let globalDefaultSetings = new Map(
})
),
},
+ ui: {
+ scope: ["org-admin", "super-admin"],
+ children: new Map(
+ Object.entries({
+ firstTimeLanguagePickerPopup: {
+ scope: ["org-admin", "super-admin"],
+ value: true,
+ },
+ })
+ ),
+ },
})
),
},
diff --git a/src/services/Config/User.js b/src/services/Config/User.js
index cdd831b23..6cffb0a24 100644
--- a/src/services/Config/User.js
+++ b/src/services/Config/User.js
@@ -22,7 +22,7 @@ export default {
userConfig["locale"] || process.env.VUE_APP_I18N_LOCALE;
clearInterval(redirectId);
}
- }, 10);
+ }, 50);
},
updateLocale() {
diff --git a/src/services/Functional/Utilities/Settings.js b/src/services/Functional/Utilities/Settings.js
index 7aa0f51b0..a3bcc60d1 100644
--- a/src/services/Functional/Utilities/Settings.js
+++ b/src/services/Functional/Utilities/Settings.js
@@ -50,23 +50,47 @@ export default {
},
/**
- * checks if the provided object is a valid settings object
+ * checks if the provided object is a valid settings object and patches it if it is not
* @param {Object} config - the object that needs to be checked for validity
- * @param {Array} keysToCheck - these keys should exist for the object to be valid
- * @returns {Boolean} - if the given config object contains valid settings
+ * @returns {Array} - returns a boolean indicating if the object is valid and a Map object, null otherwise
*/
- hasValidSettings(config, keysToCheck = ["player"]) {
+ patchInvalidIncompleteSettings(config) {
// settings key should be present inside config object
if (config == null || !("settings" in config) || config.settings == null)
- return false;
+ // return [false, null];
+ return [true, clonedeep(globalDefaultSettings)]
// decoded settings object should be an instance of Map
let decodedSettings = this.decodeMapFromPayload(clonedeep(config.settings));
- if (!(decodedSettings instanceof Map)) return false;
+ if (!(decodedSettings instanceof Map)) return [
+ true,
+ clonedeep(globalDefaultSettings)
+ ];
// certain keys should be present in the settings Map
- for (const key of keysToCheck) if (!decodedSettings.has(key)) return false;
- return true;
+
+ const defaultSettings = clonedeep(globalDefaultSettings)
+ for (let [headerName, headerDetails] of defaultSettings) {
+ if (!decodedSettings.has(headerName)) {
+ decodedSettings.set(headerName, headerDetails)
+ continue
+ }
+
+ for (let [tabName, tabDetails] of headerDetails.children) {
+ if (!decodedSettings.get(headerName).children.has(tabName)) {
+ decodedSettings.get(headerName).children.set(tabName, tabDetails)
+ continue
+ }
+
+ for (let [leafName, leafDetails] of tabDetails.children) {
+ if (!decodedSettings.get(headerName).children.get(tabName).children.has(leafName)) {
+ decodedSettings.get(headerName).children.get(tabName).children.set(leafName, leafDetails)
+ }
+ }
+ }
+ }
+
+ return [true, decodedSettings]
},
/**
@@ -75,21 +99,9 @@ export default {
* @param {Object} config - Config of a plio
*/
setPlioSettings(config) {
- let plioSettings = new Map();
- if (!this.hasValidSettings(config)) {
- // if the provided config is not valid, set plio's settings using the global defaults
- plioSettings.set(
- "player",
- clonedeep(globalDefaultSettings.get("player"))
- );
- } else {
- // if the provided config is valid, use it to set plio's settings
- plioSettings.set(
- "player",
- this.decodeMapFromPayload(clonedeep(config.settings)).get("player")
- );
- }
- return plioSettings;
+ const result = this.patchInvalidIncompleteSettings(config)
+ if (result[0] == true) return result[1]
+ return null
},
/**
diff --git a/src/store/modules/auth.js b/src/store/modules/auth.js
index bcd456aee..9474335ee 100644
--- a/src/store/modules/auth.js
+++ b/src/store/modules/auth.js
@@ -138,12 +138,21 @@ const actions = {
state.accessToken.access_token
);
if (response != undefined) {
- // use the config of a user if it exists otherwise use the global defaults
- if ("settings" in response.data.config)
- dispatch(
- "setUserSettings",
- SettingsUtilities.decodeMapFromPayload(response.data.config.settings)
- );
+ // use the config of a user (and patch for completeness) if it exists otherwise use the global defaults
+ if ("settings" in response.data.config) {
+ const result = SettingsUtilities.patchInvalidIncompleteSettings(response.data.config)
+ if (result[1] !== null) {
+ dispatch(
+ "setUserSettings",
+ result[1]
+ );
+ } else {
+ dispatch(
+ "setUserSettings",
+ SettingsUtilities.decodeMapFromPayload(response.data.config.settings)
+ );
+ }
+ }
else dispatch("setUserSettings", clonedeep(globalDefaultSettings));
// use the config of organization(s) if it exists otherwise use the global defaults
@@ -240,31 +249,40 @@ export default {
function getWorkspaceSettings(workspaceDetails = null) {
if (
workspaceDetails == null ||
- !("config" in workspaceDetails) ||
- !SettingsUtilities.hasValidSettings(workspaceDetails.config)
+ !("config" in workspaceDetails)
) {
- let workspaceSettings = clonedeep(globalDefaultSettings);
- for (let [headerName, headerDetails] of workspaceSettings) {
- if (!SettingsUtilities.isSettingApplicableToWorkspace(headerDetails)) {
- workspaceSettings.delete(headerName);
- continue;
- }
- for (let [tabName, tabDetails] of headerDetails.children) {
- if (!SettingsUtilities.isSettingApplicableToWorkspace(tabDetails)) {
- headerDetails.children.delete(tabName);
+ const result = SettingsUtilities.patchInvalidIncompleteSettings(workspaceDetails.config)
+ if (result[0] == true) {
+ let workspaceSettings = result[1]
+ for (let [headerName, headerDetails] of workspaceSettings) {
+ if (!SettingsUtilities.isSettingApplicableToWorkspace(headerDetails)) {
+ workspaceSettings.delete(headerName);
continue;
}
- for (let [leafName, leafDetails] of tabDetails.children) {
- if (!SettingsUtilities.isSettingApplicableToWorkspace(leafDetails)) {
- tabDetails.children.delete(leafName);
+ for (let [tabName, tabDetails] of headerDetails.children) {
+ if (!SettingsUtilities.isSettingApplicableToWorkspace(tabDetails)) {
+ headerDetails.children.delete(tabName);
continue;
}
+ for (let [leafName, leafDetails] of tabDetails.children) {
+ if (!SettingsUtilities.isSettingApplicableToWorkspace(leafDetails)) {
+ tabDetails.children.delete(leafName);
+ continue;
+ }
+ }
}
}
+
+ return workspaceSettings;
}
- return workspaceSettings;
}
- return SettingsUtilities.decodeMapFromPayload(
- workspaceDetails.config.settings
- );
+
+ const result = SettingsUtilities.patchInvalidIncompleteSettings(workspaceDetails.config)
+ if (result[1] !== null) {
+ return result[1];
+ } else {
+ return SettingsUtilities.decodeMapFromPayload(
+ workspaceDetails.config.settings
+ );
+ }
}
diff --git a/src/store/modules/generic.js b/src/store/modules/generic.js
index 6368aa53e..23a4b85e6 100644
--- a/src/store/modules/generic.js
+++ b/src/store/modules/generic.js
@@ -1,4 +1,5 @@
const state = {
+ isFirstTimeLanguagePickerShownBySetting: null,
isSharePlioDialogShown: false,
isEmbedPlioDialogShown: false, // whether to show the dialog with info on embedding plio
plioLinkToShare: null,
@@ -22,6 +23,9 @@ const getters = {
isTabScreen: (state) => {
return state.windowInnerWidth < 640;
},
+ isFirstTimeLanguagePickerShownBySetting: (state) => {
+ return state.isFirstTimeLanguagePickerShownBySetting;
+ },
};
const actions = {
showSharePlioDialog({ commit, dispatch }, plioLink) {
@@ -59,6 +63,12 @@ const actions = {
hideSpinner({ commit }) {
commit("hideSpinner");
},
+ setFirstTimeLanguagePickerShownBySetting({ commit }) {
+ commit("setFirstTimeLanguagePickerShownBySetting");
+ },
+ unsetFirstTimeLanguagePickerShownBySetting({ commit }) {
+ commit("unsetFirstTimeLanguagePickerShownBySetting");
+ },
};
const mutations = {
@@ -92,6 +102,12 @@ const mutations = {
hideSpinner(state) {
state.isSpinnerShown = false;
},
+ setFirstTimeLanguagePickerShownBySetting(state) {
+ state.isFirstTimeLanguagePickerShownBySetting = true;
+ },
+ unsetFirstTimeLanguagePickerShownBySetting(state) {
+ state.isFirstTimeLanguagePickerShownBySetting = false;
+ },
};
export default {