Skip to content

Commit

Permalink
[YW][#4578] Fixes and improvements for redesigned create/edit univers…
Browse files Browse the repository at this point in the history
…e page

Summary:
- group instance types in a dropdown list
- rearrange DB Config step and change ports override component as discussed
- tune the toggle component as per design
- finalize the tooltip component
- refactor common styles and introduce `clsx` lib
- modify general page layout to occupy more space and add scroll inside the form area
- always show universe name in the header
- style `Summary` widget as per design
- fix bugs for edit universe logic
{F14500}
{F14501}
{F14502}

Test Plan:
Run UI, access creation of a new universe at `http://<host>/universe/create`
Edit universe - `http://<host>/universe/<universe-uuid>/edit/primary`

Reviewers: andrew

Reviewed By: andrew

Subscribers: ui

Differential Revision: https://phabricator.dev.yugabyte.com/D9918
  • Loading branch information
sshev committed Nov 23, 2020
1 parent 5172b43 commit c1fda7f
Show file tree
Hide file tree
Showing 48 changed files with 541 additions and 430 deletions.
5 changes: 5 additions & 0 deletions managed/ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions managed/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"ace-builds": "1.4.12",
"axios": "0.19.2",
"bootstrap": "3.4.1",
"clsx": "1.1.1",
"copy-to-clipboard": "3.3.1",
"cron-parser": "2.16.3",
"cron-validator": "1.1.1",
Expand Down
1 change: 1 addition & 0 deletions managed/ui/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<title>YugabyteDB Admin Console</title>
<script type="text/javascript" src="<% if (process.env.NODE_ENV === 'development') { %>http://localhost:9000<% } %>/api/v1/platform_config"></script>
<link href="<% if (process.env.NODE_ENV === 'development') { %>http://localhost:9000<% } %>/api/v1/ui_theme" rel="stylesheet" type="text/css" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap" rel="stylesheet">
</head>
<body>
Expand Down
13 changes: 6 additions & 7 deletions managed/ui/src/redesign/uikit/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import _ from 'lodash';
import clsx from 'clsx';
import React, { FC } from 'react';
import './Button.scss';

Expand All @@ -17,14 +17,13 @@ export const Button: FC<ButtonProps> = ({
children,
...props
}) => {
const classes = ['yb-uikit-button', props.className];
if (isCTA) classes.push('yb-uikit-button--cta');
if (chevronLeft) classes.push('yb-uikit-button--chevron-left');
if (chevronRight) classes.push('yb-uikit-button--chevron-right');

const extendedProps = {
...props,
className: _.compact(classes).join(' ')
className: clsx(props.className, 'yb-uikit-button', {
'yb-uikit-button--cta': isCTA,
'yb-uikit-button--chevron-left': chevronLeft,
'yb-uikit-button--chevron-right': chevronRight
})
};

return <button {...extendedProps}>{children}</button>;
Expand Down
1 change: 1 addition & 0 deletions managed/ui/src/redesign/uikit/I18n/I18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import React, { FC } from 'react';
type I18nProps = Record<string, unknown>;

// TODO: add real i18n support
export const translate = (message: string): string => message;
export const I18n: FC<I18nProps> = (props) => <span {...props} />;
18 changes: 8 additions & 10 deletions managed/ui/src/redesign/uikit/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import clsx from 'clsx';
import React, { FC, useRef } from 'react';
import './Input.scss';

Expand Down Expand Up @@ -35,20 +36,17 @@ export const Input: FC<InputProps> = (props) => {

return (
<div
className={`
yb-uikit-input
${props.disabled ? 'yb-uikit-input--disabled' : ''}
${props.invalid ? 'yb-uikit-input--invalid' : ''}
${props.className || ''}
`}
className={clsx(props.className, 'yb-uikit-input', {
'yb-uikit-input--disabled': props.disabled,
'yb-uikit-input--invalid': props.invalid
})}
>
<input ref={input} type="text" autoComplete="off" {...props} />
{props.type === 'number' && (
<div
className={`
yb-uikit-input__number-controls
${props.disabled ? 'yb-uikit-input__number-controls--disabled' : ''}
`}
className={clsx('yb-uikit-input__number-controls', {
'yb-uikit-input__number-controls--disabled': props.disabled
})}
>
<div className="yb-uikit-input__number-up" onClick={up} />
<div className="yb-uikit-input__number-delim" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
}

&__input {
width: 350px;
width: 400px;

&:first-child {
margin-right: 20px;
Expand Down
16 changes: 10 additions & 6 deletions managed/ui/src/redesign/uikit/KeyValueInput/KeyValueInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { FC, useState } from 'react';
import { Input } from '../Input/Input';
import { PlusButton } from '../PlusButton/PlusButton';
import { ReactComponent as DeleteIcon } from './clear-24px.svg';
import { translate } from '../I18n/I18n';
import './KeyValueInput.scss';

type ValueType = Record<string, string | number>;
Expand All @@ -15,8 +16,9 @@ interface RowItem {
interface KeyValueInputProps {
value: ValueType;
onChange(value: ValueType): void;
placeholderKey?: string;
placeholderValue?: string;
disabled?: boolean;
softReadonly?: boolean; // only values are editable, add/delete row controls are hidden and keys are read only
}

const objectToArray = (data: ValueType): RowItem[] => {
Expand All @@ -41,10 +43,11 @@ const arrayToObject = (data: RowItem[]): ValueType => {
};

export const KeyValueInput: FC<KeyValueInputProps> = ({
placeholderKey,
placeholderValue,
value,
onChange,
disabled,
softReadonly
disabled
}) => {
const [internalValue, setInternalValue] = useState<RowItem[]>(objectToArray(value));

Expand All @@ -63,9 +66,9 @@ export const KeyValueInput: FC<KeyValueInputProps> = ({
<div key={index} className="key-value-input__row">
<Input
type="text"
placeholder={placeholderKey}
disabled={disabled}
className="key-value-input__input"
readOnly={softReadonly}
value={row.key}
onChange={(event) => {
const newValue = [...internalValue];
Expand All @@ -75,6 +78,7 @@ export const KeyValueInput: FC<KeyValueInputProps> = ({
/>
<Input
type="text"
placeholder={placeholderValue}
disabled={disabled}
className="key-value-input__input"
value={row.value}
Expand All @@ -84,13 +88,13 @@ export const KeyValueInput: FC<KeyValueInputProps> = ({
updateData(newValue);
}}
/>
{!disabled && !softReadonly && (
{!disabled && (
<DeleteIcon className="key-value-input__icon" onClick={() => deleteRow(row)} />
)}
</div>
))}

{!disabled && !softReadonly && (
{!disabled && (
<PlusButton text="Add Row" className="key-value-input__add-row-btn" onClick={addRow} />
)}
</div>
Expand Down
9 changes: 4 additions & 5 deletions managed/ui/src/redesign/uikit/PlusButton/PlusButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import clsx from 'clsx';
import React, { FC, HTMLAttributes } from 'react';
import { I18n } from '../I18n/I18n';
import './PlusButton.scss';
Expand All @@ -11,11 +12,9 @@ export const PlusButton: FC<PlusButtonProps> = ({ disabled, text, className, onC
return (
<div
onClick={onClick}
className={`
yb-uikit-plus-button
${disabled ? 'yb-uikit-plus-button--disabled' : ''}
${className}
`}
className={clsx(className, 'yb-uikit-plus-button', {
'yb-uikit-plus-button--disabled': disabled
})}
>
<I18n>{text}</I18n>
</div>
Expand Down
7 changes: 7 additions & 0 deletions managed/ui/src/redesign/uikit/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ const customStyles: Styles = {
fontSize: '16px',
fontWeight: 400,
fontFamily: '"Source Sans Pro", sans-serif'
}),
groupHeading: (provided) => ({
...provided,
color: '#546371',
fontSize: '16px',
fontWeight: 700,
fontFamily: '"Source Sans Pro", sans-serif'
})
};

Expand Down
11 changes: 5 additions & 6 deletions managed/ui/src/redesign/uikit/Toggle/BaseToggle.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
display: inline-flex;
font-family: $YB_FONT_FAMILY;
user-select: none;
margin: 0 6px;
position: relative;

&--disabled {
Expand Down Expand Up @@ -55,21 +54,21 @@
}

&__handle {
width: 32px;
height: 32px;
width: 28px;
height: 28px;
border-radius: 50%;
background-color: $YB_PAGE_BACKGROUND;
box-shadow: 0 0 10px #00000029;
position: absolute;
top: 0;
top: 2px;
transition: left 250ms;

&--on {
left: calc(100% - 26px);
left: calc(100% - 30px);
}

&--off {
left: -6px;
left: 2px;
}

&--disabled {
Expand Down
44 changes: 18 additions & 26 deletions managed/ui/src/redesign/uikit/Toggle/BaseToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import clsx from 'clsx';
import React, { FC, useLayoutEffect, useRef, useState, ReactNode } from 'react';
import { ReactComponent as Checkmark } from './done-24px.svg';
import { ReactComponent as Crossmark } from './close-24px.svg';
Expand Down Expand Up @@ -51,7 +52,7 @@ export const BaseToggle: FC<BaseToggleProps> = ({

return (
<div
className={`yb-uikit-toggle ${disabled ? 'yb-uikit-toggle--disabled' : ''}`}
className={clsx('yb-uikit-toggle', { 'yb-uikit-toggle--disabled': disabled })}
onClick={toggle}
>
{sliderTexts && (
Expand All @@ -61,35 +62,26 @@ export const BaseToggle: FC<BaseToggleProps> = ({
</div>
)}
<div
className={`
yb-uikit-toggle__slider
${
checked
? `yb-uikit-toggle__slider--on ${sliderClass?.on || ''}`
: `yb-uikit-toggle__slider--off ${sliderClass?.off || ''}`
}
${disabled ? 'yb-uikit-toggle__slider--disabled' : ''}
`}
className={clsx('yb-uikit-toggle__slider', {
'yb-uikit-toggle__slider--disabled': disabled,
'yb-uikit-toggle__slider--on': checked,
'yb-uikit-toggle__slider--off': !checked,
[sliderClass?.on || '']: checked,
[sliderClass?.off || '']: !checked
})}
>
<div className="yb-uikit-toggle__value" style={{ width }}>
{sliderTexts ? (
checked ? (
sliderTexts.on
) : (
sliderTexts.off
)
) : checked ? (
<Checkmark />
) : (
<Crossmark />
)}
{sliderTexts
? (checked ? sliderTexts.on : sliderTexts.off)
: (checked ? <Checkmark /> : <Crossmark />)
}
</div>
<div
className={`
yb-uikit-toggle__handle
${checked ? 'yb-uikit-toggle__handle--on' : 'yb-uikit-toggle__handle--off'}
${disabled ? 'yb-uikit-toggle__handle--disabled' : ''}
`}
className={clsx('yb-uikit-toggle__handle', {
'yb-uikit-toggle__handle--disabled': disabled,
'yb-uikit-toggle__handle--on': checked,
'yb-uikit-toggle__handle--off': !checked
})}
/>
</div>
{descriptions && (
Expand Down
35 changes: 16 additions & 19 deletions managed/ui/src/redesign/uikit/Tooltip/Tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
margin: 0 10px;
position: relative;

&__handler {
&__handle {
&:before {
content: '?';
user-select: none;
Expand All @@ -24,23 +24,20 @@
cursor: pointer;
}
}
}

// TODO: temp, replace with popper.js
&__content {
position: absolute;
display: none;
top: 40px;
left: 0;
background-color: $YB_PAGE_BACKGROUND;
box-shadow: 0 0 10px #00000029;
border-radius: 10px;
padding: 10px;
max-width: 300px;
z-index: 2000;
font-size: 14px;
}

&:hover &__content {
display: block;
}
// tooltip popup has standalone styles as it rendered via react portal at the bottom of the document body
.yb-uikit-tooltip-popup {
position: absolute;
display: block;
opacity: 0;
margin-top: 6px; // margin between tooltip handler and its content
background-color: $YB_PAGE_BACKGROUND;
box-shadow: 0 0 10px #00000029;
border-radius: 10px;
padding: 20px;
max-width: 400px;
z-index: 2000;
font-size: 14px;
transition: opacity 200ms;
}
37 changes: 29 additions & 8 deletions managed/ui/src/redesign/uikit/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
import React, { FC } from 'react';
import ReactDOM from 'react-dom';
import React, { FC, useLayoutEffect, useRef, useState } from 'react';
import { useHoverDirty } from 'react-use';
import './Tooltip.scss';

// TODO: put tooltip element outside of parent component (use portal?) + use popper.js to properly position it
const docBody = document.body;

export const Tooltip: FC = ({ children }) => {
const handle = useRef<HTMLDivElement>(null);
const isHovering = useHoverDirty(handle);
const [top, setTop] = useState<number>(0);
const [left, setLeft] = useState<number>(0);

// update tooltip position to show it right below the tooltip handle
useLayoutEffect(() => {
if (isHovering && handle.current) {
const handleRect = handle.current.getBoundingClientRect();
setTop(handleRect.bottom);
setLeft(handleRect.left);
}
}, [isHovering]);

// render tooltip popup via portal to properly show it when any parent element has "overflow: hidden"
return (
<>
<div className="yb-uikit-tooltip">
<div className="yb-uikit-tooltip__handler" />
<div className="yb-uikit-tooltip__content">{children}</div>
</div>
</>
<div className="yb-uikit-tooltip">
<div className="yb-uikit-tooltip__handle" ref={handle} />
{ReactDOM.createPortal(
<div className="yb-uikit-tooltip-popup" style={{ left, top, opacity: isHovering ? 1 : 0 }}>
{children}
</div>,
docBody
)}
</div>
);
};
Loading

0 comments on commit c1fda7f

Please sign in to comment.