web/satellite: use frontend config in Vue components

References to the meta tag config values in Vue components have been
modified to instead refer to the frontend config fetched through the
satellite API.

References #5494

Change-Id: I00ecf81d4a0ba6bd07c827cecb2c689d923d67c0
This commit is contained in:
Jeremy Wharton 2023-04-05 10:56:06 -05:00 committed by Storj Robot
parent 34e6c5048b
commit d62dd0b8e7
41 changed files with 262 additions and 213 deletions

View File

@ -251,7 +251,8 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
server.withAuth(http.HandlerFunc(projectsController.GetSalt)),
).Methods(http.MethodGet)
router.HandleFunc("/config", server.frontendConfigHandler)
router.HandleFunc("/api/v0/config", server.frontendConfigHandler)
router.HandleFunc("/registrationToken/", server.createRegistrationTokenHandler)
router.HandleFunc("/robots.txt", server.seoHandler)

View File

@ -71,8 +71,7 @@ onMounted(async (): Promise<void> => {
try {
await appStore.getConfig();
} catch (error) {
// TODO: Use a harsher error-handling approach when the config is necessary
// for the frontend to function.
appStore.setErrorPage(500, true);
notify.error(error.message, null);
}

View File

@ -9,7 +9,7 @@ import { FrontendConfig, FrontendConfigApi } from '@/types/config';
*/
export class FrontendConfigHttpApi implements FrontendConfigApi {
private readonly http: HttpClient = new HttpClient();
private readonly ROOT_PATH: string = '/config';
private readonly ROOT_PATH: string = '/api/v0/config';
/**
* Returns the frontend config.

View File

@ -124,10 +124,10 @@ import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/ana
import { LocalData } from '@/utils/localData';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { OBJECTS_MUTATIONS } from '@/store/modules/objects';
import { useAccessGrantsStore } from '@/store/modules/accessGrantsStore';
import { useAppStore } from '@/store/modules/appStore';
import VModal from '@/components/common/VModal.vue';
import CreateNewAccessStep from '@/components/accessGrants/createFlow/steps/CreateNewAccessStep.vue';
@ -146,6 +146,7 @@ const route = useRoute();
const notify = useNotify();
const store = useStore();
const agStore = useAccessGrantsStore();
const appStore = useAppStore();
const initPermissions = [
Permission.Read,
@ -507,7 +508,7 @@ async function createAccessGrant(): Promise<void> {
}
// creates access credentials.
const satelliteNodeURL = MetaUtils.getMetaContent('satellite-nodeurl');
const satelliteNodeURL = appStore.state.config.satelliteNodeURL;
const salt = await store.dispatch(PROJECTS_ACTIONS.GET_SALT, store.getters.selectedProject.id);

View File

@ -68,14 +68,14 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { useNotify, useRouter, useStore } from '@/utils/hooks';
import { useNotify, useRouter } from '@/utils/hooks';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { Download } from '@/utils/download';
import { AnalyticsHttpApi } from '@/api/analytics';
import { RouteConfig } from '@/router';
import { MetaUtils } from '@/utils/meta';
import { useAppStore } from '@/store/modules/appStore';
import VButton from '@/components/common/VButton.vue';
import ButtonsContainer from '@/components/accessGrants/createFlow/components/ButtonsContainer.vue';
@ -87,7 +87,7 @@ const props = defineProps<{
apiKey: string;
}>();
const store = useStore();
const appStore = useAppStore();
const notify = useNotify();
const router = useRouter();
@ -95,13 +95,19 @@ const isCopied = ref<boolean>(false);
const isDownloaded = ref<boolean>(false);
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const satelliteAddress = MetaUtils.getMetaContent('satellite-nodeurl');
/**
* Returns the web address of this satellite from the store.
*/
const satelliteAddress = computed((): string => {
return appStore.state.config.satelliteNodeURL;
});
/**
* Saves CLI access to clipboard.
*/
function onCopy(): void {
navigator.clipboard.writeText(`${satelliteAddress} ${props.apiKey}`);
navigator.clipboard.writeText(`${satelliteAddress.value} ${props.apiKey}`);
isCopied.value = true;
analytics.eventTriggered(AnalyticsEvent.COPY_TO_CLIPBOARD_CLICKED);
notify.success(`CLI access was copied successfully`);
@ -113,7 +119,7 @@ function onCopy(): void {
function onDownload(): void {
isDownloaded.value = true;
const fileContent = `Satellite address:\n${satelliteAddress}\n\nAPI Key:\n${props.apiKey}`;
const fileContent = `Satellite address:\n${satelliteAddress.value}\n\nAPI Key:\n${props.apiKey}`;
Download.file(fileContent, `Storj-CLI-access-${props.name}-${new Date().toISOString()}.txt`);
analytics.eventTriggered(AnalyticsEvent.DOWNLOAD_TXT_CLICKED);
}

View File

@ -100,7 +100,7 @@ const isActive = computed((): boolean => {
* Returns the whether applying a new coupon is enabled.
*/
const couponCodeBillingUIEnabled = computed((): boolean => {
return appStore.state.couponCodeBillingUIEnabled;
return appStore.state.config.couponCodeBillingUIEnabled;
});
/**

View File

@ -186,12 +186,12 @@ import {
NativePaymentHistoryItem,
} from '@/types/payments';
import { RouteConfig } from '@/router';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { useNotify, useRouter, useStore } from '@/utils/hooks';
import { useUsersStore } from '@/store/modules/usersStore';
import { useBillingStore } from '@/store/modules/billingStore';
import { useAppStore } from '@/store/modules/appStore';
import VButton from '@/components/common/VButton.vue';
import VLoader from '@/components/common/VLoader.vue';
@ -225,6 +225,7 @@ interface CardEdited {
const billingStore = useBillingStore();
const usersStore = useUsersStore();
const appStore = useAppStore();
const store = useStore();
const notify = useNotify();
const nativeRouter = useRouter();
@ -233,7 +234,6 @@ const router = reactive(nativeRouter);
const emit = defineEmits(['toggleIsLoading', 'toggleIsLoaded', 'cancel']);
const PAGE_SIZE = 10;
const nativeTokenPaymentsEnabled = MetaUtils.getMetaContent('native-token-payments-enabled') === 'true';
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const showTransactions = ref<boolean>(false);
@ -247,13 +247,20 @@ const displayedHistory = ref<NativePaymentHistoryItem[]>([]);
const transactionCount = ref<number>(0);
const defaultCreditCardSelection = ref<string>('');
const cardBeingEdited = ref<CardEdited>({});
const stripeCardInput = ref<StripeCardInput & StripeForm>();
const stripeCardInput = ref<typeof StripeCardInput & StripeForm>();
const canvas = ref<HTMLCanvasElement>();
const pageCount = computed((): number => {
return Math.ceil(transactionCount.value / PAGE_SIZE);
});
/**
* Indicates whether native token payments are enabled.
*/
const nativeTokenPaymentsEnabled = computed((): boolean => {
return appStore.state.config.nativeTokenPaymentsEnabled;
});
/**
* Returns deposit history items.
*/

View File

@ -15,10 +15,10 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
import { MetaUtils } from '@/utils/meta';
import { LoadScript } from '@/utils/loadScript';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { useNotify } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
interface StripeResponse {
error: string
@ -30,6 +30,7 @@ interface StripeResponse {
}
}
const appStore = useAppStore();
const notify = useNotify();
const props = withDefaults(defineProps<{
@ -52,7 +53,7 @@ const stripe = ref<any>(); // eslint-disable-line @typescript-eslint/no-explicit
* Stripe initialization.
*/
async function initStripe(): Promise<void> {
const stripePublicKey = MetaUtils.getMetaContent('stripe-public-key');
const stripePublicKey = appStore.state.config.stripePublicKey;
stripe.value = window['Stripe'](stripePublicKey);
if (!stripe.value) {

View File

@ -37,10 +37,12 @@
<script setup lang="ts">
import { computed } from 'vue';
import { Validator } from '@/utils/validation';
import { useAppStore } from '@/store/modules/appStore';
import VectorIcon from '@/../static/images/register/StrengthVector.svg';
const appStore = useAppStore();
/**
* BarFillStyle class holds info for BarFillStyle entity.
*/
@ -84,20 +86,35 @@ const props = withDefaults(defineProps<{
isShown: false,
});
/**
* Returns the maximum password length from the store.
*/
const passMaxLength = computed((): number => {
return appStore.state.config.passwordMaximumLength;
});
/**
* Returns the minimum password length from the store.
*/
const passMinLength = computed((): number => {
return appStore.state.config.passwordMinimumLength;
});
const isPasswordLengthAcceptable = computed((): boolean => {
return Validator.password(props.passwordString);
return props.passwordString.length <= passMaxLength.value
&& props.passwordString.length >= passMinLength.value;
});
/**
* Returns password strength label depends on score.
*/
const passwordStrength = computed((): string => {
if (props.passwordString.length < Validator.PASS_MIN_LENGTH) {
return `Use ${Validator.PASS_MIN_LENGTH} or more characters`;
if (props.passwordString.length < passMinLength.value) {
return `Use ${passMinLength.value} or more characters`;
}
if (props.passwordString.length > Validator.PASS_MAX_LENGTH) {
return `Use ${Validator.PASS_MAX_LENGTH} or fewer characters`;
if (props.passwordString.length > passMaxLength.value) {
return `Use ${passMaxLength.value} or fewer characters`;
}
const score = scorePassword();

View File

@ -4,10 +4,10 @@
<template>
<div class="beta-banner">
<p class="beta-banner__message">
Thanks for testing the {{ satelliteName }} Beta satellite | Data may be deleted during this beta | Submit testing feedback
<a class="beta-banner__message__link" :href="betaFeedbackURL" target="_blank" rel="noopener noreferrer">here</a>
Thanks for testing the {{ config.satelliteName }} Beta satellite | Data may be deleted during this beta | Submit testing feedback
<a class="beta-banner__message__link" :href="config.betaSatelliteFeedbackURL" target="_blank" rel="noopener noreferrer">here</a>
| Request support
<a class="beta-banner__message__link" :href="betaSupportURL" target="_blank" rel="noopener noreferrer">here</a>
<a class="beta-banner__message__link" :href="config.betaSatelliteSupportURL" target="_blank" rel="noopener noreferrer">here</a>
</p>
</div>
</template>
@ -15,27 +15,16 @@
<script setup lang="ts">
import { computed } from 'vue';
import { MetaUtils } from '@/utils/meta';
import { useAppStore } from '@/store/modules/appStore';
import { FrontendConfig } from '@/types/config';
const appStore = useAppStore();
/**
* Returns satellite name from store (config).
* Returns the frontend config.
*/
const satelliteName = computed((): string => {
return MetaUtils.getMetaContent('satellite-name');
});
/**
* Returns feedback URL from config for beta satellites.
*/
const betaFeedbackURL = computed((): string => {
return MetaUtils.getMetaContent('beta-satellite-feedback-url');
});
/**
* Returns support URL from config for beta satellites.
*/
const betaSupportURL = computed((): string => {
return MetaUtils.getMetaContent('beta-satellite-support-url');
const config = computed((): FrontendConfig => {
return appStore.state.config;
});
</script>

View File

@ -29,13 +29,14 @@
import { computed, onMounted, ref } from 'vue';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { useNotify, useStore } from '@/utils/hooks';
import { useUsersStore } from '@/store/modules/usersStore';
import { useAppStore } from '@/store/modules/appStore';
import VLoader from '@/components/common/VLoader.vue';
const appStore = useAppStore();
const usersStore = useUsersStore();
const store = useStore();
const notify = useNotify();
@ -63,7 +64,7 @@ const projectLimit = computed((): number => {
* Returns project limits increase request url from config.
*/
const projectLimitsIncreaseRequestURL = computed((): string => {
return MetaUtils.getMetaContent('project-limits-increase-request-url');
return appStore.state.config.projectLimitsIncreaseRequestURL;
});
/**

View File

@ -133,7 +133,6 @@ import { computed, onMounted, onBeforeMount, ref, reactive } from 'vue';
import { useNotify, useRouter, useStore } from '@/utils/hooks';
import { RouteConfig } from '@/router';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { MODALS } from '@/utils/constants/appStatePopUps';
@ -171,7 +170,7 @@ const isAddCard = ref<boolean>(true);
const isLoading = ref<boolean>(false);
const isPriceFetching = ref<boolean>(true);
const stripeCardInput = ref<StripeCardInput & StripeForm | null>(null);
const stripeCardInput = ref<typeof StripeCardInput & StripeForm | null>(null);
const extraBandwidthPriceInfo = ref<string>('');
@ -255,7 +254,7 @@ function setIsAddCard(): void {
* Returns project limits increase request url from config.
*/
const limitsIncreaseRequestURL = computed((): string => {
return MetaUtils.getMetaContent('project-limits-increase-request-url');
return appStore.state.config.projectLimitsIncreaseRequestURL;
});
/**

View File

@ -65,7 +65,6 @@
import { ref } from 'vue';
import { AuthHttpApi } from '@/api/auth';
import { Validator } from '@/utils/validation';
import { RouteConfig } from '@/router';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
@ -144,8 +143,15 @@ async function onUpdateClick(): Promise<void> {
hasError = true;
}
if (!Validator.password(newPassword.value)) {
newPasswordError.value = 'Invalid password. Use 6 or more characters';
const config = appStore.state.config;
if (newPassword.value.length < config.passwordMinimumLength) {
newPasswordError.value = `Invalid password. Use ${config.passwordMinimumLength} or more characters`;
hasError = true;
}
if (newPassword.value.length > config.passwordMaximumLength) {
newPasswordError.value = `Invalid password. Use ${config.passwordMaximumLength} or fewer characters`;
hasError = true;
}
@ -155,7 +161,7 @@ async function onUpdateClick(): Promise<void> {
}
if (newPassword.value !== confirmationPassword.value) {
confirmationPasswordError.value = 'Password not match to new one';
confirmationPasswordError.value = 'Password doesn\'t match new one';
hasError = true;
}

View File

@ -61,7 +61,6 @@ import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { Validator } from '@/utils/validation';
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { MetaUtils } from '@/utils/meta';
import { LocalData } from '@/utils/localData';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { useAppStore } from '@/store/modules/appStore';
@ -225,7 +224,7 @@ async function onCreate(): Promise<void> {
}
const salt = await store.dispatch(PROJECTS_ACTIONS.GET_SALT, store.getters.selectedProject.id);
const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl');
const satelliteNodeURL: string = appStore.state.config.satelliteNodeURL;
worker.value.postMessage({
'type': 'GenerateAccess',

View File

@ -36,7 +36,6 @@ import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/ana
import { AnalyticsHttpApi } from '@/api/analytics';
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { MetaUtils } from '@/utils/meta';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { useNotify, useStore } from '@/utils/hooks';
@ -113,7 +112,7 @@ async function onDelete(): Promise<void> {
}
const salt = await store.dispatch(PROJECTS_ACTIONS.GET_SALT, store.getters.selectedProject.id);
const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl');
const satelliteNodeURL: string = appStore.state.config.satelliteNodeURL;
worker.value.postMessage({
'type': 'GenerateAccess',

View File

@ -109,7 +109,7 @@ const canvas = ref<HTMLCanvasElement>();
* Returns satellite name from store.
*/
const satellite = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**

View File

@ -174,7 +174,7 @@ async function onCreateProjectClick(): Promise<void> {
store.commit(OBJECTS_MUTATIONS.CLEAR);
if (usersStore.shouldOnboard && appStore.state.isAllProjectsDashboard) {
if (usersStore.shouldOnboard && appStore.state.config.allProjectsDashboard) {
analytics.pageVisit(RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path);
await router.push(RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path);
return;

View File

@ -108,7 +108,7 @@ const notify = useNotify();
const isLoading = ref<boolean>(false);
const isSuccess = ref<boolean>(false);
const stripeCardInput = ref<(StripeCardInput & StripeForm) | null>(null);
const stripeCardInput = ref<(typeof StripeCardInput & StripeForm) | null>(null);
/**
* Returns the pricing plan selected from the onboarding tour.
@ -137,7 +137,7 @@ const isFree = computed((): boolean => {
function onClose(): void {
appStore.removeActiveModal();
if (isSuccess.value) {
if (appStore.state.isAllProjectsDashboard) {
if (appStore.state.config.allProjectsDashboard) {
router.push(RouteConfig.AllProjectsDashboard.path);
return;
}

View File

@ -43,7 +43,6 @@
import { computed, onMounted, ref } from 'vue';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { MetaUtils } from '@/utils/meta';
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { MODALS } from '@/utils/constants/appStatePopUps';
@ -115,7 +114,7 @@ async function setShareLink(): Promise<void> {
const LINK_SHARING_AG_NAME = `${path}_shared-bucket_${now.toISOString()}`;
const cleanAPIKey: AccessGrant = await agStore.createAccessGrant(LINK_SHARING_AG_NAME, store.getters.selectedProject.id);
const satelliteNodeURL = MetaUtils.getMetaContent('satellite-nodeurl');
const satelliteNodeURL = appStore.state.config.satelliteNodeURL;
const salt = await store.dispatch(PROJECTS_ACTIONS.GET_SALT, store.getters.selectedProject.id);
worker.value.postMessage({
@ -162,7 +161,7 @@ async function setShareLink(): Promise<void> {
path = encodeURIComponent(path.trim());
const linksharingURL = MetaUtils.getMetaContent('linksharing-url');
const linksharingURL = appStore.state.config.linksharingURL;
link.value = `${linksharingURL}/${credentials.accessKeyId}/${path}`;
} catch (error) {

View File

@ -114,7 +114,7 @@ const isDropdown = computed((): boolean => {
* Returns satellite name from store.
*/
const satellite = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**

View File

@ -173,7 +173,6 @@ import { User } from '@/types/users';
import { NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { LocalData } from '@/utils/localData';
import { MetaUtils } from '@/utils/meta';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { useNotify, useRouter, useStore } from '@/utils/hooks';
import { useABTestingStore } from '@/store/modules/abTestingStore';
@ -243,7 +242,7 @@ const isLoading = ref<boolean>(false);
* Indicates if all projects dashboard should be used.
*/
const isAllProjectsDashboard = computed((): boolean => {
return appStore.state.isAllProjectsDashboard;
return appStore.state.config.allProjectsDashboard;
});
/**
@ -271,7 +270,7 @@ const selectedProject = computed((): Project => {
* Returns satellite name from store.
*/
const satellite = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**
@ -442,7 +441,7 @@ function navigateToBilling(): void {
if (router.currentRoute.path.includes(RouteConfig.Billing.path)) return;
let link = RouteConfig.Account.with(RouteConfig.Billing);
if (MetaUtils.getMetaContent('new-billing-screen') === 'true') {
if (appStore.state.config.newBillingScreen) {
link = link.with(RouteConfig.BillingOverview);
}
router.push(link.path);

View File

@ -145,7 +145,7 @@ const isQuickStartDropdownShown = computed((): boolean => {
* Indicates if all projects dashboard should be used.
*/
const isAllProjectsDashboard = computed((): boolean => {
return appStore.state.isAllProjectsDashboard;
return appStore.state.config.allProjectsDashboard;
});
/**

View File

@ -11,11 +11,11 @@
<p class="notification-wrap__content-area__message">{{ notification.message }}</p>
<a
v-if="isSupportLinkMentioned"
:href="requestUrl"
:href="requestURL"
class="notification-wrap__content-area__link"
target="_blank"
>
{{ requestUrl }}
{{ requestURL }}
</a>
</div>
</div>
@ -28,17 +28,17 @@
</template>
<script setup lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { computed, onMounted, ref } from 'vue';
import { DelayedNotification } from '@/types/DelayedNotification';
import { NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { MetaUtils } from '@/utils/meta';
import { useStore } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
import CloseIcon from '@/../static/images/notifications/close.svg';
const store = useStore();
const appStore = useAppStore();
const props = withDefaults(defineProps<{
notification: DelayedNotification;
@ -46,10 +46,15 @@ const props = withDefaults(defineProps<{
notification: () => new DelayedNotification(() => { return; }, '', ''),
});
const requestUrl = MetaUtils.getMetaContent('general-request-url');
const isClassActive = ref<boolean>(false);
/**
* Returns the URL for the general request page from the store.
*/
const requestURL = computed((): string => {
return appStore.state.config.generalRequestURL;
});
/**
* Indicates if support word is mentioned in message.
* Temporal solution, can be changed later.

View File

@ -24,13 +24,14 @@
<script setup lang="ts">
import { computed } from 'vue';
import { MetaUtils } from '@/utils/meta';
import { useStore } from '@/utils/hooks';
import { LocalData } from '@/utils/localData';
import { useUsersStore } from '@/store/modules/usersStore';
import { useAppStore } from '@/store/modules/appStore';
import VBanner from '@/components/common/VBanner.vue';
const appStore = useAppStore();
const usersStore = useUsersStore();
const store = useStore();
@ -53,7 +54,7 @@ const bannerTextData = computed((): { title: string, body: string } => {
});
const projectLimitsIncreaseRequestURL = computed((): string => {
return MetaUtils.getMetaContent('project-limits-increase-request-url');
return appStore.state.config.projectLimitsIncreaseRequestURL;
});
/**

View File

@ -11,11 +11,12 @@
import { onMounted } from 'vue';
import { RouteConfig } from '@/router';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { useRouter } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
const router = useRouter();
const appStore = useAppStore();
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
@ -24,8 +25,7 @@ const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
* Redirects if flow is disabled.
*/
onMounted(async (): Promise<void> => {
const isFileBrowserFlowDisabled = MetaUtils.getMetaContent('file-browser-flow-disabled');
if (isFileBrowserFlowDisabled === 'true') {
if (appStore.state.config.fileBrowserFlowDisabled) {
analytics.pageVisit(RouteConfig.ProjectDashboard.path);
await router.push(RouteConfig.ProjectDashboard.path);
}

View File

@ -19,7 +19,6 @@ import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { MetaUtils } from '@/utils/meta';
import { BucketPage } from '@/types/buckets';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
@ -39,7 +38,6 @@ const notify = useNotify();
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const worker = ref<Worker | null>(null);
const linksharingURL = ref<string>('');
/**
* Indicates if upload cancel popup is visible.
@ -83,6 +81,13 @@ const edgeCredentials = computed((): EdgeCredentials => {
return store.state.objectsModule.gatewayCredentials;
});
/**
* Returns linksharing URL from store.
*/
const linksharingURL = computed((): string => {
return appStore.state.config.linksharingURL;
});
/**
* Generates a URL for an object map.
*/
@ -146,7 +151,7 @@ async function generateCredentials(cleanApiKey: string, path: string, areEndless
throw new Error('Worker is not defined');
}
const satelliteNodeURL = MetaUtils.getMetaContent('satellite-nodeurl');
const satelliteNodeURL = appStore.state.config.satelliteNodeURL;
const salt = await store.dispatch(PROJECTS_ACTIONS.GET_SALT, store.getters.selectedProject.id);
worker.value.postMessage({
@ -207,8 +212,6 @@ async function generateCredentials(cleanApiKey: string, path: string, areEndless
* Initiates file browser.
*/
onBeforeMount(() => {
linksharingURL.value = MetaUtils.getMetaContent('linksharing-url');
setWorker();
store.commit('files/init', {

View File

@ -32,12 +32,11 @@ import { computed, onMounted, ref } from 'vue';
import { AnalyticsHttpApi } from '@/api/analytics';
import { RouteConfig } from '@/router';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { MetaUtils } from '@/utils/meta';
import { PartneredSatellite } from '@/types/common';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { useNotify, useRouter } from '@/utils/hooks';
import { useUsersStore } from '@/store/modules/usersStore';
import { useAppStore } from '@/store/modules/appStore';
import { PartneredSatellite } from '@/types/config';
import OverviewContainer from '@/components/onboardingTour/steps/common/OverviewContainer.vue';
@ -51,13 +50,6 @@ const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const titleLabel = ref<string>('');
/**
* Returns satellite name.
*/
const satelliteName = computed((): string => {
return appStore.state.satelliteName;
});
/**
* Skips onboarding flow.
*/
@ -106,22 +98,12 @@ onMounted(async (): Promise<void> => {
notify.error(error.message, AnalyticsErrorEventSource.ONBOARDING_OVERVIEW_STEP);
}
const partneredSatellites = MetaUtils.getMetaContent('partnered-satellites');
if (!partneredSatellites) {
titleLabel.value = 'OSP';
return;
}
const partneredSatellitesJSON = JSON.parse(partneredSatellites);
const isPartnered = partneredSatellitesJSON.find((el: PartneredSatellite) => {
return el.name === satelliteName.value;
const config = appStore.state.config;
const isPartnered = config.partneredSatellites.find((el: PartneredSatellite) => {
return el.name === config.satelliteName;
});
if (isPartnered) {
titleLabel.value = 'DCS';
return;
}
titleLabel.value = 'OSP';
titleLabel.value = isPartnered ? 'DCS' : 'OSP';
});
</script>

View File

@ -25,7 +25,6 @@ import { RouteConfig } from '@/router';
import { PricingPlanInfo, PricingPlanType } from '@/types/common';
import { User } from '@/types/users';
import { useNotify, useRouter } from '@/utils/hooks';
import { MetaUtils } from '@/utils/meta';
import { PaymentsHttpApi } from '@/api/payments';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { useUsersStore } from '@/store/modules/usersStore';
@ -75,11 +74,11 @@ const plans = ref<PricingPlanInfo[]>([
onBeforeMount(async () => {
const user: User = usersStore.state.user;
let nextPath = RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path;
if (appStore.state.isAllProjectsDashboard) {
if (appStore.state.config.allProjectsDashboard) {
nextPath = RouteConfig.AllProjectsDashboard.path;
}
const pricingPkgsEnabled = Boolean(MetaUtils.getMetaContent('pricing-packages-enabled'));
const pricingPkgsEnabled = appStore.state.config.pricingPackagesEnabled;
if (!pricingPkgsEnabled || user.paidTier || !user.partner) {
router.push(nextPath);
return;

View File

@ -24,7 +24,6 @@
import { computed, onMounted } from 'vue';
import { RouteConfig } from '@/router';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { useRouter } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
@ -37,9 +36,15 @@ import Icon from '@/../static/images/onboardingTour/apiKeyStep.svg';
const appStore = useAppStore();
const router = useRouter();
const satelliteAddress: string = MetaUtils.getMetaContent('satellite-nodeurl');
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Returns the web address of this satellite from the store.
*/
const satelliteAddress = computed((): string => {
return appStore.state.config.satelliteNodeURL;
});
/**
* Returns API key from store.
*/

View File

@ -209,16 +209,17 @@ import {
Project,
ProjectFields, ProjectLimits,
} from '@/types/projects';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { AnalyticsHttpApi } from '@/api/analytics';
import { useNotify, useRouter, useStore } from '@/utils/hooks';
import { useUsersStore } from '@/store/modules/usersStore';
import { useAppStore } from '@/store/modules/appStore';
import VButton from '@/components/common/VButton.vue';
const usersStore = useUsersStore();
const store = useStore();
const appStore = useAppStore();
const notify = useNotify();
const router = useRouter();
@ -325,23 +326,21 @@ const bandwidthMeasurementFormatted = computed((): string => {
* Gets current default limit for paid accounts.
*/
const paidBandwidthLimit = computed((): number => {
const limitVal = getLimitValue(MetaUtils.getMetaContent('default-paid-bandwidth-limit'));
const limitVal = getLimitValue(appStore.state.config.defaultPaidBandwidthLimit);
const maxLimit = Math.max(currentLimits.value.bandwidthLimit / Memory.TB, limitVal);
if (activeBandwidthMeasurement.value === Dimensions.GB) {
return toGB(maxLimit);
} else {
return maxLimit;
}
return maxLimit;
});
const paidStorageLimit = computed((): number => {
const limitVal = getLimitValue(MetaUtils.getMetaContent('default-paid-storage-limit'));
const limitVal = getLimitValue(appStore.state.config.defaultPaidStorageLimit);
const maxLimit = Math.max(currentLimits.value.storageLimit / Memory.TB, limitVal);
if (activeStorageMeasurement.value === Dimensions.GB) {
return toGB(maxLimit);
} else {
return maxLimit;
}
return maxLimit;
});
/**

View File

@ -386,7 +386,7 @@ onMounted(async (): Promise<void> => {
isServerSideEncryptionBannerHidden.value = LocalData.getServerSideEncryptionBannerHidden();
if (!store.getters.selectedProject.id) {
if (appStore.state.isAllProjectsDashboard) {
if (appStore.state.config.allProjectsDashboard) {
await router.push(RouteConfig.AllProjectsDashboard.path);
return;
}

View File

@ -61,8 +61,8 @@ import { onMounted, reactive, ref } from 'vue';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { Validator } from '@/utils/validation';
import { MetaUtils } from '@/utils/meta';
import { useNotify, useRouter } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
import RegistrationSuccess from '@/components/common/RegistrationSuccess.vue';
import VInput from '@/components/common/VInput.vue';
@ -73,6 +73,7 @@ import InfoIcon from '@/../static/images/notifications/info.svg';
import CloseIcon from '@/../static/images/notifications/closeSmall.svg';
const notify = useNotify();
const appStore = useAppStore();
const nativeRouter = useRouter();
const router = reactive(nativeRouter);
@ -122,7 +123,7 @@ function setEmail(value: string): void {
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
window.location.href = appStore.state.config.homepageURL;
}
onMounted((): void => {

View File

@ -110,7 +110,6 @@ import { FetchState } from '@/utils/constants/fetchStateEnum';
import { LocalData } from '@/utils/localData';
import { User } from '@/types/users';
import { AuthHttpApi } from '@/api/auth';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
@ -151,9 +150,6 @@ const auth: AuthHttpApi = new AuthHttpApi();
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const resetActivityEvents: string[] = ['keypress', 'mousemove', 'mousedown', 'touchmove'];
const inactivityModalTime = 60000;
const sessionDuration: number = parseInt(MetaUtils.getMetaContent('inactivity-timer-duration')) * 1000;
const sessionRefreshInterval: number = sessionDuration / 2;
const debugTimerShown = MetaUtils.getMetaContent('inactivity-timer-viewer-enabled') === 'true';
// Minimum number of recovery codes before the recovery code warning bar is shown.
const recoveryCodeWarningThreshold = 4;
@ -169,6 +165,27 @@ const debugTimerText = ref<string>('');
const dashboardContent = ref<HTMLElement | null>(null);
/**
* Returns the session duration from the store.
*/
const sessionDuration = computed((): number => {
return appStore.state.config.inactivityTimerDuration * 1000;
});
/**
* Returns the session refresh interval from the store.
*/
const sessionRefreshInterval = computed((): number => {
return sessionDuration.value / 2;
});
/**
* Indicates whether to display the session timer for debugging.
*/
const debugTimerShown = computed((): boolean => {
return appStore.state.config.inactivityTimerViewerEnabled;
});
/**
* Indicates if account was frozen due to billing issues.
*/
@ -260,7 +277,7 @@ const isNavigationHidden = computed((): boolean => {
/* whether all projects dashboard should be used */
const isAllProjectsDashboard = computed((): boolean => {
return appStore.state.isAllProjectsDashboard;
return appStore.state.config.allProjectsDashboard;
});
/* whether the project limit banner should be shown. */
@ -314,7 +331,7 @@ const isOnboardingTour = computed((): boolean => {
* Indicates if satellite is in beta.
*/
const isBetaSatellite = computed((): boolean => {
return appStore.state.isBetaSatellite;
return appStore.state.config.isBetaSatellite;
});
/**
@ -368,9 +385,7 @@ function clearSessionTimers(): void {
* Adds DOM event listeners and starts session timers.
*/
function setupSessionTimers(): void {
const isInactivityTimerEnabled = MetaUtils.getMetaContent('inactivity-timer-enabled');
if (isInactivityTimerEnabled === 'false') return;
if (!appStore.state.config.inactivityTimerEnabled) return;
const expiresAt = LocalData.getSessionExpirationDate();
@ -379,7 +394,7 @@ function setupSessionTimers(): void {
document.addEventListener(eventName, onSessionActivity, false);
});
if (expiresAt.getTime() - sessionDuration + sessionRefreshInterval < Date.now()) {
if (expiresAt.getTime() - sessionDuration.value + sessionRefreshInterval.value < Date.now()) {
refreshSession();
}
@ -396,7 +411,7 @@ function restartSessionTimers(): void {
if (isSessionActive.value) {
await refreshSession();
}
}, sessionRefreshInterval);
}, sessionRefreshInterval.value);
inactivityTimerId.value = setTimeout(async () => {
if (store.getters['files/uploadingLength']) {
@ -410,7 +425,7 @@ function restartSessionTimers(): void {
await handleInactive();
await notify.notify('Your session was timed out.');
}, inactivityModalTime);
}, sessionDuration - inactivityModalTime);
}, sessionDuration.value - inactivityModalTime);
if (!debugTimerShown) return;
@ -636,7 +651,7 @@ onMounted(async () => {
return;
}
if (!appStore.state.isAllProjectsDashboard) {
if (!appStore.state.config.allProjectsDashboard) {
try {
if (!projects.length) {
await store.dispatch(PROJECTS_ACTIONS.CREATE_DEFAULT_PROJECT, usersStore.state.user.id);
@ -644,7 +659,8 @@ onMounted(async () => {
selectProject(projects);
}
if (usersStore.shouldOnboard) {
const onboardingPath = RouteConfig.OnboardingTour.with(RouteConfig.FirstOnboardingStep).path;
const firstOnboardingStep = appStore.state.config.pricingPackagesEnabled ? RouteConfig.PricingPlanStep : RouteConfig.OverviewStep;
const onboardingPath = RouteConfig.OnboardingTour.with(firstOnboardingStep).path;
await analytics.pageVisit(onboardingPath);
await router.push(onboardingPath);

View File

@ -26,7 +26,6 @@ import { computed, onMounted } from 'vue';
import { useRouter } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
import { MetaUtils } from '@/utils/meta';
import VButton from '@/components/common/VButton.vue';
@ -65,7 +64,7 @@ const isFatal = computed((): boolean => {
* Navigates to the homepage.
*/
function goToHomepage(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
window.location.href = appStore.state.config.homepageURL || 'https://www.storj.io';
}
/**
@ -83,7 +82,7 @@ function onButtonClick(): void {
* Lifecycle hook after initial render. Sets page title.
*/
onMounted(() => {
const satName = appStore.state.satelliteName;
const satName = appStore.state.config.satelliteName;
document.title = statusCode.value.toString() + (satName ? ' | ' + satName : '');
});
</script>

View File

@ -56,18 +56,18 @@
/>
</div>
<VueRecaptcha
v-if="recaptchaEnabled"
v-if="captchaConfig.recaptcha.enabled"
ref="captcha"
:sitekey="recaptchaSiteKey"
:sitekey="captchaConfig.recaptcha.siteKey"
:load-recaptcha-script="true"
size="invisible"
@verify="onCaptchaVerified"
@error="onCaptchaError"
/>
<VueHcaptcha
v-else-if="hcaptchaEnabled"
v-else-if="captchaConfig.hcaptcha.enabled"
ref="captcha"
:sitekey="hcaptchaSiteKey"
:sitekey="captchaConfig.hcaptcha.siteKey"
:re-captcha-compat="false"
size="invisible"
@verify="onCaptchaVerified"
@ -101,12 +101,10 @@ import VueHcaptcha from '@hcaptcha/vue-hcaptcha';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { PartneredSatellite } from '@/types/common';
import { Validator } from '@/utils/validation';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { useNotify, useRouter } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
import { MultiCaptchaConfig, PartneredSatellite } from '@/types/config';
import VInput from '@/components/common/VInput.vue';
import VButton from '@/components/common/VButton.vue';
@ -122,12 +120,7 @@ const notify = useNotify();
const nativeRouter = useRouter();
const router = reactive(nativeRouter);
const recaptchaEnabled: boolean = MetaUtils.getMetaContent('login-recaptcha-enabled') === 'true';
const recaptchaSiteKey: string = MetaUtils.getMetaContent('login-recaptcha-site-key');
const hcaptchaEnabled: boolean = MetaUtils.getMetaContent('login-hcaptcha-enabled') === 'true';
const hcaptchaSiteKey: string = MetaUtils.getMetaContent('login-hcaptcha-site-key');
const auth: AuthHttpApi = new AuthHttpApi();
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const loginPath: string = RouteConfig.Login.path;
const email = ref<string>('');
@ -143,14 +136,21 @@ const captcha = ref<VueRecaptcha | VueHcaptcha>();
* Name of the current satellite.
*/
const satelliteName = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**
* Information about partnered satellites, including name and signup link.
*/
const partneredSatellites = computed((): PartneredSatellite[] => {
return appStore.state.partneredSatellites;
return appStore.state.config.partneredSatellites;
});
/**
* This component's captcha configuration.
*/
const captchaConfig = computed((): MultiCaptchaConfig => {
return appStore.state.config.captcha.login;
});
/**
@ -237,7 +237,7 @@ async function onSendConfigurations(): Promise<void> {
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
window.location.href = appStore.state.config.homepageURL;
}
/**

View File

@ -100,14 +100,14 @@
Or use recovery code
</span>
</template>
<div v-if="recaptchaEnabled" class="login-area__content-area__container__captcha-wrapper">
<div v-if="captchaConfig.recaptcha.enabled" class="login-area__content-area__container__captcha-wrapper">
<div v-if="captchaError" class="login-area__content-area__container__captcha-wrapper__label-container">
<ErrorIcon />
<p class="login-area__content-area__container__captcha-wrapper__label-container__error">reCAPTCHA is required</p>
</div>
<VueRecaptcha
ref="recaptcha"
:sitekey="recaptchaSiteKey"
:sitekey="captchaConfig.recaptcha.siteKey"
:load-recaptcha-script="true"
size="invisible"
@verify="onCaptchaVerified"
@ -115,14 +115,14 @@
@error="onCaptchaError"
/>
</div>
<div v-else-if="hcaptchaEnabled" class="login-area__content-area__container__captcha-wrapper">
<div v-else-if="captchaConfig.hcaptcha.enabled" class="login-area__content-area__container__captcha-wrapper">
<div v-if="captchaError" class="login-area__content-area__container__captcha-wrapper__label-container">
<ErrorIcon />
<p class="login-area__content-area__container__captcha-wrapper__label-container__error">HCaptcha is required</p>
</div>
<VueHcaptcha
ref="hcaptcha"
:sitekey="hcaptchaSiteKey"
:sitekey="captchaConfig.hcaptcha.siteKey"
:re-captcha-compat="false"
size="invisible"
@verify="onCaptchaVerified"
@ -170,14 +170,13 @@ import { FetchState } from '@/utils/constants/fetchStateEnum';
import { Validator } from '@/utils/validation';
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
import { ErrorBadRequest } from '@/api/errors/ErrorBadRequest';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { TokenInfo } from '@/types/users';
import { LocalData } from '@/utils/localData';
import { useNotify, useRoute, useRouter, useStore } from '@/utils/hooks';
import { PartneredSatellite } from '@/types/common';
import { useUsersStore } from '@/store/modules/usersStore';
import { useAppStore } from '@/store/modules/appStore';
import { MultiCaptchaConfig, PartneredSatellite } from '@/types/config';
import VButton from '@/components/common/VButton.vue';
import VInput from '@/components/common/VInput.vue';
@ -217,10 +216,6 @@ const recaptcha = ref<VueRecaptcha | null>(null);
const hcaptcha = ref<VueHcaptcha | null>(null);
const mfaInput = ref<ConfirmMFAInput & ClearInput | null>(null);
const recaptchaEnabled = MetaUtils.getMetaContent('login-recaptcha-enabled') === 'true';
const recaptchaSiteKey = MetaUtils.getMetaContent('login-recaptcha-site-key');
const hcaptchaEnabled = MetaUtils.getMetaContent('login-hcaptcha-enabled') === 'true';
const hcaptchaSiteKey = MetaUtils.getMetaContent('login-hcaptcha-site-key');
const forgotPasswordPath: string = RouteConfig.ForgotPassword.path;
const registerPath: string = RouteConfig.Register.path;
@ -231,21 +226,27 @@ const appStore = useAppStore();
const usersStore = useUsersStore();
const router = useRouter();
const notify = useNotify();
const store = useStore();
const route = useRoute();
/**
* Name of the current satellite.
*/
const satelliteName = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**
* Information about partnered satellites, including name and signup link.
*/
const partneredSatellites = computed((): PartneredSatellite[] => {
return appStore.state.partneredSatellites;
return appStore.state.config.partneredSatellites;
});
/**
* This component's captcha configuration.
*/
const captchaConfig = computed((): MultiCaptchaConfig => {
return appStore.state.config.captcha.login;
});
/**
@ -256,7 +257,7 @@ onMounted(() => {
isActivatedBannerShown.value = !!route.query.activated;
isActivatedError.value = route.query.activated === 'false';
if (appStore.state.isAllProjectsDashboard) {
if (appStore.state.config.allProjectsDashboard) {
returnURL.value = RouteConfig.AllProjectsDashboard.path;
}
@ -274,7 +275,7 @@ function clearConfirmMFAInput(): void {
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
const homepageURL = MetaUtils.getMetaContent('homepage-url');
const homepageURL = appStore.state.config.homepageURL;
if (homepageURL) window.location.href = homepageURL;
}
@ -464,7 +465,7 @@ function validateFields(): boolean {
isNoErrors = false;
}
if (password.value.length < Validator.PASS_MIN_LENGTH) {
if (password.value.length < appStore.state.config.passwordMinimumLength) {
passwordError.value = 'Invalid Password';
isNoErrors = false;
}

View File

@ -80,8 +80,6 @@ import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { AuthHttpApi } from '@/api/auth';
import { ErrorMFARequired } from '@/api/errors/ErrorMFARequired';
import { RouteConfig } from '@/router';
import { Validator } from '@/utils/validation';
import { MetaUtils } from '@/utils/meta';
import { AnalyticsHttpApi } from '@/api/analytics';
import { ErrorTokenExpired } from '@/api/errors/ErrorTokenExpired';
import { useNotify, useRouter } from '@/utils/hooks';
@ -171,8 +169,9 @@ async function onResetClick(): Promise<void> {
*/
function validateFields(): boolean {
let isNoErrors = true;
let config = appStore.state.config;
if (!Validator.password(password.value)) {
if (password.value.length < config.passwordMinimumLength || password.value.length > config.passwordMaximumLength) {
passwordError.value = 'Invalid password';
isNoErrors = false;
}
@ -203,7 +202,7 @@ function hidePasswordStrength(): void {
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
window.location.href = appStore.state.config.homepageURL;
}
/**

View File

@ -116,7 +116,6 @@ import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
import { MetaUtils } from '@/utils/meta';
import { FetchState } from '@/utils/constants/fetchStateEnum';
import { LocalData } from '@/utils/localData';
import { CouponType } from '@/types/coupons';
@ -155,9 +154,6 @@ const analytics = new AnalyticsHttpApi();
const auth: AuthHttpApi = new AuthHttpApi();
const inactivityModalTime = 60000;
const sessionDuration: number = parseInt(MetaUtils.getMetaContent('inactivity-timer-duration')) * 1000;
const sessionRefreshInterval: number = sessionDuration / 2;
const debugTimerShown = MetaUtils.getMetaContent('inactivity-timer-viewer-enabled') === 'true';
// Minimum number of recovery codes before the recovery code warning bar is shown.
const recoveryCodeWarningThreshold = 4;
@ -173,6 +169,27 @@ const isHundredLimitModalShown = ref<boolean>(false);
const isEightyLimitModalShown = ref<boolean>(false);
const dashboardContent = ref<HTMLElement | null>(null);
/**
* Returns the session duration from the store.
*/
const sessionDuration = computed((): number => {
return appStore.state.config.inactivityTimerDuration * 1000;
});
/**
* Returns the session refresh interval from the store.
*/
const sessionRefreshInterval = computed((): number => {
return sessionDuration.value / 2;
});
/**
* Indicates whether to display the session timer for debugging.
*/
const debugTimerShown = computed((): boolean => {
return appStore.state.config.inactivityTimerViewerEnabled;
});
/**
* Indicates if account was frozen due to billing issues.
*/
@ -265,7 +282,7 @@ const isBillingPage = computed(() => {
* Indicates if satellite is in beta.
*/
const isBetaSatellite = computed((): boolean => {
return appStore.state.isBetaSatellite;
return appStore.state.config.isBetaSatellite;
});
/**
@ -415,9 +432,7 @@ function clearSessionTimers(): void {
* Adds DOM event listeners and starts session timers.
*/
function setupSessionTimers(): void {
const isInactivityTimerEnabled = MetaUtils.getMetaContent('inactivity-timer-enabled');
if (isInactivityTimerEnabled === 'false') return;
if (!appStore.state.config.inactivityTimerEnabled) return;
const expiresAt = LocalData.getSessionExpirationDate();
@ -426,7 +441,7 @@ function setupSessionTimers(): void {
document.addEventListener(eventName, onSessionActivity, false);
});
if (expiresAt.getTime() - sessionDuration + sessionRefreshInterval < Date.now()) {
if (expiresAt.getTime() - sessionDuration.value + sessionRefreshInterval.value < Date.now()) {
refreshSession();
}
@ -443,7 +458,7 @@ function restartSessionTimers(): void {
if (isSessionActive.value) {
await refreshSession();
}
}, sessionRefreshInterval);
}, sessionRefreshInterval.value);
inactivityTimerId.value = setTimeout(async () => {
if (store.getters['files/uploadingLength']) {
@ -457,9 +472,9 @@ function restartSessionTimers(): void {
await handleInactive();
await notify.notify('Your session was timed out.');
}, inactivityModalTime);
}, sessionDuration - inactivityModalTime);
}, sessionDuration.value - inactivityModalTime);
if (!debugTimerShown) return;
if (!debugTimerShown.value) return;
const debugTimer = () => {
const expiresAt = LocalData.getSessionExpirationDate();

View File

@ -153,7 +153,7 @@ const isNavOpened = ref(false);
* Returns satellite name from store.
*/
const satellite = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**

View File

@ -106,7 +106,7 @@ const isDropdownOpen = computed((): boolean => {
* Returns satellite name from store.
*/
const satellite = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
function openDropdown(): void {

View File

@ -230,18 +230,18 @@
</label>
</div>
<VueRecaptcha
v-if="recaptchaEnabled"
v-if="captchaConfig.recaptcha.enabled"
ref="captcha"
:sitekey="recaptchaSiteKey"
:sitekey="captchaConfig.recaptcha.siteKey"
:load-recaptcha-script="true"
size="invisible"
@verify="onCaptchaVerified"
@error="onCaptchaError"
/>
<VueHcaptcha
v-else-if="hcaptchaEnabled"
v-else-if="captchaConfig.hcaptcha.enabled"
ref="captcha"
:sitekey="hcaptchaSiteKey"
:sitekey="captchaConfig.hcaptcha.siteKey"
:re-captcha-compat="false"
size="invisible"
@verify="onCaptchaVerified"
@ -290,11 +290,8 @@ import LogoWithPartnerIcon from '../../../static/images/partnerStorjLogo.svg';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { PartneredSatellite } from '@/types/common';
import { MultiCaptchaConfig, PartneredSatellite } from '@/types/config';
import { User } from '@/types/users';
import { MetaUtils } from '@/utils/meta';
import { Validator } from '@/utils/validation';
import { AnalyticsHttpApi } from '@/api/analytics';
import { useNotify, useRouter } from '@/utils/hooks';
import { useAppStore } from '@/store/modules/appStore';
@ -347,11 +344,6 @@ const haveSalesContact = ref(false);
const captchaError = ref(false);
const captchaResponseToken = ref('');
const recaptchaEnabled: boolean = MetaUtils.getMetaContent('registration-recaptcha-enabled') === 'true';
const recaptchaSiteKey: string = MetaUtils.getMetaContent('registration-recaptcha-site-key');
const hcaptchaEnabled: boolean = MetaUtils.getMetaContent('registration-hcaptcha-enabled') === 'true';
const hcaptchaSiteKey: string = MetaUtils.getMetaContent('registration-hcaptcha-site-key');
const isPasswordStrengthShown = ref(false);
// DCS logic
@ -364,7 +356,6 @@ const loginPath = RouteConfig.Login.path;
const captcha = ref<VueRecaptcha | VueHcaptcha | null>(null);
const analytics = new AnalyticsHttpApi();
const auth = new AuthHttpApi();
const appStore = useAppStore();
@ -456,7 +447,7 @@ async function onCreateClick(): Promise<void> {
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
window.location.href = appStore.state.config.homepageURL;
}
/**
@ -492,18 +483,26 @@ function setRepeatedPassword(value: string): void {
repeatedPasswordError.value = '';
}
/**
* This component's captcha configuration.
*/
const captchaConfig = computed((): MultiCaptchaConfig => {
return appStore.state.config.captcha.registration;
});
/**
* Name of the current satellite.
*/
const satelliteName = computed((): string => {
return appStore.state.satelliteName;
return appStore.state.config.satelliteName;
});
/**
* Information about partnered satellites, including name and signup link.
*/
const partneredSatellites = computed((): PartneredSatellite[] => {
const satellites = appStore.state.partneredSatellites;
const config = appStore.state.config;
const satellites = config.partneredSatellites.filter(sat => sat.name !== config.satelliteName);
return satellites.map((s: PartneredSatellite) => {
s.address = `${s.address}/signup`;
@ -519,14 +518,14 @@ const partneredSatellites = computed((): PartneredSatellite[] => {
* Indicates if satellite is in beta.
*/
const isBetaSatellite = computed((): boolean => {
return appStore.state.isBetaSatellite;
return appStore.state.config.isBetaSatellite;
});
/**
* Indicates if coupon code ui is enabled
*/
const couponCodeSignupUIEnabled = computed((): boolean => {
return appStore.state.couponCodeSignupUIEnabled;
return appStore.state.config.couponCodeSignupUIEnabled;
});
/**
@ -642,7 +641,9 @@ function validateFields(): boolean {
isNoErrors = false;
}
if (!Validator.password(password.value)) {
let config = appStore.state.config;
if (password.value.length < config.passwordMinimumLength || password.value.length > config.passwordMaximumLength) {
passwordError.value = 'Invalid Password';
isNoErrors = false;
}
@ -748,7 +749,7 @@ async function createUser(): Promise<void> {
// signups outside of the brave browser may use a configured URL to track conversions
// if the URL is not configured, the RegisterSuccess path will be used for non-Brave browsers
const internalRegisterSuccessPath = RouteConfig.RegisterSuccess.path;
const configuredRegisterSuccessPath = MetaUtils.getMetaContent('optional-signup-success-url') || internalRegisterSuccessPath;
const configuredRegisterSuccessPath = appStore.state.config.optionalSignupSuccessURL || internalRegisterSuccessPath;
const nonBraveSuccessPath = `${configuredRegisterSuccessPath}?email=${encodeURIComponent(user.value.email)}`;
const braveSuccessPath = `${internalRegisterSuccessPath}?email=${encodeURIComponent(user.value.email)}`;