Skip to content

Commit

Permalink
fix: laggy switch (#3814)
Browse files Browse the repository at this point in the history
<!-- Thanks for creating a PR! To make it easier for reviewers and
everyone else to understand what your changes relate to, please add some
relevant content to the headings below. Feel free to ignore or delete
sections that you don't think are relevant. Thank you! ❤️ -->
Fixes laggy environment switch
## About the changes
<!-- Describe the changes introduced. What are they and why are they
being introduced? Feel free to also add screenshots or steps to view the
changes if they're visual. -->

Stabilising the functions with useCallback seems necessary in the table
view
Changed the `checked` property to be dependent on `isChecked` which
wraps the value in useOptimisticUpdate hook made the most difference

<!-- Does it close an issue? Multiple? -->
Closes
#(1-942)[https://linear.app/unleash/issue/1-942/bug-laggy-environment-toggles-in-the-ui]

<!-- (For internal contributors): Does it relate to an issue on public
roadmap? -->
<!--
Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item:
#
-->

### Important files
<!-- PRs can contain a lot of changes, but not all changes are equally
important. Where should a reviewer start looking to get an overview of
the changes? Are any files particularly important? -->


## Discussion points
<!-- Anything about the PR you'd like to discuss before it gets merged?
Got any questions or doubts? -->

---------

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
  • Loading branch information
andreas-unleash committed May 19, 2023
1 parent 6e2cd60 commit e1dd170
Showing 1 changed file with 100 additions and 69 deletions.
@@ -1,4 +1,4 @@
import { useState, VFC } from 'react';
import { useCallback, useState, VFC } from 'react';
import { Box, styled } from '@mui/material';
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
import { UPDATE_FEATURE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions';
Expand Down Expand Up @@ -68,37 +68,45 @@ export const FeatureToggleSwitch: VFC<IFeatureToggleSwitchProps> = ({
onToggle(projectId, feature.name, environmentName, !isChecked);
};

const handleToggleEnvironmentOn = async (
shouldActivateDisabled = false
) => {
try {
setIsChecked(!isChecked);
await toggleFeatureEnvironmentOn(
projectId,
feature.name,
environmentName,
shouldActivateDisabled
);
setToastData({
type: 'success',
title: `Available in ${environmentName}`,
text: `${feature.name} is now available in ${environmentName} based on its defined strategies.`,
});
callback();
} catch (error: unknown) {
if (
error instanceof Error &&
error.message === ENVIRONMENT_STRATEGY_ERROR
) {
showInfoBox && showInfoBox();
} else {
setToastApiError(formatUnknownError(error));
const handleToggleEnvironmentOn = useCallback(
async (shouldActivateDisabled = false) => {
try {
setIsChecked(!isChecked);
await toggleFeatureEnvironmentOn(
projectId,
feature.name,
environmentName,
shouldActivateDisabled
);
setToastData({
type: 'success',
title: `Available in ${environmentName}`,
text: `${feature.name} is now available in ${environmentName} based on its defined strategies.`,
});
callback();
} catch (error: unknown) {
if (
error instanceof Error &&
error.message === ENVIRONMENT_STRATEGY_ERROR
) {
showInfoBox && showInfoBox();
} else {
setToastApiError(formatUnknownError(error));
}
rollbackIsChecked();
}
rollbackIsChecked();
}
};
},
[
rollbackIsChecked,
setToastApiError,
showInfoBox,
setToastData,
toggleFeatureEnvironmentOn,
setIsChecked,
]
);

const handleToggleEnvironmentOff = async () => {
const handleToggleEnvironmentOff = useCallback(async () => {
try {
setIsChecked(!isChecked);
await toggleFeatureEnvironmentOff(
Expand All @@ -116,63 +124,86 @@ export const FeatureToggleSwitch: VFC<IFeatureToggleSwitchProps> = ({
setToastApiError(formatUnknownError(error));
rollbackIsChecked();
}
};
}, [
toggleFeatureEnvironmentOff,
setToastData,
setToastApiError,
rollbackIsChecked,
setIsChecked,
]);

const featureHasOnlyDisabledStrategies = useCallback(() => {
const featureEnvironment = feature?.environments?.find(
env => env.name === environmentName
);
return (
featureEnvironment?.strategies &&
featureEnvironment?.strategies?.length > 0 &&
featureEnvironment?.strategies?.every(strategy => strategy.disabled)
);
}, [environmentName]);

const onClick = useCallback(
async (e: React.MouseEvent) => {
if (isChangeRequestConfigured(environmentName)) {
e.preventDefault();
if (featureHasOnlyDisabledStrategies()) {
setShowEnabledDialog(true);
} else {
onChangeRequestToggle(
feature.name,
environmentName,
!value,
false
);
}
return;
}
if (value) {
await handleToggleEnvironmentOff();
return;
}

const onClick = async (e: React.MouseEvent) => {
if (isChangeRequestConfigured(environmentName)) {
e.preventDefault();
if (featureHasOnlyDisabledStrategies()) {
setShowEnabledDialog(true);
} else {
onChangeRequestToggle(
feature.name,
environmentName,
!value,
false
);
await handleToggleEnvironmentOn();
}
return;
}
if (value) {
await handleToggleEnvironmentOff();
return;
}

if (featureHasOnlyDisabledStrategies()) {
setShowEnabledDialog(true);
} else {
await handleToggleEnvironmentOn();
}
};
},
[
isChangeRequestConfigured,
onChangeRequestToggle,
handleToggleEnvironmentOff,
setShowEnabledDialog,
]
);

const onActivateStrategies = async () => {
const onActivateStrategies = useCallback(async () => {
if (isChangeRequestConfigured(environmentName)) {
onChangeRequestToggle(feature.name, environmentName, !value, true);
} else {
await handleToggleEnvironmentOn(true);
}
setShowEnabledDialog(false);
};
}, [
handleToggleEnvironmentOn,
setShowEnabledDialog,
isChangeRequestConfigured,
onChangeRequestToggle,
]);

const onAddDefaultStrategy = async () => {
const onAddDefaultStrategy = useCallback(async () => {
if (isChangeRequestConfigured(environmentName)) {
onChangeRequestToggle(feature.name, environmentName, !value, false);
} else {
await handleToggleEnvironmentOn();
}
setShowEnabledDialog(false);
};

const featureHasOnlyDisabledStrategies = () => {
const featureEnvironment = feature?.environments?.find(
env => env.name === environmentName
);
return (
featureEnvironment?.strategies &&
featureEnvironment?.strategies?.length > 0 &&
featureEnvironment?.strategies?.every(strategy => strategy.disabled)
);
};
}, [
isChangeRequestConfigured,
onChangeRequestToggle,
handleToggleEnvironmentOn,
]);

const key = `${feature.name}-${environmentName}`;

Expand All @@ -188,7 +219,7 @@ export const FeatureToggleSwitch: VFC<IFeatureToggleSwitchProps> = ({
? `Disable feature in ${environmentName}`
: `Enable feature in ${environmentName}`
}
checked={value}
checked={isChecked}
environmentId={environmentName}
projectId={projectId}
permission={UPDATE_FEATURE_ENVIRONMENT}
Expand Down

0 comments on commit e1dd170

Please sign in to comment.