mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 05:45:22 +02:00
feat(ui): portainer wizard ui change for ce EE-3576 (#7405)
* ui change for wizard
This commit is contained in:
parent
a7ab0a5662
commit
ee1ee633d7
33 changed files with 272 additions and 77 deletions
|
@ -10,6 +10,8 @@
|
|||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
color: var(--text-boxselector-header);
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.boxselector_header .fa,
|
||||
|
@ -115,6 +117,16 @@
|
|||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.boxselector_wrapper input[type='radio']:not(:disabled) ~ label,
|
||||
.box-selector-item input[type='radio']:not(:disabled) ~ label {
|
||||
background-color: var(--bg-boxselector-color);
|
||||
}
|
||||
|
||||
.boxselector_img_container {
|
||||
line-height: 90px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.box-selector-item p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export function NavTabs({ options, selectedId, onSelect = () => {} }: Props) {
|
|||
const selected = options.find((option) => option.id === selectedId);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="nav-container">
|
||||
<ul className="nav nav-tabs">
|
||||
{options.map((option) => (
|
||||
<li
|
||||
|
@ -49,7 +49,7 @@ export function NavTabs({ options, selectedId, onSelect = () => {} }: Props) {
|
|||
{selected && selected.children && (
|
||||
<div className="tab-content">{selected.children}</div>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
|
||||
function handleSelect(option: Option) {
|
||||
|
|
|
@ -18,18 +18,18 @@
|
|||
position: absolute;
|
||||
content: '';
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
top: 15px;
|
||||
left: -100%;
|
||||
z-index: 2;
|
||||
border-bottom: 5px solid var(--bg-stepper-item-counter);
|
||||
border-bottom: 3px solid var(--border-stepper-color);
|
||||
}
|
||||
|
||||
.step-wrapper::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 5px solid var(--bg-stepper-item-counter);
|
||||
border-bottom: 3px solid var(--border-stepper-color);
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
top: 15px;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
@ -46,11 +46,13 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
background: var(--bg-stepper-item-counter);
|
||||
/* background: var(--ui-white); */
|
||||
background: var(--bg-stepper-color);
|
||||
margin-bottom: 6px;
|
||||
border: 1px solid var(--ui-gray-6);
|
||||
}
|
||||
|
||||
.step-wrapper.active {
|
||||
|
@ -59,27 +61,29 @@
|
|||
}
|
||||
|
||||
.step-wrapper.active .step {
|
||||
background: #337ab7;
|
||||
background: var(--bg-stepper-active-color);
|
||||
border: 2px solid var(--ui-blue-8);
|
||||
}
|
||||
|
||||
.step-wrapper.active .step-counter {
|
||||
color: #fff;
|
||||
color: var(--text-stepper-active-color);
|
||||
}
|
||||
|
||||
.step-wrapper.completed .step {
|
||||
background-color: #48b400;
|
||||
background: var(--bg-stepper-active-color);
|
||||
border: 2px solid var(--ui-blue-8);
|
||||
}
|
||||
|
||||
.step-wrapper.completed .step-counter {
|
||||
color: #fff;
|
||||
color: var(--text-stepper-active-color);
|
||||
}
|
||||
|
||||
.step-wrapper.completed::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-bottom: 5px solid #48b400;
|
||||
border-bottom: 3px solid var(--ui-blue-8);
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
top: 15px;
|
||||
left: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,12 @@ import automode from '@/assets/ico/theme/auto.svg?c';
|
|||
import darkmode from '@/assets/ico/theme/darkmode.svg?c';
|
||||
import lightmode from '@/assets/ico/theme/lightmode.svg?c';
|
||||
import highcontrastmode from '@/assets/ico/theme/highcontrastmode.svg?c';
|
||||
// wizard icons
|
||||
import agent from '@/assets/ico/wizard/agent.svg?c';
|
||||
import api from '@/assets/ico/wizard/api.svg?c';
|
||||
import edgeagent from '@/assets/ico/wizard/edge-agent.svg?c';
|
||||
import cloudimport from '@/assets/ico/wizard/import.svg?c';
|
||||
import socket from '@/assets/ico/wizard/socket.svg?c';
|
||||
// general icons
|
||||
import arrowsupdown from '@/assets/ico/arrows-updown.svg?c';
|
||||
import arrowright from '@/assets/ico/arrow-right-long.svg?c';
|
||||
|
@ -25,6 +31,7 @@ import heartbeat from '@/assets/ico/heartbeat.svg?c';
|
|||
import laptop from '@/assets/ico/laptop.svg?c';
|
||||
import laptopcode from '@/assets/ico/laptop-code.svg?c';
|
||||
import ldap from '@/assets/ico/ldap.svg?c';
|
||||
import magic from '@/assets/ico/magic.svg?c';
|
||||
import magicwand from '@/assets/ico/magic-wand.svg?c';
|
||||
import memory from '@/assets/ico/memory.svg?c';
|
||||
import objectgroup from '@/assets/ico/object-group.svg?c';
|
||||
|
@ -71,6 +78,11 @@ import internal from '@/assets/ico/vendor/internal.svg?c';
|
|||
const placeholder = Placeholder;
|
||||
|
||||
export const SvgIcons = {
|
||||
agent,
|
||||
api,
|
||||
edgeagent,
|
||||
cloudimport,
|
||||
socket,
|
||||
automode,
|
||||
darkmode,
|
||||
lightmode,
|
||||
|
@ -96,6 +108,7 @@ export const SvgIcons = {
|
|||
laptop,
|
||||
laptopcode,
|
||||
ldap,
|
||||
magic,
|
||||
magicwand,
|
||||
memory,
|
||||
objectgroup,
|
||||
|
|
|
@ -46,7 +46,7 @@ export function FileUploadField({
|
|||
</Button>
|
||||
|
||||
<span className="vertical-center">
|
||||
{value ? value.name : <Icon icon="x" feather mode="danger" />}
|
||||
{value ? value.name : <Icon icon="x-circle" feather mode="danger" />}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -33,7 +33,7 @@ export function EnvironmentTypeSelectView() {
|
|||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<Widget>
|
||||
<WidgetTitle icon="fa-magic" title="Environment Wizard" />
|
||||
<WidgetTitle icon="svg-magic" title="Environment Wizard" />
|
||||
<WidgetBody>
|
||||
<EnvironmentSelector
|
||||
value={types}
|
||||
|
|
|
@ -12,6 +12,7 @@ import { Widget, WidgetBody, WidgetTitle } from '@@/Widget';
|
|||
import { PageHeader } from '@@/PageHeader';
|
||||
import { Button } from '@@/buttons';
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
import { environmentTypes } from '../EnvironmentTypeSelectView/environment-types';
|
||||
import { EnvironmentSelectorValue } from '../EnvironmentTypeSelectView/EnvironmentSelector';
|
||||
|
@ -65,7 +66,7 @@ export function EnvironmentCreationView() {
|
|||
|
||||
<div className={styles.wizardWrapper}>
|
||||
<Widget>
|
||||
<WidgetTitle icon="fa-magic" title="Environment Wizard" />
|
||||
<WidgetTitle icon="svg-magic" title="Environment Wizard" />
|
||||
<WidgetBody>
|
||||
<Stepper steps={steps} currentStep={currentStepIndex + 1} />
|
||||
|
||||
|
@ -83,11 +84,11 @@ export function EnvironmentCreationView() {
|
|||
)}
|
||||
>
|
||||
<Button disabled={isFirstStep} onClick={onPreviousClick}>
|
||||
<i className="fas fa-arrow-left space-right" /> Previous
|
||||
<Icon icon="arrow-left" feather /> Previous
|
||||
</Button>
|
||||
<Button onClick={onNextClick}>
|
||||
{isLastStep ? 'Finish' : 'Next'}
|
||||
<i className="fas fa-arrow-right space-left" />
|
||||
{isLastStep ? 'Close' : 'Next'}
|
||||
<Icon icon="arrow-right" feather />
|
||||
</Button>
|
||||
</div>
|
||||
</FormSection>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { LoadingButton } from '@@/buttons/LoadingButton';
|
|||
import { Input } from '@@/form-components/Input';
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { BoxSelector } from '@@/BoxSelector';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
import { NameField, nameValidation } from '../shared/NameField';
|
||||
import { AnalyticsStateKey } from '../types';
|
||||
|
@ -37,7 +38,7 @@ const initialValues: FormValues = {
|
|||
},
|
||||
};
|
||||
|
||||
const options = [buildOption('api', 'fa fa-bolt', 'API', '', 'api')];
|
||||
const options = [buildOption('api', 'svg-api', 'API', '', 'api')];
|
||||
|
||||
interface Props {
|
||||
onCreate(environment: Environment, analytics: AnalyticsStateKey): void;
|
||||
|
@ -116,11 +117,16 @@ export function WizardAzure({ onCreate }: Props) {
|
|||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="vertical-center"
|
||||
loadingText="Connecting environment..."
|
||||
isLoading={mutation.isLoading}
|
||||
disabled={!dirty || !isValid}
|
||||
>
|
||||
<i className="fa fa-plug" aria-hidden="true" /> Connect
|
||||
<Icon
|
||||
icon="svg-plug"
|
||||
className="icon icon-sm vertical-center"
|
||||
/>{' '}
|
||||
Connect
|
||||
</LoadingButton>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { LoadingButton } from '@@/buttons/LoadingButton';
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
import { NameField } from '../../shared/NameField';
|
||||
import { MoreSettingsSection } from '../../shared/MoreSettingsSection';
|
||||
|
@ -76,12 +77,16 @@ export function APIForm({ onCreate }: Props) {
|
|||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="wizard-connect-button"
|
||||
className="wizard-connect-button vertical-center"
|
||||
loadingText="Connecting environment..."
|
||||
isLoading={mutation.isLoading}
|
||||
disabled={!dirty || !isValid}
|
||||
>
|
||||
<i className="fa fa-plug" aria-hidden="true" /> Connect
|
||||
<Icon
|
||||
icon="svg-plug"
|
||||
className="icon icon-sm vertical-center"
|
||||
/>{' '}
|
||||
Connect
|
||||
</LoadingButton>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -59,7 +59,9 @@ function DeployCode({ code }: DeployCodeProps) {
|
|||
<span className="text-muted small">
|
||||
CLI script for installing agent on your environment with Docker Swarm:
|
||||
</span>
|
||||
<Code>{code}</Code>
|
||||
<div className="code-script">
|
||||
<Code>{code}</Code>
|
||||
</div>
|
||||
<CopyButton copyText={code}>Copy command</CopyButton>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ import { LoadingButton } from '@@/buttons/LoadingButton';
|
|||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
import { SwitchField } from '@@/form-components/SwitchField';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
import { NameField } from '../../shared/NameField';
|
||||
import { MoreSettingsSection } from '../../shared/MoreSettingsSection';
|
||||
|
@ -54,12 +55,16 @@ export function SocketForm({ onCreate }: Props) {
|
|||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="wizard-connect-button"
|
||||
className="wizard-connect-button vertical-center"
|
||||
loadingText="Connecting environment..."
|
||||
isLoading={mutation.isLoading}
|
||||
disabled={!dirty || !isValid}
|
||||
>
|
||||
<i className="fa fa-plug" aria-hidden="true" /> Connect
|
||||
<Icon
|
||||
icon="svg-plug"
|
||||
className="icon icon-sm vertical-center"
|
||||
/>{' '}
|
||||
Connect
|
||||
</LoadingButton>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -22,28 +22,28 @@ const defaultOptions: BoxSelectorOption<
|
|||
>[] = [
|
||||
{
|
||||
id: 'agent',
|
||||
icon: 'fa fa-bolt',
|
||||
icon: 'svg-agent',
|
||||
label: 'Agent',
|
||||
description: '',
|
||||
value: 'agent',
|
||||
},
|
||||
{
|
||||
id: 'api',
|
||||
icon: 'fa fa-cloud',
|
||||
icon: 'svg-api',
|
||||
label: 'API',
|
||||
description: '',
|
||||
value: 'api',
|
||||
},
|
||||
{
|
||||
id: 'socket',
|
||||
icon: 'fab fa-docker',
|
||||
icon: 'svg-socket',
|
||||
label: 'Socket',
|
||||
description: '',
|
||||
value: 'socket',
|
||||
},
|
||||
{
|
||||
id: 'edgeAgent',
|
||||
icon: 'fa fa-cloud', // Todo cloud with docker
|
||||
icon: 'svg-edgeagent',
|
||||
label: 'Edge Agent',
|
||||
description: '',
|
||||
value: 'edgeAgent',
|
||||
|
|
|
@ -44,7 +44,7 @@ export function WizardEndpointsList({ environmentIds }: Props) {
|
|||
|
||||
return (
|
||||
<Widget>
|
||||
<WidgetTitle icon="fa-plug" title="New Environments" />
|
||||
<WidgetTitle icon="svg-plug" title="New Environments" />
|
||||
<WidgetBody>
|
||||
{environments.map((environment) => (
|
||||
<div className={styles.wizardListWrapper} key={environment.Id}>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { FormControl } from '@@/form-components/FormControl';
|
|||
import { FormSectionTitle } from '@@/form-components/FormSectionTitle';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
import { Button } from '@@/buttons';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
|
||||
const initialValues = {
|
||||
kubeConfig: '',
|
||||
|
@ -24,26 +25,22 @@ export function KubeConfigTeaserForm() {
|
|||
|
||||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<span className="text-primary">
|
||||
<i
|
||||
className="fa fa-exclamation-circle space-right"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
<span className="text-muted small">
|
||||
Import the
|
||||
<a
|
||||
href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/"
|
||||
target="_blank"
|
||||
className="space-right space-left"
|
||||
rel="noreferrer"
|
||||
>
|
||||
kubeconfig file
|
||||
</a>
|
||||
of an existing Kubernetes cluster located on-premise or on a
|
||||
cloud platform. This will create a corresponding environment in
|
||||
Portainer and install the agent on the cluster. Please ensure:
|
||||
</span>
|
||||
<TextTip color="blue">
|
||||
<span className="text-muted">
|
||||
<a
|
||||
href="https://docs.portainer.io/start/install/agent/kubernetes/import"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="mx-1"
|
||||
>
|
||||
Import the kubeconfig file
|
||||
</a>
|
||||
of an existing Kubernetes cluster located on-premise or on a
|
||||
cloud platform. This will create a corresponding environment
|
||||
in Portainer and install the agent on the cluster. Please
|
||||
ensure:
|
||||
</span>
|
||||
</TextTip>
|
||||
</div>
|
||||
<div className="col-sm-12 text-muted small">
|
||||
<ul className="p-2 pl-4">
|
||||
|
|
|
@ -25,14 +25,14 @@ interface Props {
|
|||
const defaultOptions: BoxSelectorOption<EnvironmentCreationTypes>[] = [
|
||||
{
|
||||
id: 'agent_endpoint',
|
||||
icon: 'fa fa-bolt',
|
||||
icon: 'svg-agent',
|
||||
label: 'Agent',
|
||||
value: EnvironmentCreationTypes.AgentEnvironment,
|
||||
description: '',
|
||||
},
|
||||
{
|
||||
id: 'edgeAgent',
|
||||
icon: 'fa fa-cloud', // Todo cloud with docker
|
||||
icon: 'svg-edgeagent',
|
||||
label: 'Edge Agent',
|
||||
description: '',
|
||||
value: EnvironmentCreationTypes.EdgeAgentEnvironment,
|
||||
|
@ -40,7 +40,7 @@ const defaultOptions: BoxSelectorOption<EnvironmentCreationTypes>[] = [
|
|||
},
|
||||
{
|
||||
id: 'kubeconfig_endpoint',
|
||||
icon: 'fas fa-cloud-upload-alt',
|
||||
icon: 'svg-cloudimport',
|
||||
label: 'Import',
|
||||
value: EnvironmentCreationTypes.KubeConfigEnvironment,
|
||||
description: 'Import an existing Kubernetes config',
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Environment } from '@/portainer/environments/types';
|
|||
import { CreateAgentEnvironmentValues } from '@/portainer/environments/environment.service/create';
|
||||
|
||||
import { LoadingButton } from '@@/buttons/LoadingButton';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
import { NameField } from '../NameField';
|
||||
import { MoreSettingsSection } from '../MoreSettingsSection';
|
||||
|
@ -53,12 +54,16 @@ export function AgentForm({ onCreate, showGpus = false }: Props) {
|
|||
<div className="form-group">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="wizard-connect-button"
|
||||
className="wizard-connect-button vertical-center"
|
||||
loadingText="Connecting environment..."
|
||||
isLoading={mutation.isLoading}
|
||||
disabled={!dirty || !isValid}
|
||||
>
|
||||
<i className="fa fa-plug" aria-hidden="true" /> Connect
|
||||
<Icon
|
||||
icon="svg-plug"
|
||||
className="icon icon-sm vertical-center"
|
||||
/>{' '}
|
||||
Connect
|
||||
</LoadingButton>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,6 +8,7 @@ import { useCreateEdgeDeviceParam } from '@/react/portainer/environments/wizard/
|
|||
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
import { LoadingButton } from '@@/buttons/LoadingButton';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
import { MoreSettingsSection } from '../../MoreSettingsSection';
|
||||
import { Hardware } from '../../Hardware/Hardware';
|
||||
|
@ -55,11 +56,15 @@ export function EdgeAgentForm({ onCreate, readonly, showGpus = false }: Props) {
|
|||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<LoadingButton
|
||||
className="vertical-center"
|
||||
isLoading={createMutation.isLoading}
|
||||
loadingText="Creating environment..."
|
||||
disabled={!isValid}
|
||||
>
|
||||
<i className="fa fa-plug space-right" />
|
||||
<Icon
|
||||
icon="svg-plug"
|
||||
className="icon icon-sm vertical-center"
|
||||
/>
|
||||
Create
|
||||
</LoadingButton>
|
||||
</div>
|
||||
|
|
|
@ -23,7 +23,7 @@ export function HomeView() {
|
|||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<Widget>
|
||||
<WidgetTitle title="Environment Wizard" icon="fa-magic" />
|
||||
<WidgetTitle title="Environment Wizard" icon="svg-magic" />
|
||||
<WidgetBody>
|
||||
<div className="row">
|
||||
<div className="col-sm-12 form-section-title">
|
||||
|
@ -32,7 +32,7 @@ export function HomeView() {
|
|||
<div className="text-muted small">
|
||||
{localEnvironmentAdded.status === 'success' && (
|
||||
<p>
|
||||
We have connected your local environment of
|
||||
We have connected your local environment of{' '}
|
||||
{getTypeLabel(localEnvironmentAdded.type)} to Portainer.
|
||||
</p>
|
||||
)}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue