Compare commits

..

5 Commits

Author SHA1 Message Date
jamesgeorge007
75e2199cb5 fix: pick the corresponding REST collections to export from personal/team workspace 2023-12-19 11:57:19 +05:30
jamesgeorge007
dacecf3c17 refactor: rely on platform implementation for opening external links 2023-12-19 11:42:08 +05:30
jamesgeorge007
ae57e7b5b5 refactor: organize imports 2023-12-19 11:35:48 +05:30
jamesgeorge007
e23bc2d864 refactor: eliminate redundancy 2023-12-19 11:35:48 +05:30
jamesgeorge007
2affb21d22 chore: Gist export flow updates 2023-12-19 11:35:48 +05:30
18 changed files with 38 additions and 237 deletions

View File

@@ -676,16 +676,9 @@ export const INFRA_CONFIG_RESET_FAILED = 'infra_config/reset_failed' as const;
*/ */
export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const; export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const;
/**
* Infra Config service (auth provider/mailer/audit logs) not configured
* (InfraConfigService)
*/
export const INFRA_CONFIG_SERVICE_NOT_CONFIGURED =
'infra_config/service_not_configured' as const;
/** /**
* Error message for when the database table does not exist * Error message for when the database table does not exist
* (InfraConfigService) * (InfraConfigService)
*/ */
export const DATABASE_TABLE_NOT_EXIST = export const DATABASE_TABLE_NOT_EXIST =
'Database migration not found. Please check the documentation for assistance: https://docs.hoppscotch.io/documentation/self-host/community-edition/install-and-build#running-migrations'; 'Database migration not performed. Please check the FAQ for assistance: https://docs.hoppscotch.io/support/getting-started/faq';

View File

