1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

fix(be-teaser): mute styles [EE-6035] (#10349)

This commit is contained in:
Ali 2023-09-24 19:56:09 +01:00 committed by GitHub
parent ffac83864d
commit 13c48ab961
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 604 additions and 616 deletions

View file

@ -1,5 +1,6 @@
.be-indicator {
border: solid 1px var(--BE-only);
@apply border-solid border border-gray-6;
@apply text-gray-6 text-xs;
border-radius: 15px;
padding: 5px 10px;
font-weight: 400;
@ -9,11 +10,12 @@
}
.be-indicator .be-indicator-icon {
@apply text-black th-highcontrast:text-white th-dark:text-blue-8;
@apply text-inherit;
}
.be-indicator:hover {
@apply no-underline;
@apply underline;
@apply border-blue-9 text-blue-9;
}
.be-indicator:hover .be-indicator-label {
@ -21,5 +23,5 @@
}
.be-indicator-container {
border: solid 1px var(--BE-only);
@apply border-solid border border-gray-6;
}

View file

@ -29,16 +29,14 @@ export function BEFeatureIndicator({
}
return (
<a
className={clsx('be-indicator vertical-center', className)}
className={clsx('be-indicator vertical-center text-xs', className)}
href={url}
target="_blank"
rel="noopener noreferrer"
>
{children}
{showIcon && <Icon icon={Briefcase} className="be-indicator-icon mr-1" />}
<span className="be-indicator-label break-words">
Business Edition Feature
</span>
<span className="be-indicator-label break-words">Business Feature</span>
</a>
);
}

View file

@ -1,16 +1,18 @@
import clsx from 'clsx';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { isLimitedToBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { Tooltip } from '@@/Tip/Tooltip';
import { BEFeatureIndicator } from '.';
import { BEFeatureIndicator } from './BEFeatureIndicator';
export function BEOverlay({
featureId,
children,
className,
}: {
featureId: FeatureId;
children: React.ReactNode;
className?: string;
}) {
const isLimited = isLimitedToBE(featureId);
if (!isLimited) {
@ -19,13 +21,10 @@ export function BEOverlay({
return (
<div className="be-indicator-container limited-be">
<div className="overlay">
<div className="limited-be-link vertical-center">
<BEFeatureIndicator featureId={FeatureId.CA_FILE} />
<Tooltip message="This feature is currently limited to Business Edition users only. " />
</div>
<div className="limited-be-content">{children}</div>
<div className="limited-be-link vertical-center">
<BEFeatureIndicator featureId={featureId} />
</div>
<div className={clsx('limited-be-content', className)}>{children}</div>
</div>
);
}

View file

@ -1,4 +1,4 @@
import { ReactNode } from 'react';
import { Briefcase } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
@ -11,7 +11,6 @@ interface Props {
message: string;
buttonText: string;
className?: string;
icon?: ReactNode;
buttonClassName?: string;
}
@ -21,7 +20,6 @@ export function BETeaserButton({
message,
buttonText,
className,
icon,
buttonClassName,
}: Props) {
return (
@ -34,9 +32,9 @@ export function BETeaserButton({
<span>
<Button
className={buttonClassName}
icon={icon}
icon={Briefcase}
type="button"
color="warninglight"
color="default"
size="small"
onClick={() => {}}
disabled

View file

@ -38,12 +38,12 @@
padding-left: 20px;
}
/* used for BE teaser. Dark theme specs defined by EE-5621 */
/* used for BE teaser */
.box-selector-item.limited.business label,
.box-selector-item.limited.business input:checked + label {
@apply border-warning-7 bg-warning-1 text-black;
@apply th-dark:border-blue-8 th-dark:bg-[color:var(--bg-BE-only)] th-dark:text-white;
@apply th-highcontrast:bg-warning-8 th-highcontrast:bg-opacity-10 th-highcontrast:text-white;
@apply border-gray-6 bg-gray-6 bg-opacity-10;
@apply th-dark:border-gray-6 th-dark:bg-gray-6 th-dark:bg-opacity-10;
@apply th-highcontrast:border-gray-6 th-highcontrast:bg-gray-6 th-highcontrast:bg-opacity-10;
filter: none;
}

View file

@ -9,7 +9,7 @@ import { getFeatureDetails } from '@@/BEFeatureIndicator/utils';
import styles from './BoxSelectorItem.module.css';
import { BoxSelectorOption, Value } from './types';
import { LimitedToBeIndicator } from './LimitedToBeIndicator';
import { LimitedToBeBoxSelectorIndicator } from './LimitedToBeBoxSelectorIndicator';
import { BoxOption } from './BoxOption';
import { LogoIcon } from './LogoIcon';
@ -40,8 +40,6 @@ export function BoxSelectorItem<T extends Value>({
option.feature
);
const beIndicatorTooltipId = `box-selector-item-${radioName}-${option.id}-limited`;
const ContentBox = slim ? 'div' : Fragment;
return (
@ -59,14 +57,9 @@ export function BoxSelectorItem<T extends Value>({
type={type}
checkIcon={checkIcon}
>
{limitedToBE && (
<LimitedToBeIndicator
tooltipId={beIndicatorTooltipId}
url={featureUrl}
/>
)}
{limitedToBE && <LimitedToBeBoxSelectorIndicator url={featureUrl} />}
<div
className={clsx('flex gap-2', {
className={clsx('flex min-w-[140px] gap-2', {
'opacity-30': limitedToBE,
'h-full flex-col justify-start': !slim,
'slim items-center': slim,

View file

@ -0,0 +1,30 @@
import { Briefcase } from 'lucide-react';
import { Icon } from '@@/Icon';
import { Tooltip } from '@@/Tip/Tooltip';
interface Props {
url?: string;
}
export function LimitedToBeBoxSelectorIndicator({ url }: Props) {
return (
<div className="absolute left-0 top-0 w-full">
<div className="mx-auto flex max-w-fit items-center rounded-b-lg border border-t-0 border-solid border-gray-6 bg-transparent px-3 py-1 text-gray-6">
<a
className="inline-flex items-center text-xs text-gray-6"
href={url}
target="_blank"
rel="noreferrer"
>
<Icon icon={Briefcase} className="!mr-1" />
<span>Business Feature</span>
</a>
<Tooltip
size="sm"
message="Select this option to preview this business feature."
/>
</div>
</div>
);
}

View file

@ -1,37 +0,0 @@
import { HelpCircle } from 'lucide-react';
import clsx from 'clsx';
import { TooltipWithChildren } from '@@/Tip/TooltipWithChildren';
interface Props {
tooltipId: string;
url?: string;
}
export function LimitedToBeIndicator({ tooltipId, url }: Props) {
return (
<div className="absolute left-0 top-0 w-full">
<div className="mx-auto flex max-w-fit items-center gap-1 rounded-b-lg bg-warning-4 px-3 py-1 text-sm th-dark:bg-[color:var(--bg-BE-only)]">
<a
className="text-warning-9 th-dark:text-blue-8"
href={url}
target="_blank"
rel="noreferrer"
>
BE Feature
</a>
<TooltipWithChildren
position="bottom"
className={clsx(tooltipId, 'portainer-tooltip')}
heading="Business Edition feature."
message="This feature is currently limited to Business Edition users only."
>
<HelpCircle
className="ml-1 !text-warning-7 th-dark:!text-blue-8"
aria-hidden="true"
/>
</TooltipWithChildren>
</div>
</div>
);
}

View file

@ -1,14 +1,26 @@
import { HelpCircle } from 'lucide-react';
import { ReactNode, useMemo } from 'react';
import sanitize from 'sanitize-html';
import clsx from 'clsx';
import { TooltipWithChildren, Position } from '../TooltipWithChildren';
type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
const sizeClasses: Record<Size, string> = {
xs: 'text-xs',
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
xl: 'text-xl',
};
export interface Props {
position?: Position;
message: ReactNode;
className?: string;
setHtmlMessage?: boolean;
size?: Size;
}
export function Tooltip({
@ -16,6 +28,7 @@ export function Tooltip({
position = 'bottom',
className,
setHtmlMessage,
size = 'md',
}: Props) {
// allow angular views to set html messages for the tooltip
const htmlMessage = useMemo(() => {
@ -27,14 +40,14 @@ export function Tooltip({
}, [setHtmlMessage, message]);
return (
<TooltipWithChildren
message={htmlMessage || message}
position={position}
className={className}
>
<span className="inline-flex text-base">
<HelpCircle className="lucide ml-1" aria-hidden="true" />
</span>
</TooltipWithChildren>
<span className={clsx('ml-1 inline-flex items-center', sizeClasses[size])}>
<TooltipWithChildren
message={htmlMessage || message}
position={position}
className={className}
>
<HelpCircle className="lucide" aria-hidden="true" />
</TooltipWithChildren>
</span>
);
}

View file

@ -36,9 +36,5 @@
}
.tooltip-beteaser {
@apply text-warning-5 th-dark:text-blue-8;
}
.tooltip-beteaser:hover {
@apply text-warning-5 th-dark:text-blue-8;
@apply text-blue-8 hover:text-blue-9;
}

View file

@ -49,7 +49,7 @@ export function TooltipWithChildren({
rel="noreferrer"
className={styles.tooltipBeteaser}
>
Business Edition Only
Business Feature
</a>
)}
</div>

View file

@ -1,5 +1,3 @@
import { Plus } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { BETeaserButton } from '@@/BETeaserButton';
@ -42,7 +40,6 @@ export function AnnotationsBeTeaser() {
message="Allows specifying of annotations on this resource."
featureId={FeatureId.K8S_ANNOTATIONS}
buttonClassName="!ml-0"
icon={Plus}
/>
</div>
</div>

View file

@ -1,5 +1,3 @@
import { RefreshCw } from 'lucide-react';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { BETeaserButton } from '@@/BETeaserButton';
@ -10,7 +8,6 @@ export function RestartApplicationButton() {
buttonClassName="!ml-0"
data-cy="k8sAppDetail-restartButton"
heading="Rolling restart"
icon={RefreshCw}
featureId={FeatureId.K8S_ROLLING_RESTART}
message="A rolling restart of the application is performed."
buttonText="Rolling restart"

View file

@ -81,7 +81,7 @@ export function KubeConfigTeaserForm() {
<div className="form-group">
<div className="col-sm-12">
<LoadingButton
className="wizard-connect-button"
className="wizard-connect-button !ml-0"
loadingText="Connecting environment..."
isLoading={false}
disabled

View file

@ -11,7 +11,7 @@ import EdgeAgentAsyncIcon from '@/react/edge/components/edge-agent-async.svg?c';
import { BoxSelectorOption } from '@@/BoxSelector/types';
import { BoxSelector } from '@@/BoxSelector';
import { BEFeatureIndicator } from '@@/BEFeatureIndicator';
import { BEOverlay } from '@@/BEFeatureIndicator/BEOverlay';
import { AnalyticsStateKey } from '../types';
import { EdgeAgentTab } from '../shared/EdgeAgentTab';
@ -112,11 +112,10 @@ export function WizardKubernetes({ onCreate }: Props) {
);
case 'kubeconfig':
return (
<div className="border border-solid border-orange-1 px-1 py-5">
<BEFeatureIndicator
featureId={options.find((o) => o.value === type)?.feature}
/>
<KubeConfigTeaserForm />
<div className="mb-3">
<BEOverlay featureId={FeatureId.K8S_CREATE_FROM_KUBECONFIG}>
<KubeConfigTeaserForm />
</BEOverlay>
</div>
);
default:

View file

@ -10,17 +10,19 @@ button.limited-be,
button[disabled].limited-be.oauth-save-settings-button {
background-color: var(--BE-only);
border-color: var(--BE-only);
margin-left: 0px;
}
button.limited-be.oauth-save-settings-button {
background-color: var(--blue-2);
border-color: transparent;
margin-left: 0px;
}
ng-form.limited-be,
form.limited-be,
div.limited-be {
border: solid 2px var(--BE-only);
border: solid 1px var(--BE-only);
border-radius: 8px;
pointer-events: none;
touch-action: none;
@ -28,49 +30,31 @@ div.limited-be {
}
.limited-be-content {
background: rgba(247, 144, 9, 0.1);
opacity: 0.5;
padding: 10px;
@apply border-gray-6 p-2.5 text-xs opacity-50;
}
.limited-be-link {
padding: 10px;
width: inherit;
z-index: 5;
position: relative;
width: 270px;
height: 40px;
top: 0px;
right: 0px;
float: right;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
@apply bg-warning-5 text-warning-9;
@apply th-dark:bg-[color:var(--bg-BE-only)] th-dark:text-blue-8;
padding: 5px 10px;
touch-action: auto;
cursor: hand;
pointer-events: auto;
}
.limited-be-link a {
@apply pointer-events-auto cursor-pointer;
@apply text-warning-9 th-dark:text-blue-8;
@apply text-gray-6;
}
.limited-be-link a:hover {
@apply text-warning-9 underline th-dark:text-blue-8;
}
.overlay {
@apply bg-center bg-no-repeat;
@apply bg-[url(~@/assets/ico/lock.svg)] th-dark:bg-[url(~@/assets/ico/lock-2.svg)];
}
.limited-be input,
.limited-be .widget-body {
background: rgba(247, 144, 9, 0.05);
@apply th-dark:bg-[color:var(--bg-BE-only)];
@apply underline;
@apply border-blue-9 text-blue-9;
}
.form-control.limited-be[disabled] {

View file

@ -13,6 +13,7 @@ import { FormControl } from '@@/form-components/FormControl';
import { LoadingButton } from '@@/buttons/LoadingButton';
import { Input } from '@@/form-components/Input';
import { SwitchField } from '@@/form-components/SwitchField';
import { BEOverlay } from '@@/BEFeatureIndicator/BEOverlay';
import {
useBackupS3Settings,
@ -57,159 +58,159 @@ export function BackupS3Form() {
validateOnMount
>
{({ values, errors, isSubmitting, setFieldValue, isValid }) => (
<Form className="form-horizontal">
<div className="form-group">
<div className="col-sm-12">
<SwitchField
name="schedule-automatic-backup"
labelClass="col-sm-3 col-lg-2"
label="Schedule automatic backups"
checked={values.scheduleAutomaticBackup}
featureId={FeatureId.S3_BACKUP_SETTING}
onChange={(e) => setFieldValue('scheduleAutomaticBackup', e)}
/>
<BEOverlay featureId={FeatureId.S3_BACKUP_SETTING}>
<Form className="form-horizontal">
<div className="form-group">
<div className="col-sm-12">
<SwitchField
name="schedule-automatic-backup"
labelClass="col-sm-3 col-lg-2"
label="Schedule automatic backups"
checked={values.scheduleAutomaticBackup}
onChange={(e) => setFieldValue('scheduleAutomaticBackup', e)}
/>
</div>
</div>
</div>
{values.scheduleAutomaticBackup && (
{values.scheduleAutomaticBackup && (
<FormControl
inputId="cron_rule"
label="Cron rule"
size="small"
errors={errors.cronRule}
required
>
<Field
id="cron_rule"
name="cronRule"
type="text"
as={Input}
placeholder="0 2 * * *"
data-cy="settings-backupCronRuleInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
)}
<FormControl
inputId="cron_rule"
label="Cron rule"
size="small"
errors={errors.cronRule}
required
label="Access key ID"
inputId="access_key_id"
errors={errors.accessKeyID}
>
<Field
id="cron_rule"
name="cronRule"
id="access_key_id"
name="accessKeyID"
type="text"
as={Input}
placeholder="0 2 * * *"
data-cy="settings-backupCronRuleInput"
data-cy="settings-accessKeyIdInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
)}
<FormControl
label="Access key ID"
inputId="access_key_id"
errors={errors.accessKeyID}
>
<Field
id="access_key_id"
name="accessKeyID"
type="text"
as={Input}
data-cy="settings-accessKeyIdInput"
className={clsx({ 'limited-be': limitedToBE })}
<FormControl
label="Secret access key"
inputId="secret_access_key"
errors={errors.secretAccessKey}
>
<Field
id="secret_access_key"
name="secretAccessKey"
type="password"
as={Input}
data-cy="settings-secretAccessKeyInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<FormControl label="Region" inputId="region" errors={errors.region}>
<Field
id="region"
name="region"
type="text"
as={Input}
placeholder="default region is us-east-1 if left empty"
data-cy="settings-backupRegionInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<FormControl
label="Bucket name"
inputId="bucket_name"
errors={errors.bucketName}
>
<Field
id="bucket_name"
name="bucketName"
type="text"
as={Input}
data-cy="settings-backupBucketNameInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<FormControl
label="S3 compatible host"
inputId="s3_compatible_host"
tooltip="Hostname of a S3 service"
errors={errors.s3CompatibleHost}
>
<Field
id="s3_compatible_host"
name="s3CompatibleHost"
type="text"
as={Input}
placeholder="leave empty for AWS S3"
data-cy="settings-backupS3CompatibleHostInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<SecurityFieldset
switchDataCy="settings-passwordProtectToggleS3"
inputDataCy="settings-backups3pw"
disabled={limitedToBE}
/>
</FormControl>
<FormControl
label="Secret access key"
inputId="secret_access_key"
errors={errors.secretAccessKey}
>
<Field
id="secret_access_key"
name="secretAccessKey"
type="password"
as={Input}
data-cy="settings-secretAccessKeyInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<FormControl label="Region" inputId="region" errors={errors.region}>
<Field
id="region"
name="region"
type="text"
as={Input}
placeholder="default region is us-east-1 if left empty"
data-cy="settings-backupRegionInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<FormControl
label="Bucket name"
inputId="bucket_name"
errors={errors.bucketName}
>
<Field
id="bucket_name"
name="bucketName"
type="text"
as={Input}
data-cy="settings-backupBucketNameInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<FormControl
label="S3 compatible host"
inputId="s3_compatible_host"
tooltip="Hostname of a S3 service"
errors={errors.s3CompatibleHost}
>
<Field
id="s3_compatible_host"
name="s3CompatibleHost"
type="text"
as={Input}
placeholder="leave empty for AWS S3"
data-cy="settings-backupS3CompatibleHostInput"
className={clsx({ 'limited-be': limitedToBE })}
disabled={limitedToBE}
/>
</FormControl>
<SecurityFieldset
switchDataCy="settings-passwordProtectToggleS3"
inputDataCy="settings-backups3pw"
disabled={limitedToBE}
/>
<div className="form-group">
<div className="col-sm-12">
<LoadingButton
type="button"
loadingText="Exporting..."
isLoading={isSubmitting}
className={clsx('!ml-0', { 'limited-be': limitedToBE })}
disabled={!isValid || limitedToBE}
data-cy="settings-exportBackupS3Button"
icon={Upload}
onClick={() => {
handleExport(values);
}}
>
Export backup
</LoadingButton>
<div className="form-group">
<div className="col-sm-12">
<LoadingButton
type="button"
loadingText="Exporting..."
isLoading={isSubmitting}
className={clsx('!ml-0', { 'limited-be': limitedToBE })}
disabled={!isValid || limitedToBE}
data-cy="settings-exportBackupS3Button"
icon={Upload}
onClick={() => {
handleExport(values);
}}
>
Export backup
</LoadingButton>
</div>
</div>
</div>
<div className="form-group">
<hr />
<div className="col-sm-12">
<LoadingButton
loadingText="Saving settings..."
isLoading={isSubmitting}
className={clsx('!ml-0', { 'limited-be': limitedToBE })}
disabled={!isValid || limitedToBE}
data-cy="settings-saveBackupSettingsButton"
>
Save backup settings
</LoadingButton>
<div className="form-group">
<div className="col-sm-12">
<LoadingButton
loadingText="Saving settings..."
isLoading={isSubmitting}
className={clsx('!ml-0', { 'limited-be': limitedToBE })}
disabled={!isValid || limitedToBE}
data-cy="settings-saveBackupSettingsButton"
>
Save backup settings
</LoadingButton>
</div>
</div>
</div>
</Form>
</Form>
</BEOverlay>
)}
</Formik>
);

View file

@ -30,7 +30,7 @@ export function HelmCertPanel() {
};
return (
<BEOverlay featureId={FeatureId.CA_FILE}>
<BEOverlay featureId={FeatureId.CA_FILE} className="!p-0">
<Widget>
<Widget.Title
icon={Key}

View file

@ -78,8 +78,7 @@ function UpgradeBEBanner() {
<ArrowUpCircle
className={clsx(
'lucide text-lg',
'fill-warning-6 stroke-[#023959] th-dark:stroke-black',
'th-highcontrast:fill-warning-6 th-highcontrast:stroke-black'
'fill-gray-6 stroke-[#023959] th-dark:stroke-black th-highcontrast:stroke-black'
)}
/>
{isSidebarOpen && <>Upgrade to Business Edition</>}