Skip to content

Commit a4de313

Browse files
XFox111Copilotdependabot[bot]
authored
Minor 5.1.0 (#560)
* Force no-wrap for special characters tooltip (resolves #551) (#555) * Increase width of password count field in advanced generator (resolves #548) (#554) * Added password length limit in advanced generator (#552) * Added password length limit in advanced generator (resolves #547) * Add radix to parseInt Co-authored-by: Copilot <[email protected]> * Remove unnecessary callback dependency Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * npm audit fix (#556) * Added length slider range limits (#557) * Added length slider range limits (resolves #546) * Fix validateMaxLimit logic Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * Added password length update on input field blur (resolves #549) (#559) * Separator option for advanced password generator (#558) * Added separator option for advanced password generator (resolves #545) * Fix typos * Fixed merge typo * Update package.json * Bump @fluentui/react-components from 9.64.0 to 9.66.5 (#561) Bumps [@fluentui/react-components](https://github.com/microsoft/fluentui) from 9.64.0 to 9.66.5. - [Release notes](https://github.com/microsoft/fluentui/releases) - [Changelog](https://github.com/microsoft/fluentui/blob/master/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/fluentui/compare/@fluentui/react-components_v9.64.0...@fluentui/react-components_v9.66.5) --- updated-dependencies: - dependency-name: "@fluentui/react-components" dependency-version: 9.66.5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/parser from 8.33.1 to 8.35.1 (#562) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.33.1 to 8.35.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.35.1/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-version: 8.35.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @eslint/js from 9.28.0 to 9.30.0 (#564) Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.28.0 to 9.30.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/commits/v9.30.0/packages/js) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-version: 9.30.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump eslint from 9.28.0 to 9.30.0 (#566) Bumps [eslint](https://github.com/eslint/eslint) from 9.28.0 to 9.30.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](eslint/eslint@v9.28.0...v9.30.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 9.30.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/eslint-plugin from 8.33.1 to 8.35.1 (#563) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.33.1 to 8.35.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.35.1/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.35.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @fluentui/react-icons from 2.0.302 to 2.0.305 (#565) Bumps [@fluentui/react-icons](https://github.com/microsoft/fluentui-system-icons) from 2.0.302 to 2.0.305. - [Changelog](https://github.com/microsoft/fluentui-system-icons/blob/main/fluentui-android-system-icons-release.yml) - [Commits](https://github.com/microsoft/fluentui-system-icons/commits) --- updated-dependencies: - dependency-name: "@fluentui/react-icons" dependency-version: 2.0.305 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Moved default password lengths to constants (#553) * Added radix 10 for parseInt (#553) * Removed ts-expect-error microsoft/fluentui#27090 --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 5d8037e commit a4de313

File tree

18 files changed

+1000
-913
lines changed

18 files changed

+1000
-913
lines changed

entrypoints/advanced/components/GeneratorForm.styles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ export const useStyles = makeStyles({
1717
{
1818
display: "grid",
1919
alignItems: "center",
20-
gridTemplateColumns: "24px 24px 56px",
20+
gridTemplateColumns: "24px 24px 60px",
2121
}
2222
});

entrypoints/advanced/components/GeneratorForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function GeneratorForm(props: GeneratorFormProps): ReactElement
1414

1515
const setPasswordCount = useCallback((_: any, e: InputOnChangeData) =>
1616
{
17-
const n = parseInt(e.value ?? "1");
17+
const n = parseInt(e.value ?? "1", 10);
1818
private_setPasswordCount(isNaN(n) || n < 1 ? null : Math.min(n, 1000));
1919
}, []);
2020

entrypoints/advanced/sections/PassphraseSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function PassphraseSection(props: GeneratorProps): ReactElement
2727

2828
const setWordCount = useCallback((_: any, e: InputOnChangeData) =>
2929
{
30-
const n = parseInt(e.value ?? "");
30+
const n = parseInt(e.value ?? "", 10);
3131
private_setWordCount(isNaN(n) || n < 1 ? null : Math.min(n, 100));
3232
}, []);
3333

entrypoints/advanced/sections/PasswordSection.tsx

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import * as fui from "@fluentui/react-components";
44
import { ReactElement } from "react";
55
import { GeneratorProps } from "../Page";
66
import GeneratorForm from "../components/GeneratorForm";
7+
import { DEFAULT_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from "@/utils/constants";
78

89
// TODO: needs refactoring
910
export default function PasswordSection(props: GeneratorProps): ReactElement
1011
{
1112
const [state, private_setState] = useState<PasswordSectionState>({
12-
length: 8,
13+
length: DEFAULT_PASSWORD_LENGTH,
1314
enableUppercase: true, uppercaseCount: 1,
1415
enableLowercase: true, lowercaseCount: 1,
1516
enableNumeric: true, numericCount: 1,
@@ -19,7 +20,11 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
1920
excludeSimilar: true,
2021
excludeAmbiguous: true,
2122
excludeRepeating: false,
22-
excludeCustom: false, excludeCustomSet: ""
23+
excludeCustom: false, excludeCustomSet: "",
24+
25+
enableSeparator: false,
26+
separator: "-",
27+
separatorInterval: DEFAULT_PASSWORD_LENGTH / 2
2328
});
2429

2530
const cls = useStyles();
@@ -31,9 +36,9 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
3136

3237
const setLength = useCallback((_: any, e: fui.InputOnChangeData) =>
3338
{
34-
const n = parseInt(e.value ?? "");
35-
setState({ length: isNaN(n) || n < 1 ? null : n });
36-
}, [state]);
39+
const n = parseInt(e.value ?? "", 10);
40+
setState({ length: isNaN(n) || n < 1 ? null : Math.min(n, MAX_PASSWORD_LENGTH) });
41+
}, [setState]);
3742

3843
const saveConfiguration = useCallback(
3944
async () => await browser.storage.sync.set({ AdvancedPasswordOptions: state }),
@@ -46,7 +51,7 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
4651

4752
for (let i = 0; i < count; i++)
4853
passwords.push(generatePassword({
49-
length: state.length ?? 8,
54+
length: state.length ?? DEFAULT_PASSWORD_LENGTH,
5055
custom: state.enableCustom ? state.customCount ?? 1 : 0,
5156
customSet: state.customSet,
5257
numeric: state.enableNumeric ? state.numericCount ?? 1 : 0,
@@ -57,6 +62,8 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
5762
excludeCustom: state.excludeCustom ? state.excludeCustomSet : "",
5863
excludeRepeating: state.excludeRepeating,
5964
excludeSimilar: state.excludeSimilar,
65+
separator: state.enableSeparator ? state.separator : undefined,
66+
separatorInterval: state.separatorInterval ?? (DEFAULT_PASSWORD_LENGTH / 2)
6067
}));
6168

6269
props.onGenerated(passwords);
@@ -80,10 +87,38 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
8087
onChange: (_, e) => setState({ [key]: parseCount(e.value) })
8188
}), [state]);
8289

