1
0
mirror of https://github.com/XFox111/PasswordGeneratorExtension.git synced 2026-04-22 08:08:01 +03:00

Major 2.0 (#8)

* Migrated to React 18 and FluentUI 9

* Added Ukranian translation

* Updated GitHub templates

* Updated CI/CD
- Added CodeQL and Dependabot pipelines
- Removed Whitesource Bolt integration
- Added PR pipeline
- Update release pipeline to meet ReactJS
- Added Edge publish to pipeline
- Updated PR checklist

* Updated repo docs

* Moved dependabot yml to the right place

* Update README.md

* Added path filters to pipelines
This commit is contained in:
Eugene Fox
2022-09-06 19:12:02 +03:00
committed by GitHub
parent 8991884494
commit 03d74f93d6
56 changed files with 11817 additions and 1134 deletions
+54
View File
@@ -0,0 +1,54 @@
import { AccordionItem, AccordionHeader, AccordionPanel, Link, Text, Button } from "@fluentui/react-components";
import { InfoRegular, PersonFeedbackRegular } from "@fluentui/react-icons";
import { ReactComponent as BuyMeACoffee } from "../Assets/BuyMeACoffee.svg";
import React from "react";
import { loc } from "../Utils/Localization";
export default class AboutSection extends React.Component
{
public render(): JSX.Element
{
return (
<AccordionItem value="about">
<AccordionHeader as="h2" icon={ <InfoRegular /> }>{ loc("About") }</AccordionHeader>
<AccordionPanel>
<section className="stack gap fadeIn">
<Text as="p">
{ loc("Developed by Eugene Fox") } (<Link href="https://twitter.com/xfox111" target="_blank">@xfox111</Link>)
<br />
{ loc("Licensed under") } <Link href="https://github.com/XFox111/PasswordGeneratorExtension/blob/master/LICENSE" target="_blank">{ loc("MIT license") }</Link>
</Text>
<Text as="p">
{ loc("Want to contribute translation for your language?") } <Link href="https://github.com/XFox111/PasswordGeneratorExtension/blob/master/CONTRIBUTING.md" target="_blank">{ loc("Read this to get started") }</Link>
</Text>
<Text as="p">
<Link href="https://xfox111.net/" target="_blank">{ loc("My website") }</Link>
<br />
<Link href="https://github.com/xfox111/PasswordGeneratorExtension" target="_blank">{ loc("Source code") }</Link>
<br />
<Link href="https://github.com/XFox111/PasswordGeneratorExtension/releases/latest" target="_blank">{ loc("Changelog") }</Link>
</Text>
<div className="stack horizontal gap">
<Button
as="a" target="_blank"
href="mailto:feedback@xfox111.net"
appearance="primary" icon={ <PersonFeedbackRegular /> }>
{ loc("Leave feedback") }
</Button>
<Button
as="a" target="_blank"
href="https://buymeacoffee.com/xfox111"
className="bmc" appearance="primary" icon={ <BuyMeACoffee /> }>
{ loc("Buy me a coffee") }
</Button>
</div>
</section>
</AccordionPanel>
</AccordionItem>
);
}
}
+76
View File
@@ -0,0 +1,76 @@
import { Button, Text } from "@fluentui/react-components";
import { Dialog, DialogTrigger, DialogSurface, DialogTitle, DialogBody, Table, TableHeader, TableRow, TableHeaderCell, TableBody, TableCell, DialogActions } from "@fluentui/react-components/unstable";
import { QuestionCircleRegular } from "@fluentui/react-icons";
import React from "react";
import Generator from "../Utils/Generator";
import { loc } from "../Utils/Localization";
export default class CharacterHelpDialog extends React.Component
{
public render(): JSX.Element
{
return (
<Dialog>
<DialogTrigger>
<Button appearance="subtle" style={ { marginLeft: 5 } } icon={ <QuestionCircleRegular /> } />
</DialogTrigger>
<DialogSurface aria-label="label">
<DialogTitle>{ loc("Character options") }</DialogTitle>
<DialogBody>
<Table>
<TableHeader>
<TableRow>
<TableHeaderCell>{ loc("Set_name") }</TableHeaderCell>
<TableHeaderCell>{ loc("Characters") }</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>{ loc("Lowercase") }</TableCell>
<TableCell>
<Text font="monospace">{ Generator.Lowercase.substring(0, 10) }{ loc(", etc.") }</Text>
</TableCell>
</TableRow>
<TableRow>
<TableCell>{ loc("Uppercase") }</TableCell>
<TableCell>
<Text font="monospace">{ Generator.Uppercase.substring(0, 10) }{ loc(", etc.") }</Text>
</TableCell>
</TableRow>
<TableRow>
<TableCell>{ loc("Numeric") }</TableCell>
<TableCell>
<Text font="monospace">{ Generator.Numeric }</Text>
</TableCell>
</TableRow>
<TableRow>
<TableCell>{ loc("Special symbols") }</TableCell>
<TableCell>
<Text font="monospace">{ Generator.SpecialCharacters }</Text>
</TableCell>
</TableRow>
<TableRow>
<TableCell>{ loc("Ambiguous") }</TableCell>
<TableCell>
<Text font="monospace">{ Generator.AmbiguousCharacters }</Text>
</TableCell>
</TableRow>
<TableRow>
<TableCell>{ loc("Similar") }</TableCell>
<TableCell>
<Text font="monospace">{ Generator.SimilarCharacters }</Text>
</TableCell>
</TableRow>
</TableBody>
</Table>
</DialogBody>
<DialogActions>
<DialogTrigger>
<Button appearance="secondary">{ loc("OK") }</Button>
</DialogTrigger>
</DialogActions>
</DialogSurface>
</Dialog>
);
}
}
+129
View File
@@ -0,0 +1,129 @@
import { Input, Button, Link, Text, Tooltip } from "@fluentui/react-components";
import { Alert } from "@fluentui/react-components/unstable";
import { ArrowClockwiseRegular, CheckmarkRegular, CopyRegular } from "@fluentui/react-icons";
import React from "react";
import Generator from "../Utils/Generator";
import GeneratorOptions from "../Utils/GeneratorOptions";
import { loc } from "../Utils/Localization";
import Settings from "../Utils/Settings";
interface IStates
{
password: string;
error?: string;
copyIcon: JSX.Element;
}
interface IProps
{
generatorOptions: GeneratorOptions;
settings: Settings;
}
export default class PasswordView extends React.Component<IProps, IStates>
{
constructor(props: IProps)
{
super(props);
this.state =
{
password: Generator.GeneratePassword(props.generatorOptions),
error: Generator.ValidateProps(props.generatorOptions),
copyIcon: <CopyRegular className="scaleUpIn" />,
};
}
private OnCopyPassword(password : string): void
{
console.log("PasswordView.OnCopyPassword");
if (!document.hasFocus())
return;
window.navigator.clipboard.writeText(password);
this.setState({ copyIcon: <CheckmarkRegular className="scaleUpIn" /> });
setTimeout(() => this.setState({ copyIcon: <CopyRegular className="scaleUpIn" /> }), 3000);
}
private OnRefreshPassword(): void
{
console.log("PasswordView.OnRefreshPassword");
let password : string = Generator.GeneratePassword(this.props.generatorOptions);
this.setState({ password });
document.querySelector("svg#refresh-btn")?.classList.add("spin");
setTimeout(() => document.querySelector("svg#refresh-btn")?.classList.remove("spin"), 600);
if (this.props.settings.Autocopy)
this.OnCopyPassword(password);
}
public componentDidUpdate(prevProps: Readonly<IProps>): void
{
console.log("PasswordView.componentDidUpdate");
// Converting to JSON is the easiest way to compare objects
if (JSON.stringify(prevProps.generatorOptions) === JSON.stringify(this.props.generatorOptions))
return;
let error : string = Generator.ValidateProps(this.props.generatorOptions);
let password = Generator.GeneratePassword(this.props.generatorOptions);
this.setState({ password, error });
if (!error && this.props.settings.Autocopy)
this.OnCopyPassword(password);
}
private AlterSpecialsOnce(useSpecials : boolean) : void
{
console.log("PasswordView.AlterSpecialsOnce", `useSpecials: ${useSpecials}`);
let options : GeneratorOptions = { ...this.props.generatorOptions, Special: useSpecials, ExcludeAmbiguous: true };
let error : string = Generator.ValidateProps(options);
let password : string = Generator.GeneratePassword(options);
this.setState({ password, error });
if (error)
setTimeout(() => this.OnRefreshPassword(), 3000);
}
public render(): JSX.Element
{
return this.state.error ?
<Alert intent="error" className="fadeIn">{ this.state.error }</Alert>
:
<section className="stack fadeIn">
<Input
value={ this.state.password } readOnly
contentAfter={
<>
<Tooltip content={ loc("Copy") } relationship="label">
<Button onClick={ () => this.OnCopyPassword(this.state.password) } appearance="subtle" icon={ this.state.copyIcon } />
</Tooltip>
<Tooltip content={ loc("Generate new") } relationship="label">
<Button onClick={ () => this.OnRefreshPassword() } appearance="subtle" icon={ <ArrowClockwiseRegular id="refresh-btn" /> } />
</Tooltip>
</>
} />
<Text>
{ this.props.generatorOptions.Special ?
<Link onClick={ () => this.AlterSpecialsOnce(false) }>
{ loc("Exclude special symbols one time") }
</Link>
:
<Link onClick={ () => this.AlterSpecialsOnce(true) }>
{ loc("Include special symbols one time") }
</Link>
}
</Text>
</section>
;
}
}
+81
View File
@@ -0,0 +1,81 @@
import { AccordionItem, AccordionHeader, AccordionPanel, Label, Text, Input, Divider, Checkbox, Tooltip } from "@fluentui/react-components";
import { QuestionCircleRegular, SettingsRegular } from "@fluentui/react-icons";
import React from "react";
import GeneratorOptions from "../Utils/GeneratorOptions";
import { loc } from "../Utils/Localization";
import Settings from "../Utils/Settings";
import CharacterHelpDialog from "./CharacterHelpDialog";
interface IProps
{
generatorOptions: GeneratorOptions;
settings: Settings;
}
export default class SettingsSection extends React.Component<IProps>
{
public render(): JSX.Element
{
let options : GeneratorOptions = this.props.generatorOptions;
let settings : Settings = this.props.settings;
return (
<AccordionItem value="settings">
<AccordionHeader as="h2" icon={ <SettingsRegular /> }>{ loc("Settings") }</AccordionHeader>
<AccordionPanel>
<section className="stack gap fadeIn">
<Label weight="semibold" htmlFor="pwd-length">{ loc("Password length") }</Label>
<div className="stack">
<Input
id="pwd-length"
value={ options.Length.toString() }
onChange={ (_, e) => GeneratorOptions.Update({ Length: parseInt(e.value) }) }
type="number" min={ 4 } />
<Text size={ 200 }>{ loc("Recommended password length") } <b>16-32</b></Text>
</div>
<Divider />
<div className="stack">
<Text as="h3" weight="semibold">
{ loc("Character options") }
<CharacterHelpDialog />
</Text>
<Text as="h4">{ loc("Include") }</Text>
<div className="stack horizontal">
<Checkbox label={ loc("Special symbols") }
checked={ options.Special } onChange={ (_, e) => GeneratorOptions.Update({ Special: e.checked as boolean }) } />
<Checkbox label={ loc("Numeric") }
checked={ options.Numeric } onChange={ (_, e) => GeneratorOptions.Update({ Numeric: e.checked as boolean }) } />
<Checkbox label={ loc("Uppercase") }
checked={ options.Uppercase } onChange={ (_, e) => GeneratorOptions.Update({ Uppercase: e.checked as boolean }) } />
<Checkbox label={ loc("Lowercase") }
checked={ options.Lowercase } onChange={ (_, e) => GeneratorOptions.Update({ Lowercase: e.checked as boolean }) } />
</div>
<Text as="h4">{ loc("Exclude") }</Text>
<div className="stack horizontal">
<Checkbox label={ loc("Similar") }
checked={ options.ExcludeSimilar } onChange={ (_, e) => GeneratorOptions.Update({ ExcludeSimilar: e.checked as boolean }) } />
<Checkbox label={ loc("Ambiguous") }
checked={ options.ExcludeAmbiguous } onChange={ (_, e) => GeneratorOptions.Update({ ExcludeAmbiguous: e.checked as boolean }) } />
<Checkbox label={ loc("Repeating") }
checked={ options.ExcludeRepeating } onChange={ (_, e) => GeneratorOptions.Update({ ExcludeRepeating: e.checked as boolean }) } />
</div>
</div>
<Divider />
<div className="stack">
<div>
<Tooltip content={ loc("Right-click password field to quickly generate password") } relationship="description">
<Checkbox label={ <Text>{loc("Add shortcut to context menu")} <QuestionCircleRegular /></Text> }
checked={ settings.AddContext } onChange={ (_, e) => Settings.Update({ AddContext: e.checked as boolean }) } />
</Tooltip>
</div>
<Checkbox label={ loc("Automatically copy to clipboard") }
checked={ settings.Autocopy } onChange={ (_, e) => Settings.Update({ Autocopy: e.checked as boolean }) } />
</div>
</section>
</AccordionPanel>
</AccordionItem>
);
}
}