@@ -15,13 +15,11 @@ import {
INFRA_CONFIG_NOT_LISTED, INFRA_CONFIG_NOT_LISTED,
INFRA_CONFIG_RESET_FAILED, INFRA_CONFIG_RESET_FAILED,
INFRA_CONFIG_UPDATE_FAILED, INFRA_CONFIG_UPDATE_FAILED,
INFRA_CONFIG_SERVICE_NOT_CONFIGURED,
} from 'src/errors'; } from 'src/errors';
import { throwErr, validateEmail, validateSMTPUrl } from 'src/utils'; import { throwErr, validateEmail, validateSMTPUrl } from 'src/utils';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { ServiceStatus, stopApp } from './helper'; import { ServiceStatus, stopApp } from './helper';
import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args'; import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args';
import { AuthProvider } from 'src/auth/helper';
@Injectable() @Injectable()
export class InfraConfigService implements OnModuleInit { export class InfraConfigService implements OnModuleInit {
@@ -126,7 +124,7 @@ export class InfraConfigService implements OnModuleInit {
cast(dbInfraConfig: DBInfraConfig) { cast(dbInfraConfig: DBInfraConfig) {
return <InfraConfig>{ return <InfraConfig>{
name: dbInfraConfig.name, name: dbInfraConfig.name,
value: dbInfraConfig.value ?? '', value: dbInfraConfig.value,
}; };
} }
@@ -184,38 +182,6 @@ export class InfraConfigService implements OnModuleInit {
} }
} }
/**
* Check if the service is configured or not
* @param service Service can be Auth Provider, Mailer, Audit Log etc.
* @returns Either true or false
*/
isServiceConfigured(service: AuthProvider) {
switch (service) {
case AuthProvider.GOOGLE:
return (
this.configService.get<string>('INFRA.GOOGLE_CLIENT_ID') &&
this.configService.get<string>('INFRA.GOOGLE_CLIENT_SECRET')
);
case AuthProvider.GITHUB:
return (
this.configService.get<string>('INFRA.GITHUB_CLIENT_ID') &&
!this.configService.get<string>('INFRA.GITHUB_CLIENT_SECRET')
);
case AuthProvider.MICROSOFT:
return (
this.configService.get<string>('INFRA.MICROSOFT_CLIENT_ID') &&
!this.configService.get<string>('INFRA.MICROSOFT_CLIENT_SECRET')
);
case AuthProvider.EMAIL:
return (
this.configService.get<string>('INFRA.MAILER_SMTP_URL') &&
this.configService.get<string>('INFRA.MAILER_ADDRESS_FROM')
);
default:
return false;
}
}
/** /**
* Enable or Disable SSO for login/signup * Enable or Disable SSO for login/signup
* @param provider Auth Provider to enable or disable * @param provider Auth Provider to enable or disable
@@ -229,21 +195,15 @@ export class InfraConfigService implements OnModuleInit {
let updatedAuthProviders = allowedAuthProviders; let updatedAuthProviders = allowedAuthProviders;
for (let i = 0; i < providerInfo.length; i++) { providerInfo.forEach(({ provider, status }) => {
const { provider, status } = providerInfo[i];
if (status === ServiceStatus.ENABLE) { if (status === ServiceStatus.ENABLE) {
const isConfigured = this.isServiceConfigured(provider);
if (!isConfigured) {
throwErr(INFRA_CONFIG_SERVICE_NOT_CONFIGURED);
}
updatedAuthProviders.push(provider); updatedAuthProviders.push(provider);
} else if (status === ServiceStatus.DISABLE) { } else if (status === ServiceStatus.DISABLE) {
updatedAuthProviders = updatedAuthProviders.filter( updatedAuthProviders = updatedAuthProviders.filter(
(p) => p !== provider, (p) => p !== provider,
); );
} }
} });
updatedAuthProviders = [...new Set(updatedAuthProviders)]; updatedAuthProviders = [...new Set(updatedAuthProviders)];
@@ -326,9 +286,6 @@ export class InfraConfigService implements OnModuleInit {
} }
} }
/**
* Validate the values of the InfraConfigs
*/
validateEnvValues( validateEnvValues(
infraConfigs: { infraConfigs: {
name: InfraConfigEnumForClient | InfraConfigEnum; name: InfraConfigEnumForClient | InfraConfigEnum;
@@ -345,24 +302,6 @@ export class InfraConfigService implements OnModuleInit {
const isValidEmail = validateEmail(infraConfigs[i].value); const isValidEmail = validateEmail(infraConfigs[i].value);
if (!isValidEmail) return E.left(INFRA_CONFIG_INVALID_INPUT); if (!isValidEmail) return E.left(INFRA_CONFIG_INVALID_INPUT);
break; break;
case InfraConfigEnumForClient.GOOGLE_CLIENT_ID:
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
break;
case InfraConfigEnumForClient.GOOGLE_CLIENT_SECRET:
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
break;
case InfraConfigEnumForClient.GITHUB_CLIENT_ID:
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
break;
case InfraConfigEnumForClient.GITHUB_CLIENT_SECRET:
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
break;
case InfraConfigEnumForClient.MICROSOFT_CLIENT_ID:
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
break;
case InfraConfigEnumForClient.MICROSOFT_CLIENT_SECRET:
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
break;
default: default:
break; break;
} }

View File

@@ -121,7 +121,7 @@
"generate_token": "Generate Token", "generate_token": "Generate Token",
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init", "graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
"include_in_url": "Include in URL", "include_in_url": "Include in URL",
"inherited_from": "Inherited {auth} from parent collection {collection} ", "inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
"learn": "Learn how", "learn": "Learn how",
"oauth": { "oauth": {
"redirect_auth_server_returned_error": "Auth Server returned an error state", "redirect_auth_server_returned_error": "Auth Server returned an error state",
@@ -295,7 +295,6 @@
"incorrect_email": "Incorrect email", "incorrect_email": "Incorrect email",
"invalid_link": "Invalid link", "invalid_link": "Invalid link",
"invalid_link_description": "The link you clicked is invalid or expired.", "invalid_link_description": "The link you clicked is invalid or expired.",
"invalid_embed_link": "The embed does not exist or is invalid.",
"json_parsing_failed": "Invalid JSON", "json_parsing_failed": "Invalid JSON",
"json_prettify_invalid_body": "Couldn't prettify an invalid body, solve json syntax errors and try again", "json_prettify_invalid_body": "Couldn't prettify an invalid body, solve json syntax errors and try again",
"network_error": "There seems to be a network error. Please try again.", "network_error": "There seems to be a network error. Please try again.",

View File

@@ -1,11 +1,11 @@
/* eslint-disable */ // generated by unplugin-vue-components
/* prettier-ignore */ // We suggest you to commit this file into source control
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {} export {}
declare module 'vue' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default'] AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default']
AppBanner: typeof import('./components/app/Banner.vue')['default'] AppBanner: typeof import('./components/app/Banner.vue')['default']
@@ -210,4 +210,5 @@ declare module 'vue' {
WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default'] WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default']
WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default'] WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default']
} }
} }