90+
const setSeparatorInterval = (_: any, e: fui.InputOnChangeData) =>
91+
{
92+
if (!e.value)
93+
{
94+
setState({ separatorInterval: undefined });
95+
return;
96+
}
97+
98+
const n = parseInt(e.value, 10);
99+
100+
if (!isNaN(n))
101+
setState({ separatorInterval: n < 1 ? 1 : Math.min(n, state.length ?? DEFAULT_PASSWORD_LENGTH) });
102+
};
103+
104+
const updateLength = (): void =>
105+
{
106+
const minLength = Math.max(MIN_PASSWORD_LENGTH,
107+
(state.enableCustom ? state.customCount ?? 1 : 0) +
108+
(state.enableNumeric ? state.numericCount ?? 1 : 0) +
109+
(state.enableSpecial ? state.specialCount ?? 1 : 0) +
110+
(state.enableUppercase ? state.uppercaseCount ?? 1 : 0) +
111+
(state.enableLowercase ? state.lowercaseCount ?? 1 : 0)
112+
);
113+
114+
if (!state.length || state.length < minLength)
115+
setState({ length: minLength });
116+
};
117+
83118
return (
84119
<GeneratorForm onGenerate={ generate } onSave={ saveConfiguration }>
85120
<fui.Field label={ i18n.t("advanced.password.length") }>
86-
<fui.Input value={ state.length?.toString() ?? "" } onChange={ setLength } />
121+
<fui.Input value={ state.length?.toString() ?? "" } onChange={ setLength } onBlur={ updateLength } />
87122
</fui.Field>
88123
<fui.Table size="small" as="div">
89124
<fui.TableHeader as="div">
@@ -95,19 +130,19 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
95130
<fui.TableBody as="div">
96131
<Row>
97132
<fui.Checkbox label={ i18n.t("common.characters.uppercase") } { ...checkboxControls("enableUppercase") } />
98-
<fui.Input { ...minInputControls("enableUppercase", "uppercaseCount") } />
133+
<fui.Input { ...minInputControls("enableUppercase", "uppercaseCount") } onBlur={ updateLength } />
99134
</Row>
100135
<Row>
101136
<fui.Checkbox label={ i18n.t("common.characters.lowercase") } { ...checkboxControls("enableLowercase") } />
102-
<fui.Input { ...minInputControls("enableLowercase", "lowercaseCount") } />
137+
<fui.Input { ...minInputControls("enableLowercase", "lowercaseCount") } onBlur={ updateLength } />
103138
</Row>
104139
<Row>
105140
<fui.Checkbox label={ i18n.t("common.characters.numeric") } { ...checkboxControls("enableNumeric") } />
106-
<fui.Input { ...minInputControls("enableNumeric", "numericCount") } />
141+
<fui.Input { ...minInputControls("enableNumeric", "numericCount") } onBlur={ updateLength } />
107142
</Row>
108143
<Row>
109-
<fui.Checkbox label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special) } { ...checkboxControls("enableSpecial") } />
110-
<fui.Input { ...minInputControls("enableSpecial", "specialCount") } />
144+
<fui.Checkbox label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special, true) } { ...checkboxControls("enableSpecial") } />
145+
<fui.Input { ...minInputControls("enableSpecial", "specialCount") } onBlur={ updateLength } />
111146
</Row>
112147
<Row>
113148
<>
@@ -116,7 +151,7 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
116151
placeholder={ i18n.t("common.characters.custom") }
117152
value={ state.customSet } onChange={ (_, e) => setState({ customSet: e.value }) } />
118153
</>
119-
<fui.Input { ...minInputControls("enableCustom", "customCount") } />
154+
<fui.Input { ...minInputControls("enableCustom", "customCount") } onBlur={ updateLength } />
120155
</Row>
121156
</fui.TableBody>
122157
</fui.Table>
@@ -133,13 +168,34 @@ export default function PasswordSection(props: GeneratorProps): ReactElement
133168
value={ state.excludeCustomSet } onChange={ (_, e) => setState({ excludeCustomSet: e.value }) } />
134169
</div>
135170
</section>
171+
172+
<div>
173+
<fui.Checkbox
174+
{ ...checkboxControls("enableSeparator") }
175+
label={
176+
<span className={ cls.separatorLabel }>
177+
{ i18n.t("advanced.password.separator1") }
178+
<fui.Input size="small" className={ cls.separatorInput }
179+
disabled={ !state.enableSeparator }
180+
value={ state.separator ?? "" }
181+
onChange={ (_, e) => setState({ separator: e.value ? e.value[e.value.length - 1] : undefined }) } />
182+
{ i18n.t("advanced.password.separator2") }
183+
<fui.Input size="small" className={ cls.separatorInput }
184+
disabled={ !state.enableSeparator }
185+
value={ state.separatorInterval?.toString() ?? "" }
186+
onBlur={ () => state.separatorInterval ? null : setState({ separatorInterval: DEFAULT_PASSWORD_LENGTH / 2 }) }
187+
onChange={ setSeparatorInterval } />
188+
{ i18n.t("advanced.password.separator3") }
189+
</span>
190+
} />
191+
</div>
136192
</GeneratorForm>
137193
);
138194
}
139195

