feat: reset editor layout button (#57104)

This commit is contained in:
Sem Bauke
2024-12-09 09:45:40 +01:00
committed by GitHub
parent e7f43df0eb
commit cfb14af924
8 changed files with 111 additions and 2 deletions
@@ -238,6 +238,8 @@
"sound-mode": "This adds the pleasant sound of acoustic guitar throughout the website. You'll get musical feedback as you type in the editor, complete challenges, claim certifications, and more.",
"sound-volume": "Campfire Volume:",
"scrollbar-width": "Editor Scrollbar Width",
"reset-editor-layout-tooltip": "Reset the editor layout to its default state",
"reset-editor-layout": "Reset Editor Layout",
"shortcuts-explained": "Within a challenge, press ESC followed by the question mark to show a list of available shortcuts.",
"username": {
"contains invalid characters": "Username \"{{username}}\" contains invalid characters",
@@ -896,6 +898,7 @@
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request.",
"generate-exam-error": "An error occurred trying to generate your exam.",
"cert-not-found": "The certification {{certSlug}} does not exist.",
"reset-editor-layout": "Your editor layout has been reset.",
"ms": {
"transcript": {
"link-err-1": "Please include a Microsoft transcript URL in the request.",
@@ -35,7 +35,8 @@ import {
updateMySound,
updateMyTheme,
updateMyKeyboardShortcuts,
verifyCert
verifyCert,
resetMyEditorLayout
} from '../redux/settings/actions';
const { apiLocation } = envData;
@@ -47,6 +48,7 @@ type ShowSettingsProps = Pick<ThemeProps, 'toggleNightMode'> & {
navigate: (location: string) => void;
showLoading: boolean;
toggleSoundMode: (sound: boolean) => void;
resetEditorLayout: () => void;
toggleKeyboardShortcuts: (keyboardShortcuts: boolean) => void;
updateIsHonest: () => void;
updateQuincyEmail: (isSendQuincyEmail: boolean) => void;
@@ -80,6 +82,7 @@ const mapDispatchToProps = {
updateIsHonest: updateMyHonesty,
updateQuincyEmail: (sendQuincyEmail: boolean) =>
updateMyQuincyEmail({ sendQuincyEmail }),
resetEditorLayout: () => resetMyEditorLayout(),
verifyCert
};
@@ -91,6 +94,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
toggleNightMode,
toggleSoundMode,
toggleKeyboardShortcuts,
resetEditorLayout,
user: {
completedChallenges,
email,
@@ -140,6 +144,7 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
return <Loader fullScreen={true} />;
}
const sound = (store.get('fcc-sound') as boolean) ?? false;
const editorLayout = (store.get('challenge-layout') as boolean) ?? false;
return (
<>
<Helmet title={`${t('buttons.settings')} | freeCodeCamp.org`} />
@@ -161,6 +166,8 @@ export function ShowSettings(props: ShowSettingsProps): JSX.Element {
currentTheme={theme}
keyboardShortcuts={keyboardShortcuts}
sound={sound}
editorLayout={editorLayout}
resetEditorLayout={resetEditorLayout}
toggleKeyboardShortcuts={toggleKeyboardShortcuts}
toggleNightMode={toggleNightMode}
toggleSoundMode={toggleSoundMode}
@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Spacer } from '@freecodecamp/ui';
import { Button, Spacer } from '@freecodecamp/ui';
import { FullWidthRow } from '../helpers';
import ThemeSettings, { ThemeProps } from '../../components/settings/theme';
import SoundSettings from '../../components/settings/sound';
@@ -11,15 +11,19 @@ type MiscSettingsProps = ThemeProps & {
currentTheme: string;
keyboardShortcuts: boolean;
sound: boolean;
editorLayout: boolean | null;
toggleKeyboardShortcuts: (keyboardShortcuts: boolean) => void;
toggleNightMode: () => void;
toggleSoundMode: (sound: boolean) => void;
resetEditorLayout: () => void;
};
const MiscSettings = ({
currentTheme,
keyboardShortcuts,
sound,
editorLayout,
resetEditorLayout,
toggleKeyboardShortcuts,
toggleNightMode,
toggleSoundMode
@@ -41,6 +45,19 @@ const MiscSettings = ({
explain={t('settings.shortcuts-explained')?.toString()}
/>
<ScrollbarWidthSettings />
<label htmlFor='reset-layout-btn'>
{t('settings.reset-editor-layout-tooltip')}
</label>
<Spacer size='xs' />
<Button
onClick={resetEditorLayout}
id='reset-layout-btn'
data-playwright-test-label='reset-layout-btn'
disabled={!editorLayout}
aria-disabled={!editorLayout}
>
{t('settings.reset-editor-layout')}
</Button>
</FullWidthRow>
</>
);
+2
View File
@@ -491,6 +491,8 @@ export const reducer = handleActions(
payload ? spreadThePayloadOnUser(state, payload) : state,
[settingsTypes.updateMyPortfolioComplete]: (state, { payload }) =>
payload ? spreadThePayloadOnUser(state, payload) : state,
[settingsTypes.resetMyEditorLayoutComplete]: (state, { payload }) =>
payload ? spreadThePayloadOnUser(state, payload) : state,
[settingsTypes.verifyCertComplete]: (state, { payload }) =>
payload ? spreadThePayloadOnUser(state, payload) : state,
[settingsTypes.submitProfileUIComplete]: (state, { payload }) =>
@@ -18,6 +18,7 @@ export const actionTypes = createTypes(
...createAsyncTypes('submitProfileUI'),
...createAsyncTypes('verifyCert'),
...createAsyncTypes('resetProgress'),
...createAsyncTypes('resetMyEditorLayout'),
...createAsyncTypes('deleteAccount')
],
ns
+8
View File
@@ -105,5 +105,13 @@ export const verifyCertError = createAction(types.verifyCertError);
export const resetProgress = createAction(types.resetProgress);
export const resetProgressError = createAction(types.resetProgressError);
export const resetMyEditorLayout = createAction(types.resetMyEditorLayout);
export const resetMyEditorLayoutComplete = createAction(
types.resetMyEditorLayoutComplete
);
export const resetMyEditorLayoutError = createAction(
types.resetMyEditorLayoutError
);
export const deleteAccount = createAction(types.deleteAccount);
export const deleteAccountError = createAction(types.deleteAccountError);
@@ -30,6 +30,8 @@ import {
} from '../../utils/ajax';
import { completedChallengesSelector } from '../selectors';
import {
resetMyEditorLayoutComplete,
resetMyEditorLayoutError,
submitNewAboutComplete,
submitNewAboutError,
submitNewUsernameComplete,
@@ -110,6 +112,26 @@ function* updateMySoundSaga({ payload: update }) {
}
}
function* resetMyEditorLayoutSaga() {
const layout = store.get('challenge-layout');
if (layout) {
try {
const data = {
message: 'flash.reset-editor-layout',
type: 'success'
};
store.remove('challenge-layout');
yield put(createFlashMessage({ ...data }));
yield put(resetMyEditorLayoutComplete({ ...data }));
} catch (e) {
yield put(resetMyEditorLayoutError);
}
}
}
function* updateMyThemeSaga({ payload: update }) {
try {
const { data } = yield call(putUpdateMyTheme, update);
@@ -225,6 +247,7 @@ export function createSettingsSagas(types) {
takeEvery(types.updateMySocials, updateMySocialsSaga),
takeEvery(types.updateMyHonesty, updateMyHonestySaga),
takeEvery(types.updateMySound, updateMySoundSaga),
takeEvery(types.resetMyEditorLayout, resetMyEditorLayoutSaga),
takeEvery(types.updateMyTheme, updateMyThemeSaga),
takeEvery(types.updateMyKeyboardShortcuts, updateMyKeyboardShortcutsSaga),
takeEvery(types.updateMyQuincyEmail, updateMyQuincyEmailSaga),
+48
View File
@@ -0,0 +1,48 @@
import { test, expect } from '@playwright/test';
test.use({ storageState: 'playwright/.auth/certified-user.json' });
test.describe('Reset Editor Layout', () => {
test('drag layout and reset', async ({ page, isMobile }) => {
test.skip(
isMobile,
'The mobile layout does not have resizable panes, so this test is not applicable.'
);
await page.goto(
'/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-15'
);
const desktopLayout = page.getByTestId('desktop-layout');
const splitter = page.getByTestId('preview-left-splitter');
const editorPane = desktopLayout.getByTestId('editor-pane');
const initialStyle = await editorPane.getAttribute('style');
expect(initialStyle).toContain('flex: 1');
// Drag the splitter to resize the editor pane
await splitter.hover();
await page.mouse.down();
await page.mouse.move(100, 100);
await page.mouse.up();
const newStyle = await editorPane.getAttribute('style');
expect(newStyle).not.toContain('flex: 1');
await page.goto('/settings#privacy-settings');
const resetButton = page.getByTestId('reset-layout-btn');
await resetButton.click();
await expect(page.getByTestId('flash-message')).toContainText(
'Your editor layout has been reset'
);
await expect(resetButton).toBeDisabled();
await page.goto(
'/learn/2022/responsive-web-design/learn-basic-css-by-building-a-cafe-menu/step-15'
);
const afterReset = await editorPane.getAttribute('style');
expect(afterReset).toContain('flex: 1');
});
});