View File

@@ -1,16 +1,15 @@
<template> <template>
<Splitpanes <Splitpanes
class="smart-splitter"
:rtl="SIDEBAR_ON_LEFT && mdAndLarger" :rtl="SIDEBAR_ON_LEFT && mdAndLarger"
:class="{ :class="{
'!flex-row-reverse': SIDEBAR_ON_LEFT && mdAndLarger, '!flex-row-reverse': SIDEBAR_ON_LEFT && mdAndLarger,
'smart-splitter': SIDEBAR && hasSidebar,
'no-splitter': !(SIDEBAR && hasSidebar),
}" }"
:horizontal="!mdAndLarger" :horizontal="!mdAndLarger"
@resize="setPaneEvent($event, 'vertical')" @resize="setPaneEvent($event, 'vertical')"
> >
<Pane <Pane
:size="SIDEBAR && hasSidebar ? PANE_MAIN_SIZE : 100" :size="PANE_MAIN_SIZE"
min-size="65" min-size="65"
class="flex flex-col !overflow-auto" class="flex flex-col !overflow-auto"
> >
@@ -37,8 +36,9 @@
</Splitpanes> </Splitpanes>
</Pane> </Pane>
<Pane <Pane
:size="SIDEBAR && hasSidebar ? PANE_SIDEBAR_SIZE : 0" v-if="SIDEBAR && hasSidebar"
:min-size="25" :size="PANE_SIDEBAR_SIZE"
min-size="25"
class="flex flex-col !overflow-auto bg-primaryContrast" class="flex flex-col !overflow-auto bg-primaryContrast"
> >
<slot name="sidebar" /> <slot name="sidebar" />

View File

@@ -33,7 +33,6 @@
@select="onSelect" @select="onSelect"
@update-team="updateTeam" @update-team="updateTeam"
@update-collection-type="updateCollectionType" @update-collection-type="updateCollectionType"
@set-team-collection-adapter="teamCollectionAdapter = $event"
/> />
</div> </div>
</template> </template>
@@ -87,7 +86,6 @@ import { platform } from "~/platform"
import { useService } from "dioc/vue" import { useService } from "dioc/vue"
import { RESTTabService } from "~/services/tab/rest" import { RESTTabService } from "~/services/tab/rest"
import { GQLTabService } from "~/services/tab/graphql" import { GQLTabService } from "~/services/tab/graphql"
import TeamCollectionAdapter from "~/helpers/teams/TeamCollectionAdapter"
const t = useI18n() const t = useI18n()
const toast = useToast() const toast = useToast()
@@ -95,8 +93,6 @@ const toast = useToast()
const RESTTabs = useService(RESTTabService) const RESTTabs = useService(RESTTabService)
const GQLTabs = useService(GQLTabService) const GQLTabs = useService(GQLTabService)
const teamCollectionAdapter = ref<TeamCollectionAdapter>()
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
type CollectionType = type CollectionType =
@@ -384,6 +380,7 @@ const saveRequestAs = async () => {
platform: "rest", platform: "rest",
workspaceType: "team", workspaceType: "team",
}) })
pipe( pipe(
updateTeamRequest(picked.value.requestID, data), updateTeamRequest(picked.value.requestID, data),
TE.match( TE.match(
@@ -391,31 +388,7 @@ const saveRequestAs = async () => {
toast.error(`${getErrorMessage(err)}`) toast.error(`${getErrorMessage(err)}`)
modalLoadingState.value = false modalLoadingState.value = false
}, },
(result) => { () => {
const { updateRequest } = result
RESTTabs.currentActiveTab.value.document = {
request: requestUpdated,
isDirty: false,
saveContext: {
originLocation: "team-collection",
requestID: updateRequest.id,
collectionID: updateRequest.collectionID,
},
}
if (teamCollectionAdapter.value) {
const { auth, headers } =
teamCollectionAdapter.value.cascadeParentCollectionForHeaderAuth(
updateRequest.collectionID
)
RESTTabs.currentActiveTab.value.document.inheritedProperties = {
auth,
headers,
}
}
modalLoadingState.value = false modalLoadingState.value = false
requestSaved() requestSaved()
} }
@@ -543,18 +516,6 @@ const updateTeamCollectionOrFolder = (
}, },
} }
if (teamCollectionAdapter.value) {
const { auth, headers } =
teamCollectionAdapter.value.cascadeParentCollectionForHeaderAuth(
createRequestInCollection.collection.id
)
RESTTabs.currentActiveTab.value.document.inheritedProperties = {
auth,
headers,
}
}
modalLoadingState.value = false modalLoadingState.value = false
requestSaved() requestSaved()
} }

View File

@@ -262,7 +262,6 @@ const emit = defineEmits<{
(event: "select", payload: Picked | null): void (event: "select", payload: Picked | null): void
(event: "update-team", team: SelectedTeam): void (event: "update-team", team: SelectedTeam): void
(event: "update-collection-type", type: CollectionType["type"]): void (event: "update-collection-type", type: CollectionType["type"]): void
(event: "set-team-collection-adapter", adapter: TeamCollectionAdapter): void
}>() }>()
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
@@ -355,7 +354,6 @@ watch(
(newTeam) => { (newTeam) => {
if (newTeam) { if (newTeam) {
teamCollectionAdapter.changeTeamID(newTeam.id) teamCollectionAdapter.changeTeamID(newTeam.id)
emit("set-team-collection-adapter", teamCollectionAdapter)
} }
} }
) )

View File

@@ -140,10 +140,7 @@ const runQuery = async (
const runVariables = clone(request.value.variables) const runVariables = clone(request.value.variables)
const runAuth = const runAuth =
request.value.auth.authType === "inherit" && request.value.auth.authActive request.value.auth.authType === "inherit" && request.value.auth.authActive
? clone( ? clone(tabs.currentActiveTab.value.document.inheritedProperties?.auth)
tabs.currentActiveTab.value.document.inheritedProperties?.auth
.inheritedAuth
)
: clone(request.value.auth) : clone(request.value.auth)
const inheritedHeaders = const inheritedHeaders =

View File

@@ -21,7 +21,7 @@
/> />
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<div v-if="loading" class="flex flex-col items-center justify-center p-4"> <div v-if="loading" class="flex flex-col items-center justify-center">
<HoppSmartSpinner class="mb-4" /> <HoppSmartSpinner class="mb-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
@@ -451,7 +451,7 @@ const getErrorMessage = (err: GQLError<string>) => {
} }
switch (err.error) { switch (err.error) {
case "shortcode/not_found": case "shortcode/not_found":
return t("shared_requests.not_found") return t("shared_request.not_found")
default: default:
return t("error.something_went_wrong") return t("error.something_went_wrong")
} }

View File

@@ -2,6 +2,5 @@ mutation UpdateRequest($data: UpdateTeamRequestInput!, $requestID: ID!) {
updateRequest(data: $data, requestID: $requestID) { updateRequest(data: $data, requestID: $requestID) {
id id
title title
collectionID
} }
} }

View File

@@ -27,7 +27,7 @@ export const getDefaultGQLRequest = (): HoppGQLRequest => ({
}`, }`,
query: DEFAULT_QUERY, query: DEFAULT_QUERY,
auth: { auth: {
authType: "none", authType: "inherit",
authActive: true, authActive: true,
}, },
}) })

View File

@@ -156,7 +156,6 @@ export default class ShortcodeListAdapter {
const [shortcodeCreated$, shortcodeCreatedSub] = runAuthOnlyGQLSubscription( const [shortcodeCreated$, shortcodeCreatedSub] = runAuthOnlyGQLSubscription(
{ {
query: ShortcodeCreatedDocument, query: ShortcodeCreatedDocument,
variables: {},
} }
) )
@@ -173,7 +172,6 @@ export default class ShortcodeListAdapter {
const [shortcodeRevoked$, shortcodeRevokedSub] = runAuthOnlyGQLSubscription( const [shortcodeRevoked$, shortcodeRevokedSub] = runAuthOnlyGQLSubscription(
{ {
query: ShortcodeDeletedDocument, query: ShortcodeDeletedDocument,
variables: {},
} }
) )
@@ -190,7 +188,6 @@ export default class ShortcodeListAdapter {
const [shortcodeUpdated$, shortcodeUpdatedSub] = runAuthOnlyGQLSubscription( const [shortcodeUpdated$, shortcodeUpdatedSub] = runAuthOnlyGQLSubscription(
{ {
query: ShortcodeUpdatedDocument, query: ShortcodeUpdatedDocument,
variables: {},
} }
) )

View File

@@ -1034,11 +1034,6 @@ export default class NewTeamCollectionAdapter {
} }
} }
/**
* Used to obtain the inherited auth and headers for a given folder path, used for both REST and GraphQL team collections
* @param folderPath the path of the folder to cascade the auth from
* @returns the inherited auth and headers for the given folder path
*/
public cascadeParentCollectionForHeaderAuth(folderPath: string) { public cascadeParentCollectionForHeaderAuth(folderPath: string) {
let auth: HoppInheritedProperty["auth"] = { let auth: HoppInheritedProperty["auth"] = {
parentID: folderPath ?? "", parentID: folderPath ?? "",
@@ -1094,10 +1089,7 @@ export default class NewTeamCollectionAdapter {
const parentFolderAuth = data.auth const parentFolderAuth = data.auth
const parentFolderHeaders = data.headers const parentFolderHeaders = data.headers
if ( if (parentFolderAuth?.authType === "inherit" && path.length === 1) {
parentFolderAuth?.authType === "inherit" &&
[...path.slice(0, i + 1)].length === 1
) {
auth = { auth = {
parentID: [...path.slice(0, i + 1)].join("/"), parentID: [...path.slice(0, i + 1)].join("/"),
parentName: parentFolder.title, parentName: parentFolder.title,

View File

@@ -4,7 +4,6 @@ import {
HoppRESTRequest, HoppRESTRequest,
HoppCollection, HoppCollection,
makeCollection, makeCollection,
HoppGQLAuth,
} from "@hoppscotch/data" } from "@hoppscotch/data"
import DispatchingStore, { defineDispatchers } from "./DispatchingStore" import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
import { cloneDeep } from "lodash-es" import { cloneDeep } from "lodash-es"
@@ -12,9 +11,6 @@ import { resolveSaveContextOnRequestReorder } from "~/helpers/collection/request
import { getService } from "~/modules/dioc" import { getService } from "~/modules/dioc"
import { RESTTabService } from "~/services/tab/rest" import { RESTTabService } from "~/services/tab/rest"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
import { HoppRESTAuth } from "@hoppscotch/data"
import { HoppRESTHeaders } from "@hoppscotch/data"
import { HoppGQLHeader } from "~/helpers/graphql"
const defaultRESTCollectionState = { const defaultRESTCollectionState = {
state: [ state: [
@@ -67,12 +63,6 @@ export function navigateToFolderWithIndexPath(
return target !== undefined ? target : null return target !== undefined ? target : null
} }
/**
* Used to obtain the inherited auth and headers for a given folder path, used for both REST and GraphQL personal collections
* @param folderPath the path of the folder to cascade the auth from
* @param type the type of collection
* @returns the inherited auth and headers for the given folder path
*/
export function cascadeParentCollectionForHeaderAuth( export function cascadeParentCollectionForHeaderAuth(
folderPath: string | undefined, folderPath: string | undefined,
type: "rest" | "graphql" type: "rest" | "graphql"
@@ -113,16 +103,10 @@ export function cascadeParentCollectionForHeaderAuth(
return { auth, headers } return { auth, headers }
} }
const parentFolderAuth = parentFolder.auth as HoppRESTAuth | HoppGQLAuth const parentFolderAuth = parentFolder.auth
const parentFolderHeaders = parentFolder.headers as const parentFolderHeaders = parentFolder.headers
| HoppRESTHeaders
| HoppGQLHeader[]
// check if the parent folder has authType 'inherit' and if it is the root folder // check if the parent folder has authType 'inherit' and if it is the root folder
if ( if (parentFolderAuth?.authType === "inherit" && path.length === 1) {
parentFolderAuth?.authType === "inherit" &&
[...path.slice(0, i + 1)].length === 1
) {
auth = { auth = {
parentID: [...path.slice(0, i + 1)].join("/"), parentID: [...path.slice(0, i + 1)].join("/"),
parentName: parentFolder.name, parentName: parentFolder.name,

View File

@@ -1,58 +1,11 @@
<template> <template>
<div class="flex flex-col justify-center"> <div class="flex flex-col flex-1 w-full">
<div
v-if="invalidLink"
class="flex flex-1 flex-col items-center justify-center p-8"
>
<icon-lucide-alert-triangle class="svg-icons mb-2 opacity-75" />
<h1 class="heading text-center">
{{ t("error.invalid_link") }}
</h1>
<p class="mt-2 text-center">
{{ t("error.invalid_embed_link") }}
</p>
</div>
<Embeds <Embeds
v-else-if="!invalidLink && tab" v-if="tab"
v-model:modelTab="tab" v-model:modelTab="tab"
:properties="properties" :properties="properties"
:shared-request-i-d="sharedRequestID" :shared-request-i-d="sharedRequestID"
/> />
<div v-else class="flex flex-1 flex-col items-center justify-center p-4">
<div
v-if="sharedRequestDetails.loading"
class="flex flex-1 flex-col items-center justify-center p-4"
>
<HoppSmartSpinner />
</div>
<div v-else>
<div
v-if="
!sharedRequestDetails.loading && E.isLeft(sharedRequestDetails.data)
"
class="flex flex-col items-center p-4"
>
<icon-lucide-alert-triangle class="svg-icons mb-2 opacity-75" />
<h1 class="heading text-center">
{{ t("error.invalid_link") }}
</h1>
<p class="mt-2 text-center">
{{ t("error.invalid_embed_link") }}
</p>
</div>
<div
v-if="
!sharedRequestDetails.loading &&
E.isRight(sharedRequestDetails.data)
"
class="flex flex-1 flex-col items-center justify-center p-4"
>
<h1 class="heading">
{{ t("state.loading") }}
</h1>
</div>
</div>
</div>
</div> </div>
</template> </template>
@@ -75,9 +28,6 @@ import {
import { HoppTab } from "~/services/tab" import { HoppTab } from "~/services/tab"
import { HoppRESTDocument } from "~/helpers/rest/document" import { HoppRESTDocument } from "~/helpers/rest/document"
import { applySetting } from "~/newstore/settings" import { applySetting } from "~/newstore/settings"
import { useI18n } from "~/composables/i18n"
const t = useI18n()
const route = useRoute() const route = useRoute()

View File

@@ -244,13 +244,9 @@ export class PersistenceService extends Service {
private setupSettingsPersistence() { private setupSettingsPersistence() {
const settingsKey = "settings" const settingsKey = "settings"
let settingsData = JSON.parse( let settingsData = JSON.parse(
window.localStorage.getItem(settingsKey) ?? "null" window.localStorage.getItem(settingsKey) || "{}"
) )
if (!settingsData) {
settingsData = getDefaultSettings()
}
// Validate data read from localStorage // Validate data read from localStorage
const result = SETTINGS_SCHEMA.safeParse(settingsData) const result = SETTINGS_SCHEMA.safeParse(settingsData)
if (result.success) { if (result.success) {

View File

@@ -36,7 +36,7 @@ const SettingsDefSchema = z.object({
httpUser: z.boolean(), httpUser: z.boolean(),
httpPassword: z.boolean(), httpPassword: z.boolean(),
bearerToken: z.boolean(), bearerToken: z.boolean(),
oauth2Token: z.optional(z.boolean()), oauth2Token: z.boolean(),
}), }),
THEME_COLOR: ThemeColorSchema, THEME_COLOR: ThemeColorSchema,
BG_COLOR: BgColorSchema, BG_COLOR: BgColorSchema,
@@ -103,10 +103,13 @@ export const LOCAL_STATE_SCHEMA = z.union([
.strict(), .strict(),
]) ])
export const SETTINGS_SCHEMA = SettingsDefSchema.extend({ export const SETTINGS_SCHEMA = z.union([
EXTENSIONS_ENABLED: z.optional(z.boolean()), z.object({}).strict(),
PROXY_ENABLED: z.optional(z.boolean()), SettingsDefSchema.extend({
}) EXTENSIONS_ENABLED: z.optional(z.boolean()),
PROXY_ENABLED: z.optional(z.boolean()),
}),
])
export const REST_HISTORY_ENTRY_SCHEMA = z export const REST_HISTORY_ENTRY_SCHEMA = z
.object({ .object({
@@ -205,7 +208,7 @@ export const MQTT_REQUEST_SCHEMA = z.nullable(
z z
.object({ .object({
endpoint: z.string(), endpoint: z.string(),
clientID: z.optional(z.string()), clientID: z.string(),
}) })
.strict() .strict()
) )

View File

@@ -1,8 +0,0 @@
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
module.exports = config