140196
function parseCount(value: string): number | null
141197
{
142-
const n = parseInt(value);
198+
const n = parseInt(value, 10);
143199
return isNaN(n) || n < 1 ? null : Math.min(n, 100);
144200
};
145201

@@ -162,6 +218,17 @@ const useStyles = fui.makeStyles({
162218
display: "flex",
163219
flexDirection: "column",
164220
},
221+
separatorLabel:
222+
{
223+
display: "inline-flex",
224+
flexWrap: "wrap",
225+
alignItems: "center",
226+
gap: `${fui.tokens.spacingVerticalXXS} ${fui.tokens.spacingHorizontalS}`,
227+
},
228+
separatorInput:
229+
{
230+
width: "4em",
231+
}
165232
});
166233

167234
type PasswordSectionState =
@@ -185,4 +252,8 @@ type PasswordSectionState =
185252

186253
excludeCustomSet: string;
187254
customSet: string;
255+
256+
enableSeparator: boolean;
257+
separator?: string;
258+
separatorInterval?: number;
188259
};

entrypoints/options/SettingsSection.tsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ArrowUndoRegular } from "@fluentui/react-icons";
55
import { ReactElement } from "react";
66
import infoLabel from "../../utils/infoLabel";
77
import { useStyles } from "./SettingsSection.styles";
8+
import { MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from "@/utils/constants";
89

910
export default function SettingsSection(): ReactElement
1011
{
@@ -28,7 +29,7 @@ export default function SettingsSection(): ReactElement
2829
{
2930
if (e.value.length >= 1)
3031
{
31-
const value = parseInt(e.value);
32+
const value = parseInt(e.value, 10);
3233

3334
if (!isNaN(value) && value >= 0)
3435
updateStorage({ [key]: value });
@@ -37,12 +38,38 @@ export default function SettingsSection(): ReactElement
3738
updateStorage({ [key]: defaultValue });
3839
};
3940

41+
const validateMinLimit = () =>
42+
{
43+
if (extOptions.MinLength < MIN_PASSWORD_LENGTH)
44+
updateStorage({ MinLength: MIN_PASSWORD_LENGTH });
45+
else if (extOptions.MinLength > MAX_PASSWORD_LENGTH - 1)
46+
updateStorage({ MinLength: MAX_PASSWORD_LENGTH - 1, MaxLength: MAX_PASSWORD_LENGTH });
47+
else if (extOptions.MinLength >= extOptions.MaxLength)
48+
updateStorage({ MaxLength: extOptions.MinLength + 1 });
49+
};
50+
51+
const validateMaxLimit = () =>
52+
{
53+
if (extOptions.MaxLength > MAX_PASSWORD_LENGTH)
54+
updateStorage({ MaxLength: MAX_PASSWORD_LENGTH });
55+
else if (extOptions.MaxLength < MIN_PASSWORD_LENGTH + 1)
56+
updateStorage({ MinLength: MIN_PASSWORD_LENGTH, MaxLength: MIN_PASSWORD_LENGTH + 1 });
57+
else if (extOptions.MaxLength <= extOptions.MinLength)
58+
updateStorage({ MinLength: extOptions.MaxLength - 1 });
59+
};
60+
61+
const validateLength = () =>
62+
{
63+
updateStorage({ Length: Math.max(Math.min(generatorOptions.Length, extOptions.MaxLength), extOptions.MinLength) });
64+
};
65+
4066
return (
4167
<section className={ cls.root }>
4268

4369
<fui.Field label={ i18n.t("settings.length.title") } hint={ i18n.t("settings.length.hint") }>
4470
<fui.Input
4571
value={ generatorOptions.Length.toString() }
72+
onBlur={ validateLength }
4673
onChange={ updateNumberField("Length", 0) } />
4774
</fui.Field>
4875

@@ -51,13 +78,15 @@ export default function SettingsSection(): ReactElement
5178
<fui.Input
5279
input={ { className: cls.rangeInput } }
5380
value={ extOptions.MinLength.toString() }
81+
onBlur={ validateMinLimit }
5482
onChange={ updateNumberField("MinLength", defaultOptions.extension.MinLength) } />
5583

5684
<fui.Divider />
5785

5886
<fui.Input
5987
input={ { className: cls.rangeInput } }
6088
value={ extOptions.MaxLength.toString() }
89+
onBlur={ validateMaxLimit }
6190
onChange={ updateNumberField("MaxLength", defaultOptions.extension.MaxLength) } />
6291

6392
<fui.Tooltip relationship="label" content={ i18n.t("common.actions.reset") }>
@@ -84,7 +113,7 @@ export default function SettingsSection(): ReactElement
84113
checked={ generatorOptions.Numeric }
85114
onChange={ setOption("Numeric") } />
86115
<fui.Checkbox
87-
label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special) }
116+
label={ infoLabel(i18n.t("common.characters.special"), CharacterHints.special, true) }
88117
checked={ generatorOptions.Special }
89118
onChange={ setOption("Special") } />
90119
<div>

locales/en.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ advanced:
6969
title: "Password generator"
7070
length: "Password length"
7171
min_of_type: "Minimum number of characters"
72+
separator1: "Add separator"
73+
separator2: "every"
74+
separator3: "character(s)"
7275
passphrase:
7376
title: "Passphrase generator"
7477
length: "Number of words"

locales/pl.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ advanced:
6969
title: "Generator haseł"
7070
length: "Długość hasła"
7171
min_of_type: "Minimum"
72+
separator1: "Dodaj separator"
73+
separator2: "co"
74+
separator3: "znak(ów)"
7275
passphrase:
7376
title: "Frazy hasłowe"
7477
length: "Liczba słów"

locales/pt_BR.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ advanced:
6969
title: "Gerador de senhas"
7070
length: "Comprimento da senha"
7171
min_of_type: "Número mínimo de caracteres"
72+
separator1: "Adicionar separador"
73+
separator2: "a cada"
74+
separator3: "caractere(s)"
7275
passphrase:
7376
title: "Gerador de frases-senha"
7477
length: "Número de palavras"

locales/ru.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ advanced:
6969
title: "Генератор паролей"
7070
length: "Длина пароля"
7171
min_of_type: "Не менее"
72+
separator1: "Добавить разделитель"
73+
separator2: "каждые"
74+
separator3: "символов"
7275
passphrase:
7376
title: "Парольных фраз"
7477
length: "Количество слов"

locales/uk.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ advanced:
6969
title: "Генератор паролів"
7070
length: "Довжина пароля"
7171
min_of_type: "Не менше"
72+
separator1: "Додати розділювач"
73+
separator2: "кожні"
74+
separator3: "символів"
7275
passphrase:
7376
title: "Парольних фраз"
7477
length: "Кількість слів"

0 commit comments

Comments
 (0)