Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/.storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ window.Row = Row
window.FormGroup = FormGroup
// isMobile is set at app boot; stub it so components that read it render in Storybook.
window.isMobile = false
window.toast = (message) => console.log('[toast]', message)

/** @type { import('storybook').Preview } */
const preview = {
Expand Down
2 changes: 1 addition & 1 deletion frontend/common/theme/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"text": {
"default": { "cssVar": "--color-text-default", "light": "#1a2634", "dark": "#ffffff" },
"secondary": { "cssVar": "--color-text-secondary", "light": "#656d7b", "dark": "#9da4ae" },
"tertiary": { "cssVar": "--color-text-tertiary", "light": "#9da4ae", "dark": "rgba(255, 255, 255, 0.48)" },
"tertiary": { "cssVar": "--color-text-tertiary", "light": "#656d7b", "dark": "rgba(255, 255, 255, 0.48)", "description": "Placeholders and hint text. In light mode, dark enough to clear 4.5:1 on surface-default." },
"disabled": { "cssVar": "--color-text-disabled", "light": "#9da4ae", "dark": "rgba(255, 255, 255, 0.32)" },
"action": { "cssVar": "--color-text-action", "light": "#6837fc", "dark": "#906af6" },
"danger": { "cssVar": "--color-text-danger", "light": "#bb1720", "dark": "#ef4d56", "description": "In light mode, darker than border/icon danger to clear 4.5:1 on the tint." },
Expand Down
2 changes: 1 addition & 1 deletion frontend/common/theme/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export const colorTextDisabled = 'var(--color-text-disabled, #9da4ae)'
export const colorTextInfo = 'var(--color-text-info, #0aaddf)'
export const colorTextSecondary = 'var(--color-text-secondary, #656d7b)'
export const colorTextSuccess = 'var(--color-text-success, #13787b)'
export const colorTextTertiary = 'var(--color-text-tertiary, #9da4ae)'
export const colorTextTertiary = 'var(--color-text-tertiary, #656d7b)'
export const colorTextWarning = 'var(--color-text-warning, #9f5208)'

// Chart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export const AllTokens: StoryObj = {
<code>--color-text-tertiary</code>
</td>
<td>
<code>var(--slate-300)</code>
<code>var(--slate-500)</code>
</td>
</tr>
<tr>
Expand Down
94 changes: 94 additions & 0 deletions frontend/documentation/components/ValueEditor.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { useState } from 'react'
import type { Meta, StoryObj } from 'storybook'
Comment thread
talissoncosta marked this conversation as resolved.

import ValueEditor from 'components/ValueEditor'
import FieldLabel from 'components/base/forms/FieldLabel'
import Constants from 'common/constants'

const meta: Meta = {
parameters: { chromatic: { disableSnapshot: false } },
title: 'Components/Forms/ValueEditor',
}
export default meta

type Story = StoryObj
Comment thread
talissoncosta marked this conversation as resolved.

const DEFAULT_TOOLTIP = Constants.strings.REMOTE_CONFIG_DESCRIPTION

const Interactive = ({
initialValue = '',
label,
tooltip = DEFAULT_TOOLTIP,
...props
}: Record<string, any>) => {
Comment thread
talissoncosta marked this conversation as resolved.
const [value, setValue] = useState(initialValue)
return (
<div style={{ maxWidth: 640, paddingTop: 24 }}>
{label && <FieldLabel tooltip={tooltip}>{label}</FieldLabel>}
<ValueEditor {...props} value={value} onChange={setValue} />
</div>
)
}

export const Default: Story = {
render: () => <Interactive label='Value' />,
}

export const WithValue: Story = {
render: () => <Interactive label='Value' initialValue='DEFAULT_VALUE' />,
}

export const Multiline: Story = {
render: () => (
<Interactive
label='Value'
initialValue={
'a-long-single-line-value-that-runs-under-the-copy-button-if-unpadded\nsecond line\nthird line'
}
/>
),
}

export const Json: Story = {
render: () => (
<Interactive
label='Value'
language='json'
initialValue='{ "colour": "blue", "size": 12 }'
/>
),
}

export const InvalidJson: Story = {
render: () => (
<Interactive label='Value' language='json' initialValue='{ "colour": ' />
),
}

export const CodeMedium: Story = {
render: () => (
<Interactive
label='Variation Value'
tooltip={Constants.strings.REMOTE_CONFIG_DESCRIPTION_VARIATION}
className='code-medium'
initialValue='variant-a'
/>
),
}

export const Disabled: Story = {
render: () => (
<Interactive label='Control value' disabled initialValue='DEFAULT_VALUE' />
),
}

export const OnlyOneLang: Story = {
render: () => (
<Interactive
label='IDP metadata XML'
onlyOneLang
language='xml'
initialValue={'<EntityDescriptor entityID="https://example.com" />'}
/>
),
}
53 changes: 29 additions & 24 deletions frontend/web/components/ValueEditor.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React, { Component } from 'react'
import cx from 'classnames'
import Highlight from './Highlight'
import ConfigProvider from 'common/providers/ConfigProvider'
import { Clipboard } from 'polyfill-react-native'
import Icon from './icons/Icon'
import { IonIcon } from '@ionic/react'
import { checkmarkCircle, warning } from 'ionicons/icons'
import BareButton from './base/forms/BareButton'
Comment thread
talissoncosta marked this conversation as resolved.

import toml from 'toml'
import yaml from 'yaml'
Expand Down Expand Up @@ -95,23 +93,24 @@ class Validation extends Component {
this.props.language === 'ini' ? 'toml' : this.props.language
return this.state.error ? (
<Tooltip
position='top'
title={
<IonIcon
<span
id='language-validation-error'
className='language-icon text-danger'
icon={warning}
/>
>
<Icon name='warning' width={14} fill='currentColor' />
</span>
}
>
{`${displayLanguage} validation error, please check your value.<br/>Error: ${this.state.error}`}
</Tooltip>
) : (
<IonIcon
<span
id='language-validation-success'
className='language-icon text-success'
icon={checkmarkCircle}
/>
>
<Icon name='checkmark-circle' width={14} />
</span>
)
}
}
Expand Down Expand Up @@ -141,8 +140,17 @@ class ValueEditor extends Component {
/>
)

copyValue = () => {
const res = Clipboard.setString(this.props.value)
toast(
res ? 'Clipboard set' : 'Could not set clipboard :(',
res ? '' : 'danger',
)
}

render() {
const { ...rest } = this.props
const showCopy = !this.props.onlyOneLang && !this.props.disabled
return (
<div
className={cx(
Expand Down Expand Up @@ -207,22 +215,19 @@ class ValueEditor extends Component {
>
.yaml {this.state.language === 'yaml' && this.renderValidation()}
</span>
<span
onMouseDown={() => {
const res = Clipboard.setString(this.props.value)
toast(
res ? 'Clipboard set' : 'Could not set clipboard :(',
res ? '' : 'danger',
)
}}
className={cx('txt primary')}
>
<Icon name='copy-outlined' fill={'#6837fc'} />
copy
</span>
</Row>
)}

{showCopy && (
<BareButton
className='value-editor__copy position-absolute rounded-sm icon-secondary'
aria-label='Copy value'
onClick={this.copyValue}
>
<Icon name='copy-outlined' width={20} />
</BareButton>
)}

{E2E ? (
<textarea {...rest} />
) : (
Expand All @@ -243,4 +248,4 @@ class ValueEditor extends Component {
}
}

export default ConfigProvider(ValueEditor)
export default ValueEditor
8 changes: 6 additions & 2 deletions frontend/web/components/base/forms/FieldLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ const FieldLabel: FC<FieldLabelProps> = ({
tooltip,
tooltipPlace = 'top',
}) => (
<label id={id} htmlFor={htmlFor} className={cn('control-label', className)}>
<label
id={id}
htmlFor={htmlFor}
className={cn('control-label d-flex align-items-center', className)}
>
{children}
{required && (
<span className='text-danger ml-1' aria-hidden>
Expand All @@ -36,7 +40,7 @@ const FieldLabel: FC<FieldLabelProps> = ({
)}
{tooltip && (
<Tooltip
title={<Icon name='info-outlined' width={12} height={12} />}
title={<Icon name='info-outlined' width={16} height={16} />}
place={tooltipPlace}
titleClassName='cursor-pointer ml-1 d-inline-flex align-items-center'
>
Expand Down
20 changes: 17 additions & 3 deletions frontend/web/styles/3rdParty/_hljs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@
padding: 9px 12px 9px 16px;
min-height: $input-height;
}
.value-editor__copy {
top: 11px;
}
}

.value-editor__copy {
top: 18px;
right: 12px;
z-index: 1;
padding: 2px;
&:hover {
color: var(--color-icon-action);
}
}

&:has(.value-editor__copy) .hljs {
padding-right: 44px;
}
textarea {
min-height: 50px;
Expand Down Expand Up @@ -78,9 +95,6 @@
color: var(--color-text-default);
font-weight: 500;
}
&.primary {
color: var(--color-text-action);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/web/styles/3rdParty/_react-select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
overflow: hidden;
text-overflow: ellipsis;
font-weight: normal;
color: $input-placeholder-color;
color: var(--color-text-tertiary);
}
&__indicator {
color: $text-icon-light-grey;
Expand Down
2 changes: 1 addition & 1 deletion frontend/web/styles/_tokens.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
--color-text-info: var(--blue-500);
--color-text-secondary: var(--slate-500);
--color-text-success: var(--green-600);
--color-text-tertiary: var(--slate-300);
--color-text-tertiary: var(--slate-500);
--color-text-warning: var(--orange-800);

// Code
Expand Down
2 changes: 0 additions & 2 deletions frontend/web/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ $input-border-color: $basic-alpha-16;
$input-border-color-dark: $bg-dark400;
$input-focus-border-color-dark: $primary;
$input-hover-border-color-dark: $white-alpha-8;
$input-placeholder-color: $text-icon-light-grey;
$input-padding: 12px 12px 12px 16px;
$input-padding-sm: 8px 12px 8px 14px;
$input-padding-xsm: 6px 8px;
Expand All @@ -256,7 +255,6 @@ $textarea-height-sm: 100px;
$textarea-height-xsm: 86px;
$textarea-height-lg: 128px;
$input-border-highlight-color: $primary400;
$input-placeholder-color-dark: $text-icon-light-grey;

//Switch
$switch-height: 24px;
Expand Down
Loading