mirror of https://github.com/portainer/portainer
				
				
				
			fix(home): dark mode for edit buttons [EE-4828] (#8241)
							parent
							
								
									adf92ce5e0
								
							
						
					
					
						commit
						5942f4ff58
					
				| 
						 | 
				
			
			@ -210,25 +210,12 @@ input[type='checkbox'] {
 | 
			
		|||
  margin-right: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blocklist-item--disabled {
 | 
			
		||||
  cursor: auto;
 | 
			
		||||
  background-color: var(--grey-12);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blocklist-item--selected {
 | 
			
		||||
  background-color: var(--bg-blocklist-item-selected-color);
 | 
			
		||||
  border: 2px solid var(--border-blocklist-item-selected-color);
 | 
			
		||||
  color: var(--text-blocklist-item-selected-color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blocklist-item:not(.blocklist-item-not-interactive):hover {
 | 
			
		||||
  @apply border border-blue-7;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
 | 
			
		||||
  background-color: var(--bg-blocklist-hover-color);
 | 
			
		||||
  color: var(--text-blocklist-hover-color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blocklist-item-box {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -222,7 +222,6 @@
 | 
			
		|||
  --border-table-color: var(--grey-19);
 | 
			
		||||
  --border-table-top-color: var(--grey-19);
 | 
			
		||||
  --border-datatable-top-color: var(--grey-10);
 | 
			
		||||
  --border-blocklist-color: var(--grey-44);
 | 
			
		||||
  --border-input-group-addon-color: var(--grey-44);
 | 
			
		||||
  --border-btn-default-color: var(--grey-44);
 | 
			
		||||
  --border-boxselector-color: var(--grey-6);
 | 
			
		||||
| 
						 | 
				
			
			@ -231,7 +230,6 @@
 | 
			
		|||
  --border-navtabs-color: var(--ui-white);
 | 
			
		||||
  --border-codemirror-cursor-color: var(--black-color);
 | 
			
		||||
  --border-pre-color: var(--grey-43);
 | 
			
		||||
  --border-blocklist-item-selected-color: var(--grey-46);
 | 
			
		||||
  --border-pagination-span-color: var(--ui-white);
 | 
			
		||||
  --border-pagination-hover-color: var(--ui-white);
 | 
			
		||||
  --border-panel-color: var(--white-color);
 | 
			
		||||
| 
						 | 
				
			
			@ -245,6 +243,7 @@
 | 
			
		|||
  --border-sortbutton: var(--grey-8);
 | 
			
		||||
  --border-bootbox: var(--ui-gray-5);
 | 
			
		||||
  --border-blocklist: var(--ui-gray-5);
 | 
			
		||||
  --border-blocklist-item-selected-color: var(--grey-46);
 | 
			
		||||
  --border-widget: var(--ui-gray-5);
 | 
			
		||||
  --border-nav-container-color: var(--ui-gray-5);
 | 
			
		||||
  --border-stepper-color: var(--ui-gray-4);
 | 
			
		||||
| 
						 | 
				
			
			@ -408,7 +407,6 @@
 | 
			
		|||
  --border-table-color: var(--grey-3);
 | 
			
		||||
  --border-table-top-color: var(--grey-3);
 | 
			
		||||
  --border-datatable-top-color: var(--grey-3);
 | 
			
		||||
  --border-blocklist-color: var(--grey-3);
 | 
			
		||||
  --border-input-group-addon-color: var(--grey-38);
 | 
			
		||||
  --border-btn-default-color: var(--grey-38);
 | 
			
		||||
  --border-boxselector-color: var(--grey-1);
 | 
			
		||||
| 
						 | 
				
			
			@ -417,6 +415,7 @@
 | 
			
		|||
  --border-navtabs-color: var(--grey-38);
 | 
			
		||||
  --border-codemirror-cursor-color: var(--white-color);
 | 
			
		||||
  --border-pre-color: var(--grey-3);
 | 
			
		||||
  --border-blocklist: var(--ui-gray-9);
 | 
			
		||||
  --border-blocklist-item-selected-color: var(--grey-38);
 | 
			
		||||
  --border-pagination-span-color: var(--grey-1);
 | 
			
		||||
  --border-pagination-hover-color: var(--grey-3);
 | 
			
		||||
| 
						 | 
				
			
			@ -430,7 +429,6 @@
 | 
			
		|||
  --border-modal: 0px;
 | 
			
		||||
  --border-sortbutton: var(--grey-3);
 | 
			
		||||
  --border-bootbox: var(--ui-gray-9);
 | 
			
		||||
  --border-blocklist: var(--ui-gray-9);
 | 
			
		||||
  --border-widget: var(--grey-3);
 | 
			
		||||
  --border-pagination-color: var(--grey-1);
 | 
			
		||||
  --border-nav-container-color: var(--ui-gray-neutral-8);
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +598,6 @@
 | 
			
		|||
  --border-pre-color: var(--grey-3);
 | 
			
		||||
  --border-codemirror-cursor-color: var(--white-color);
 | 
			
		||||
  --border-modal: 1px solid var(--white-color);
 | 
			
		||||
  --border-blocklist-color: var(--white-color);
 | 
			
		||||
  --border-sortbutton: var(--black-color);
 | 
			
		||||
  --border-bootbox: var(--black-color);
 | 
			
		||||
  --border-blocklist: var(--white-color);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@ export function LinkButton({
 | 
			
		|||
  return (
 | 
			
		||||
    <Button
 | 
			
		||||
      title={title}
 | 
			
		||||
      size="medium"
 | 
			
		||||
      // eslint-disable-next-line react/jsx-props-no-spreading
 | 
			
		||||
      {...props}
 | 
			
		||||
      className={clsx(className, '!m-0 no-link')}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,12 @@ export function EditButtons({ environment }: { environment: Environment }) {
 | 
			
		|||
  const isEdgeAsync = checkEdgeAsync(environment);
 | 
			
		||||
 | 
			
		||||
  const configRoute = getConfigRoute(environment);
 | 
			
		||||
 | 
			
		||||
  const buttonsClasses = clsx(
 | 
			
		||||
    'w-full h-full !ml-0 !rounded-none',
 | 
			
		||||
    'hover:bg-gray-3 th-dark:hover:bg-gray-9 th-highcontrast:hover:bg-white'
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ButtonsGrid className="w-11 ml-3">
 | 
			
		||||
      <LinkButton
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +35,7 @@ export function EditButtons({ environment }: { environment: Environment }) {
 | 
			
		|||
        color="none"
 | 
			
		||||
        icon={Edit2}
 | 
			
		||||
        size="medium"
 | 
			
		||||
        className="w-full h-full !ml-0 hover:bg-gray-3 !rounded-none"
 | 
			
		||||
        className={buttonsClasses}
 | 
			
		||||
        title="Edit"
 | 
			
		||||
      />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +46,7 @@ export function EditButtons({ environment }: { environment: Environment }) {
 | 
			
		|||
        color="none"
 | 
			
		||||
        icon={Settings}
 | 
			
		||||
        size="medium"
 | 
			
		||||
        className="w-full h-full !ml-0 hover:bg-gray-3 !rounded-none"
 | 
			
		||||
        className={buttonsClasses}
 | 
			
		||||
        title="Configuration"
 | 
			
		||||
      />
 | 
			
		||||
    </ButtonsGrid>
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +85,9 @@ function ButtonsGrid({
 | 
			
		|||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      className={clsx(
 | 
			
		||||
        'grid border border-solid border-gray-5 rounded-r-lg',
 | 
			
		||||
        'grid border border-solid rounded-r-lg',
 | 
			
		||||
        'border-gray-5 th-dark:border-gray-9 th-highcontrast:border-white',
 | 
			
		||||
        'overflow-hidden',
 | 
			
		||||
        className
 | 
			
		||||
      )}
 | 
			
		||||
    >
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +95,7 @@ function ButtonsGrid({
 | 
			
		|||
        <div
 | 
			
		||||
          key={index}
 | 
			
		||||
          className={clsx({
 | 
			
		||||
            'border-0 border-b border-solid border-b-gray-5':
 | 
			
		||||
            'border-0 border-b border-solid border-b-inherit':
 | 
			
		||||
              index < children.length - 1,
 | 
			
		||||
          })}
 | 
			
		||||
        >
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import { History, Wifi, WifiOff } from 'lucide-react';
 | 
			
		||||
import { History, Wifi, WifiOff, X } from 'lucide-react';
 | 
			
		||||
import clsx from 'clsx';
 | 
			
		||||
 | 
			
		||||
import { Environment } from '@/react/portainer/environments/types';
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -9,16 +10,19 @@ import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
 | 
			
		|||
 | 
			
		||||
import { Icon } from '@@/Icon';
 | 
			
		||||
import { LinkButton } from '@@/LinkButton';
 | 
			
		||||
import { Button } from '@@/buttons';
 | 
			
		||||
 | 
			
		||||
type BrowseStatus = 'snapshot' | 'connected' | 'disconnected';
 | 
			
		||||
 | 
			
		||||
export function EnvironmentBrowseButtons({
 | 
			
		||||
  environment,
 | 
			
		||||
  onClickBrowse,
 | 
			
		||||
  onClickDisconnect,
 | 
			
		||||
  isActive,
 | 
			
		||||
}: {
 | 
			
		||||
  environment: Environment;
 | 
			
		||||
  onClickBrowse(): void;
 | 
			
		||||
  onClickDisconnect(): void;
 | 
			
		||||
  isActive: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
  const isEdgeAsync = checkEdgeAsync(environment);
 | 
			
		||||
| 
						 | 
				
			
			@ -26,35 +30,60 @@ export function EnvironmentBrowseButtons({
 | 
			
		|||
 | 
			
		||||
  const dashboardRoute = getDashboardRoute(environment);
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="flex flex-col gap-1 justify-center [&>*]:h-1/3 h-24">
 | 
			
		||||
      {isBE && (
 | 
			
		||||
    <div className="flex flex-col gap-2 justify-center [&>*]:h-1/3 h-24 w-full">
 | 
			
		||||
      {isBE &&
 | 
			
		||||
        (browseStatus !== 'snapshot' ? (
 | 
			
		||||
          <LinkButton
 | 
			
		||||
            icon={History}
 | 
			
		||||
            disabled={!isEdgeAsync}
 | 
			
		||||
            to="edge.browse.dashboard"
 | 
			
		||||
            params={{
 | 
			
		||||
              environmentId: environment.Id,
 | 
			
		||||
            }}
 | 
			
		||||
            size="medium"
 | 
			
		||||
            color="light"
 | 
			
		||||
            className="w-full !py-0 !m-0"
 | 
			
		||||
          >
 | 
			
		||||
            Browse snapshot
 | 
			
		||||
          </LinkButton>
 | 
			
		||||
        ) : (
 | 
			
		||||
          <Button
 | 
			
		||||
            icon={X}
 | 
			
		||||
            onClick={onClickDisconnect}
 | 
			
		||||
            className="w-full !py-0 !m-0 opacity-60"
 | 
			
		||||
            size="medium"
 | 
			
		||||
            color="light"
 | 
			
		||||
          >
 | 
			
		||||
            Close snapshot
 | 
			
		||||
          </Button>
 | 
			
		||||
        ))}
 | 
			
		||||
 | 
			
		||||
      {browseStatus !== 'connected' ? (
 | 
			
		||||
        <LinkButton
 | 
			
		||||
          icon={History}
 | 
			
		||||
          disabled={!isEdgeAsync || browseStatus === 'snapshot'}
 | 
			
		||||
          to="edge.browse.dashboard"
 | 
			
		||||
          params={{
 | 
			
		||||
            environmentId: environment.Id,
 | 
			
		||||
          }}
 | 
			
		||||
          color="light"
 | 
			
		||||
          title="Live connection is not available for async environments"
 | 
			
		||||
          icon={Wifi}
 | 
			
		||||
          disabled={isEdgeAsync}
 | 
			
		||||
          to={dashboardRoute.to}
 | 
			
		||||
          params={dashboardRoute.params}
 | 
			
		||||
          size="medium"
 | 
			
		||||
          onClick={onClickBrowse}
 | 
			
		||||
          color="primary"
 | 
			
		||||
          className="w-full !py-0 !m-0"
 | 
			
		||||
        >
 | 
			
		||||
          Browse snapshot
 | 
			
		||||
          Live connect
 | 
			
		||||
        </LinkButton>
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Button
 | 
			
		||||
          icon={WifiOff}
 | 
			
		||||
          onClick={onClickDisconnect}
 | 
			
		||||
          className="w-full !py-0 !m-0 opacity-60"
 | 
			
		||||
          size="medium"
 | 
			
		||||
          color="primary"
 | 
			
		||||
        >
 | 
			
		||||
          Disconnect
 | 
			
		||||
        </Button>
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
      <LinkButton
 | 
			
		||||
        title="Live connection is not available for async environments"
 | 
			
		||||
        icon={Wifi}
 | 
			
		||||
        disabled={isEdgeAsync || browseStatus === 'connected'}
 | 
			
		||||
        to={dashboardRoute.to}
 | 
			
		||||
        params={dashboardRoute.params}
 | 
			
		||||
        onClick={onClickBrowse}
 | 
			
		||||
        color="primary"
 | 
			
		||||
        className="w-full !py-0 !m-0"
 | 
			
		||||
      >
 | 
			
		||||
        Live connect
 | 
			
		||||
      </LinkButton>
 | 
			
		||||
 | 
			
		||||
      <BrowseStatusTag status={browseStatus} />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +116,7 @@ function BrowseStatusTag({ status }: { status: BrowseStatus }) {
 | 
			
		|||
 | 
			
		||||
function Disconnected() {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="vertical-center justify-center opacity-50">
 | 
			
		||||
    <div className="flex items-center gap-2 justify-center opacity-50">
 | 
			
		||||
      <Icon icon={WifiOff} />
 | 
			
		||||
      Disconnected
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -96,8 +125,14 @@ function Disconnected() {
 | 
			
		|||
 | 
			
		||||
function Connected() {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="vertical-center gap-2 justify-center text-green-8 bg-green-3 rounded-lg">
 | 
			
		||||
      <div className="rounded-full h-2 w-2 bg-green-8" />
 | 
			
		||||
    <div
 | 
			
		||||
      className={clsx(
 | 
			
		||||
        'flex items-center gap-2 justify-center rounded-lg',
 | 
			
		||||
        'text-green-8 th-dark:text-green-4',
 | 
			
		||||
        'bg-green-3 th-dark:bg-green-3/30'
 | 
			
		||||
      )}
 | 
			
		||||
    >
 | 
			
		||||
      <div className="rounded-full h-2 w-2 bg-green-8 th-dark:bg-green-4" />
 | 
			
		||||
      Connected
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +140,13 @@ function Connected() {
 | 
			
		|||
 | 
			
		||||
function Snapshot() {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="vertical-center gap-2 justify-center text-warning-7 bg-warning-3 rounded-lg">
 | 
			
		||||
    <div
 | 
			
		||||
      className={clsx(
 | 
			
		||||
        'flex items-center gap-2 justify-center rounded-lg',
 | 
			
		||||
        'text-warning-7 th-dark:text-warning-4',
 | 
			
		||||
        'bg-warning-3 th-dark:bg-warning-3/10 th-highcontrast:bg-warning-3/30'
 | 
			
		||||
      )}
 | 
			
		||||
    >
 | 
			
		||||
      <div className="rounded-full h-2 w-2 bg-warning-7" />
 | 
			
		||||
      Browsing Snapshot
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ function Template({ environment }: Args) {
 | 
			
		|||
    <EnvironmentItem
 | 
			
		||||
      environment={environment}
 | 
			
		||||
      onClickBrowse={() => {}}
 | 
			
		||||
      onClickDisconnect={() => {}}
 | 
			
		||||
      isActive={false}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ function renderComponent(
 | 
			
		|||
      <EnvironmentItem
 | 
			
		||||
        isActive={false}
 | 
			
		||||
        onClickBrowse={() => {}}
 | 
			
		||||
        onClickDisconnect={() => {}}
 | 
			
		||||
        environment={env}
 | 
			
		||||
        groupName={group.Name}
 | 
			
		||||
      />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,12 +33,14 @@ interface Props {
 | 
			
		|||
  environment: Environment;
 | 
			
		||||
  groupName?: string;
 | 
			
		||||
  onClickBrowse(): void;
 | 
			
		||||
  onClickDisconnect(): void;
 | 
			
		||||
  isActive: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function EnvironmentItem({
 | 
			
		||||
  environment,
 | 
			
		||||
  onClickBrowse,
 | 
			
		||||
  onClickDisconnect,
 | 
			
		||||
  groupName,
 | 
			
		||||
  isActive,
 | 
			
		||||
}: Props) {
 | 
			
		||||
| 
						 | 
				
			
			@ -113,10 +115,11 @@ export function EnvironmentItem({
 | 
			
		|||
      see https://stackoverflow.com/questions/66409964/warning-validatedomnesting-a-cannot-appear-as-a-descendant-of-a
 | 
			
		||||
      */}
 | 
			
		||||
      <div className="absolute inset-y-0 right-0 flex justify-end w-56">
 | 
			
		||||
        <div className="py-3 flex items-center">
 | 
			
		||||
        <div className="py-3 flex items-center flex-1">
 | 
			
		||||
          <EnvironmentBrowseButtons
 | 
			
		||||
            environment={environment}
 | 
			
		||||
            onClickBrowse={onClickBrowse}
 | 
			
		||||
            onClickDisconnect={onClickDisconnect}
 | 
			
		||||
            isActive={isActive}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ const storageKey = 'home_endpoints';
 | 
			
		|||
 | 
			
		||||
export function EnvironmentList({ onClickBrowse, onRefresh }: Props) {
 | 
			
		||||
  const { isAdmin } = useUser();
 | 
			
		||||
  const { environmentId: currentEnvironmentId } = useStore(environmentStore);
 | 
			
		||||
  const currentEnvStore = useStore(environmentStore);
 | 
			
		||||
 | 
			
		||||
  const [platformTypes, setPlatformTypes] = useHomePageFilter<
 | 
			
		||||
    Filter<PlatformType>[]
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +223,12 @@ export function EnvironmentList({ onClickBrowse, onRefresh }: Props) {
 | 
			
		|||
                    groupsQuery.data?.find((g) => g.Id === env.GroupId)?.Name
 | 
			
		||||
                  }
 | 
			
		||||
                  onClickBrowse={() => onClickBrowse(env)}
 | 
			
		||||
                  isActive={env.Id === currentEnvironmentId}
 | 
			
		||||
                  onClickDisconnect={() =>
 | 
			
		||||
                    env.Id === currentEnvStore.environmentId
 | 
			
		||||
                      ? currentEnvStore.clear()
 | 
			
		||||
                      : null
 | 
			
		||||
                  }
 | 
			
		||||
                  isActive={env.Id === currentEnvStore.environmentId}
 | 
			
		||||
                />
 | 
			
		||||
              ))
 | 
			
		||||
            )}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue