Skip to content

Commit

Permalink
Chore: rebrand nodeauthrequired popop (#1942)
Browse files Browse the repository at this point in the history
* chore: type fix

* chore: rebrand NodeAuthRequiredPopup

* chore: extract NodeAuthTab for reus

* feat: use Node Authentication tab if required

* chore: show default network
  • Loading branch information
Tuditi authored Feb 15, 2024
1 parent fc3e882 commit 132f7c0
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 72 deletions.
10 changes: 8 additions & 2 deletions packages/desktop/components/popup/popups/AddNodePopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
let nodeConfigurationForm: NodeConfigurationForm
let isBusy = false
let requiresAuth = false
$: disabled = !node?.url || (requiresAuth && !node?.auth)
async function onSubmit(): Promise<void> {
try {
Expand All @@ -40,7 +43,9 @@
onSuccess()
} catch (err) {
if (err.type !== 'validationError') {
if (err?.error?.match(/(username)|(password)|(jwt)/g)) {
requiresAuth = true
} else if (err.type !== 'validationError') {
showNotification({
variant: 'error',
text: localize(err?.error ?? 'error.global.generic'),
Expand All @@ -63,12 +68,13 @@
type: 'submit',
form: 'node-configuration-form',
text: localize(`actions.${isEditingNode ? 'updateNode' : 'addNode'}`),
disabled: !node.url,
disabled,
}}
>
<NodeConfigurationForm
bind:this={nodeConfigurationForm}
bind:node
{requiresAuth}
{onSubmit}
{isBusy}
isDeveloperProfile={$activeProfile.isDeveloperProfile}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,58 @@
<script lang="ts">
import { Text, TextInput, TextType } from '@ui'
import { NodeAuthTab } from '@ui'
import type { IAuth } from '@iota/sdk'
import { handleError } from '@core/error/handlers'
import { localize } from '@core/i18n'
import { closePopup } from '@desktop/auxiliary/popup'
import { Button } from '@bloomwalletio/ui'
import PopupTemplate from '../PopupTemplate.svelte'
import { IError } from '@core/error'
export let onSubmit: (auth: IAuth) => unknown = () => {}
let isBusy = false
let auth: IAuth
let jwtError: string | undefined
let jwt: string
let jwtError: string
$: disabled = isBusy || !auth
$: disabled = !jwt || isBusy
async function handleSubmit(): Promise<void> {
async function onConfirmClick(): Promise<void> {
try {
isBusy = true
const auth = { jwt }
await onSubmit(auth)
isBusy = false
} catch (err) {
const error = err as IError
isBusy = false
const authenticationError = err?.error?.match(/(jwt)/g)?.[0]
const authenticationError = error?.error?.match(/(jwt)/g)?.[0]
switch (authenticationError) {
case 'jwt':
jwtError = err.error
jwtError = error?.error
break
default:
handleError(err)
handleError(error)
break
}
}
}
function onCancelClick(): void {
closePopup()
}
</script>

<form id="node-auth-required" on:submit|preventDefault={handleSubmit}>
<Text type={TextType.h3} classes="mb-6">{localize('popups.nodeAuthRequired.title')}</Text>
<Text fontSize="15">{localize('popups.nodeAuthRequired.body')}</Text>
<div class="flex flex-col w-full space-y-5 mt-4">
<TextInput
bind:value={jwt}
bind:error={jwtError}
placeholder={localize('general.jwt')}
label={localize('general.jwt')}
/>
</div>
<div class="flex w-full space-x-4 mt-6">
<Button variant="outlined" width="full" on:click={() => closePopup()} text={localize('actions.cancel')} />
<Button {disabled} busy={isBusy} type="submit" width="full" text={localize('actions.confirm')} />
</div>
</form>
<PopupTemplate
title={localize('popups.nodeAuthRequired.title')}
description={localize('popups.nodeAuthRequired.body')}
backButton={{
text: localize('actions.cancel'),
onClick: onCancelClick,
}}
continueButton={{
text: localize('actions.confirm'),
onClick: onConfirmClick,
disabled,
}}
busy={isBusy}
>
<NodeAuthTab bind:auth {jwtError} />
</PopupTemplate>
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
getNetworkIdFromOnboardingNetworkType,
getNodeInfoWhileLoggedOut,
} from '@core/network'
import features from '@features/features'
import { NodeConfigurationForm } from '@ui'
import { OnboardingLayout } from '@views/components'
import { onMount } from 'svelte'
Expand All @@ -20,15 +19,10 @@
let node: INode
let busy = false
let formError = ''
let networkType: OnboardingNetworkType = getInitialSelectedNetworkType()
let requiresAuth = false
let networkType: OnboardingNetworkType
function getInitialSelectedNetworkType(): OnboardingNetworkType {
return features?.onboarding?.shimmer?.enabled
? OnboardingNetworkType.Shimmer
: features?.onboarding?.testnet?.enabled
? OnboardingNetworkType.Testnet
: OnboardingNetworkType.Custom
}
$: disableContinue = !node?.url || !networkType || (requiresAuth && !node?.auth)
function onBackClick(): void {
$networkSetupRouter.previous()
Expand Down Expand Up @@ -61,7 +55,9 @@
} catch (err) {
console.error(err)
updateOnboardingProfile({ clientOptions: undefined, network: undefined })
if (err?.error?.includes('error sending request for url')) {
if (err?.error?.match(/(username)|(password)|(jwt)/g)) {
requiresAuth = true
} else if (err?.error?.includes('error sending request for url')) {
formError = localize('error.node.unabledToConnect')
} else if (err?.message === 'error.node.differentNetwork') {
formError = localize('error.node.differentNetwork')
Expand All @@ -86,6 +82,7 @@
title={localize('views.onboarding.networkSetup.setupCustomNetwork.title')}
continueButton={{
onClick: onContinueClick,
disabled: disableContinue,
}}
backButton={{
onClick: onBackClick,
Expand All @@ -100,6 +97,7 @@
bind:coinType
bind:node
bind:formError
{requiresAuth}
isBusy={busy}
isDeveloperProfile
networkEditable
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/src/components/helpers/getTabItems.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { localize } from '@core/i18n'
import { KeyValue } from '../types'
import { Tab } from '@ui/enums'
import { PopupTab } from '@ui/enums'

export function getTabItems(items: Tab[]): KeyValue<string>[] {
export function getTabItems(items: PopupTab[]): KeyValue<string>[] {
return items.map((item) => ({ key: item, value: localize(`general.${item}`) }))
}
46 changes: 46 additions & 0 deletions packages/shared/src/components/molecules/NodeAuthTab.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script lang="ts">
import { KeyValue } from '@ui'
import { localize } from '@core/i18n'
import { PasswordInput, TextInput, Tabs } from '@bloomwalletio/ui'
import { IAuth } from '@iota/sdk'
export let auth: IAuth | undefined
export let jwtError: string | undefined = undefined
let [username, password] = auth?.basicAuthNamePwd ?? ['', '']
let jwt = auth?.jwt ?? ''
enum Auth {
Credentials = 'credentials',
Jwt = 'jwt',
}
const tabs: KeyValue<string>[] = [
{ key: Auth.Credentials, value: localize('popups.node.credentials') },
{ key: Auth.Jwt, value: localize('popups.node.jwt') },
]
let selectedTab = tabs[0]
$: isJwtAuthentication = selectedTab.key === Auth.Jwt
$: selectedTab, jwt, username, password, setAuth()
function setAuth(): void {
if (isJwtAuthentication && jwt) {
auth = { jwt }
} else if (!isJwtAuthentication && username && password) {
auth = { basicAuthNamePwd: [username, password] as [string, string] }
} else {
auth = undefined
}
}
</script>

<div class="flex flex-col w-full space-y-4">
<Tabs bind:selectedTab {tabs} />
{#if isJwtAuthentication}
<TextInput bind:value={jwt} error={jwtError} label={localize('popups.node.jwt')} />
{:else}
<TextInput bind:value={username} label={localize('general.username')} />
<PasswordInput bind:value={password} minlength={1} label={localize('general.password')} />
{/if}
</div>
1 change: 1 addition & 0 deletions packages/shared/src/components/molecules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as NetworkRecipientSelector } from './NetworkRecipientSelector.
export { default as NftGallery } from './NftGallery.svelte'
export { default as NftGalleryItem } from './NftGalleryItem.svelte'
export { default as NftMedia } from './NftMedia.svelte'
export { default as NodeAuthTab } from './NodeAuthTab.svelte'
export { default as SelectorInput } from './SelectorInput.svelte'
export { default as ShimmerClaimingAccountList } from './ShimmerClaimingAccountList.svelte'
export { default as TransactionAssetSection } from './TransactionAssetSection.svelte'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { OnboardingNetworkType } from '@contexts/onboarding'
import { localize } from '@core/i18n'
import { IAuth, INode } from '@iota/sdk/out/types'
import { INode } from '@iota/sdk/out/types'
import { DEFAULT_NETWORK_METADATA, EMPTY_NODE } from '@core/network/constants'
import { IClientOptions, INodeInfoResponse } from '@core/network/interfaces'
import { nodeInfo } from '@core/network/stores'
Expand All @@ -14,7 +14,8 @@
import { activeProfile } from '@core/profile/stores'
import { cleanUrl } from '@core/utils'
import features from '@features/features'
import { Error, IOption, NumberInput, PasswordInput, SelectInput, TextInput } from '@bloomwalletio/ui'
import { NodeAuthTab } from '@ui'
import { Alert, Error, IOption, NumberInput, SelectInput, TextInput } from '@bloomwalletio/ui'
interface INodeValidationOptions {
checkNodeInfo: boolean
Expand All @@ -28,24 +29,22 @@
export let coinType: string = ''
export let isBusy = false
export let formError = ''
export let requiresAuth = false
export let currentClientOptions: IClientOptions | undefined = undefined
export let isDeveloperProfile: boolean = false
export let onSubmit: () => void = () => {}
export let networkEditable: boolean = false
const networkOptions: IOption[] = getNetworkTypeOptions()
let [username, password] = node.auth?.basicAuthNamePwd ?? ['', '']
let jwt = node.auth?.jwt ?? ''
let auth = node?.auth
$: networkType, (coinType = '')
$: networkType, coinType, node.url, (formError = '')
$: jwt,
username,
password,
$: auth,
(node = {
url: node.url,
auth: getAuth(),
auth,
})
function getNetworkTypeOptions(): IOption[] {
Expand All @@ -61,17 +60,6 @@
return options.filter((item) => features.onboarding?.[item.value]?.enabled)
}
function getAuth(): IAuth {
const auth: IAuth = {}
if ([username, password].every((value) => value !== '')) {
auth.basicAuthNamePwd = [username, password]
}
if (jwt !== '') {
auth.jwt = jwt
}
return auth
}
function cleanNodeUrl(): void {
node.url = cleanUrl(node?.url)
}
Expand Down Expand Up @@ -146,13 +134,9 @@
disabled={isBusy}
on:change={cleanNodeUrl}
/>
<TextInput bind:value={username} label={localize('popups.node.optionalUsername')} disabled={isBusy} />
<PasswordInput
bind:value={password}
label={localize('popups.node.optionalPassword')}
required={!!username}
disabled={isBusy}
/>
<PasswordInput bind:value={jwt} label={localize('popups.node.optionalJwt')} required={false} disabled={isBusy} />
{#if requiresAuth}
<NodeAuthTab bind:auth />
<Alert variant="warning" text={localize('popups.node.requiresAuthentication')} />
{/if}
{#if formError}<Error error={formError} />{/if}
</form>
9 changes: 5 additions & 4 deletions packages/shared/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -848,10 +848,8 @@
"updatingNode": "Updating node",
"loadingNodeInfo": "Loading node info",
"nodeAddress": "Node address",
"optionalUsername": "Username (optional)",
"optionalPassword": "Password (optional)",
"optionalJwt": "JSON web token (optional)",
"removeConfirmation": "Are you sure you want to remove this node?",
"requiresAuthentication": "Node requires authentication",
"info": {
"general": {
"tab": "General",
Expand Down Expand Up @@ -886,7 +884,9 @@
"decimals": "Decimals",
"useMetricPrefix": "Use metric prefix"
}
}
},
"jwt": "JSON web token",
"credentials": "Sign-in credentials"
},
"errorLog": {
"title": "Error Log",
Expand Down Expand Up @@ -1348,6 +1348,7 @@
},
"general": {
"recipient": "Recipient",
"username": "Username",
"password": "Password",
"confirmPassword": "Confirm password",
"currentPassword": "Current password",
Expand Down

0 comments on commit 132f7c0

Please sign in to comment.