Added move and delete functionality

This commit is contained in:
Sergej Schwabauer 2023-04-13 16:38:08 +02:00
parent cd0e96834c
commit 2b3da349b0
7 changed files with 145 additions and 34 deletions

View File

@ -3,6 +3,7 @@ import styles from './PasswordVault.module.scss';
import { cssClasses, isNullOrEmpty } from '@spfxappdev/utility'; import { cssClasses, isNullOrEmpty } from '@spfxappdev/utility';
import { ActionButton, Callout, Icon, TooltipHost, DirectionalHint } from 'office-ui-fabric-react'; import { ActionButton, Callout, Icon, TooltipHost, DirectionalHint } from 'office-ui-fabric-react';
import { ModuleType } from '@src/models'; import { ModuleType } from '@src/models';
import * as strings from 'PasswordVaultWebPartStrings';
export interface IAddNewModuleProps { export interface IAddNewModuleProps {
onModuleSelected(module: ModuleType): void; onModuleSelected(module: ModuleType): void;
@ -29,14 +30,14 @@ export default class AddNewModule extends React.Component<IAddNewModuleProps, IA
<div className={cssClasses(styles["separator-container"], isCallOutVisibleClass)}> <div className={cssClasses(styles["separator-container"], isCallOutVisibleClass)}>
<button type="button" <button type="button"
aria-haspopup="true" aria-haspopup="true"
aria-label="Add a new control" aria-label={strings.AddNewModuleLabel}
ref={(ref: HTMLButtonElement) => { this.addNewButtonRef = ref }} ref={(ref: HTMLButtonElement) => { this.addNewButtonRef = ref }}
onClick={() => { onClick={() => {
this.setState({ this.setState({
showAddNewCallout: true showAddNewCallout: true
}); });
}}> }}>
<TooltipHost content="Add a new secured module" <TooltipHost content={strings.AddNewModuleLabel}
// id={this.WebPart.instanceId + "_addNewControl"} // id={this.WebPart.instanceId + "_addNewControl"}
> >
<Icon iconName="Add" /> <Icon iconName="Add" />
@ -70,15 +71,15 @@ export default class AddNewModule extends React.Component<IAddNewModuleProps, IA
}} }}
> >
<ActionButton iconProps={{iconName: "PasswordField"}} onClick={() => { this.onModuleSelected(ModuleType.PasswordField); }}> <ActionButton iconProps={{iconName: "PasswordField"}} onClick={() => { this.onModuleSelected(ModuleType.PasswordField); }}>
<div>Password</div> <div>{strings.PasswordModuleLabel}</div>
</ActionButton> </ActionButton>
<ActionButton iconProps={{iconName: "UserOptional"}} onClick={() => { this.onModuleSelected(ModuleType.UserField); }}> <ActionButton iconProps={{iconName: "UserOptional"}} onClick={() => { this.onModuleSelected(ModuleType.UserField); }}>
<div>Username</div> <div>{strings.UsernameModuleLabel}</div>
</ActionButton> </ActionButton>
<ActionButton iconProps={{iconName: "EditNote"}} onClick={() => { this.onModuleSelected(ModuleType.NoteField); }}> <ActionButton iconProps={{iconName: "EditNote"}} onClick={() => { this.onModuleSelected(ModuleType.NoteField); }}>
<div>Note</div> <div>{strings.NoteModuleLabel}</div>
</ActionButton> </ActionButton>
</Callout> </Callout>
</> </>

View File

@ -27,7 +27,7 @@ export default class NoteField extends React.Component<INoteFieldProps, INoteFie
} }
private renderDisplayMode(): JSX.Element { private renderDisplayMode(): JSX.Element {
return (<><Label>{strings.NoteLabel}</Label> return (<>
<RichText <RichText
isEditMode={false} isEditMode={false}
value={this.props.defaultValue} value={this.props.defaultValue}

View File

@ -79,9 +79,43 @@
opacity: 1; opacity: 1;
} }
} }
.edit-container {
border: dotted 1px $ms-color-themePrimary;
&--header {
background-color: $ms-color-neutralLighter;
.delete-btn {
float: right;
}
button:disabled,
button[disabled] {
cursor: not-allowed;
i {
color: $ms-color-neutralTertiaryAlt;
}
}
}
&--content {
padding: 10px;
}
}
} }
:global { :global {
.ql-editor
{
padding: 0px !important;
}
.ql-editor[contenteditable='true'] {
padding: 8px 10px !important;
}
.addnew-callout { .addnew-callout {
display: block; display: block;

View File

@ -3,10 +3,8 @@ import styles from './PasswordVault.module.scss';
import { SPFxAppDevWebPartComponent, ISPFxAppDevWebPartComponentProps } from '@spfxappdev/framework'; import { SPFxAppDevWebPartComponent, ISPFxAppDevWebPartComponentProps } from '@spfxappdev/framework';
import PasswordVaultWebPart from '../PasswordVaultWebPart'; import PasswordVaultWebPart from '../PasswordVaultWebPart';
import { IPasswordVaultService } from '@src/services/PasswordVaultService'; import { IPasswordVaultService } from '@src/services/PasswordVaultService';
import { Callout, DefaultButton, DirectionalHint, Icon, ITextField, Label, MessageBar, MessageBarType, PrimaryButton, TextField } from 'office-ui-fabric-react'; import { DefaultButton, IconButton, MessageBar, MessageBarType, PrimaryButton, TextField } from 'office-ui-fabric-react';
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
import { RichText } from "@pnp/spfx-controls-react/lib/RichText";
import { IVaultData } from '@src/models/IVaultData';
import * as strings from 'PasswordVaultWebPartStrings'; import * as strings from 'PasswordVaultWebPartStrings';
import AddNewModule from './AddNewModule'; import AddNewModule from './AddNewModule';
import { IModule, ModuleType } from '@src/models'; import { IModule, ModuleType } from '@src/models';
@ -31,11 +29,7 @@ export interface IPasswordVaultProps extends ISPFxAppDevWebPartComponentProps<Pa
modules?: IModule[]; modules?: IModule[];
} }
//TODO: //TODO:
// Header Module????
// Filter/Search for combination?
// "Change Password" as command button, only if vault already have set a master password // "Change Password" as command button, only if vault already have set a master password
// Delete Module
// Change Order of module
export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVaultWebPart, IPasswordVaultProps, IPasswordVaultState> { export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVaultWebPart, IPasswordVaultProps, IPasswordVaultState> {
@ -150,8 +144,6 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
} }
private renderEditMode(): JSX.Element { private renderEditMode(): JSX.Element {
const wp: PasswordVaultWebPart = this.WebPart;
const showForm: boolean = this.state.isVaultOpen; const showForm: boolean = this.state.isVaultOpen;
return ( return (
@ -250,26 +242,60 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
</div> </div>
<div className="spfxappdev-grid-row" key={module.id}> <div className="spfxappdev-grid-row" key={module.id}>
<div className="spfxappdev-grid-col spfxappdev-sm12"> <div className="spfxappdev-grid-col spfxappdev-sm12">
{module.type == ModuleType.UserField && <div className={styles["edit-container"]}>
<UserField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => { <div className={styles["edit-container--header"]}>
this.decryptedModuleData[module.id] = newVal; <IconButton
}} isDisplayMode={false} /> className={styles["delete-btn"]}
} iconProps={{ iconName: "Delete"}}
title={strings.DeleteModuleLabel}
onClick={() => {
this.onDeleteModule(index);
}}
/>
{module.type == ModuleType.PasswordField && <IconButton
<PasswordField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => { iconProps={{ iconName: "Up"}}
this.decryptedModuleData[module.id] = newVal; title={strings.MoveUpLabel}
}} isDisplayMode={false} /> disabled={this.state.modules.length === 1 || index === 0}
} onClick={() => {
this.onMoveUp(index);
}}
/>
{module.type == ModuleType.NoteField && <IconButton
<NoteField defaultValue={this.decryptedModuleData[module.id]} onChange={(newVal: string) => { iconProps={{ iconName: "Down"}}
title={strings.MoveDownLabel}
disabled={this.state.modules.length === 1 || this.state.modules.length - 1 === index}
onClick={() => {
this.onMoveDown(index);
}}
/>
</div>
this.decryptedModuleData[module.id] = newVal; <div className={styles["edit-container--content"]}>
{module.type == ModuleType.UserField &&
<UserField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => {
this.decryptedModuleData[module.id] = newVal;
}} isDisplayMode={false} />
}
return newVal; {module.type == ModuleType.PasswordField &&
}} isDisplayMode={false} /> <PasswordField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => {
} this.decryptedModuleData[module.id] = newVal;
}} isDisplayMode={false} />
}
{module.type == ModuleType.NoteField &&
<NoteField defaultValue={this.decryptedModuleData[module.id]} onChange={(newVal: string) => {
this.decryptedModuleData[module.id] = newVal;
return newVal;
}} isDisplayMode={false} />
}
</div>
</div>
</div> </div>
</div> </div>
</> </>
@ -387,7 +413,6 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
} }
private onAddNewModule(moduleType: ModuleType, index: number): void { private onAddNewModule(moduleType: ModuleType, index: number): void {
console.log("add new Module", moduleType);
const module: IModule = { const module: IModule = {
id: Guid.newGuid().toString(), id: Guid.newGuid().toString(),
@ -406,4 +431,34 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
modules: this.state.modules modules: this.state.modules
}); });
} }
private onDeleteModule(index: number): void {
this.state.modules.RemoveAt(index);
this.setState({
modules: this.state.modules
});
}
private onMoveUp(index: number): void {
const prevModule: IModule = this.state.modules[index-1];
this.state.modules[index-1] = this.state.modules[index];
this.state.modules[index] = prevModule;
this.setState({
modules: this.state.modules
});
}
private onMoveDown(index: number): void {
this.state.modules.RemoveAt(index);
this.setState({
modules: this.state.modules
});
}
} }

View File

@ -14,6 +14,13 @@ define([], function() {
"OpenVaultLabel": "Tresor entsperren", "OpenVaultLabel": "Tresor entsperren",
"UsernameCopiedLabel": "Benutzername kopiert", "UsernameCopiedLabel": "Benutzername kopiert",
"PasswordCopiedLabel": "Passwort kopiert", "PasswordCopiedLabel": "Passwort kopiert",
"DontLoseMasterpasswordLabel": "Wenn Sie das Master passwort vergessen, können Sie den Tresor nicht mehr entsperren und alle Daten gehen verloren. Es ist nicht möglich das Passwort wiederherzustellen." "DontLoseMasterpasswordLabel": "Wenn Sie das Master passwort vergessen, können Sie den Tresor nicht mehr entsperren und alle Daten gehen verloren. Es ist nicht möglich das Passwort wiederherzustellen.",
"AddNewModuleLabel": "Ein neues Modul hinzufügen",
"DeleteModuleLabel": "Modul löschen",
"MoveUpLabel": "Nach oben verschieben",
"MoveDownLabel": "Nach unten verschieben",
"PasswordModuleLabel": "Passwort",
"UsernameModuleLabel": "Benutzername",
"NoteModuleLabel": "Notiz",
} }
}); });

View File

@ -14,6 +14,13 @@ define([], function() {
"OpenVaultLabel": "Open vault", "OpenVaultLabel": "Open vault",
"UsernameCopiedLabel": "Username copied", "UsernameCopiedLabel": "Username copied",
"PasswordCopiedLabel": "Password copied", "PasswordCopiedLabel": "Password copied",
"DontLoseMasterpasswordLabel": "If you forget the master password, you will not be able to unlock the vault and all data will be lost. It is not possible to recover the password." "DontLoseMasterpasswordLabel": "If you forget the master password, you will not be able to unlock the vault and all data will be lost. It is not possible to recover the password.",
"AddNewModuleLabel": "Add a new secured module",
"DeleteModuleLabel": "Delete",
"MoveUpLabel": "Move up",
"MoveDownLabel": "Move down",
"PasswordModuleLabel": "Password",
"UsernameModuleLabel": "Username",
"NoteModuleLabel": "Note",
} }
}); });

View File

@ -14,6 +14,13 @@ declare interface IPasswordVaultWebPartStrings {
UsernameCopiedLabel: string; UsernameCopiedLabel: string;
PasswordCopiedLabel: string; PasswordCopiedLabel: string;
DontLoseMasterpasswordLabel: string; DontLoseMasterpasswordLabel: string;
AddNewModuleLabel: string;
DeleteModuleLabel: string;
MoveUpLabel: string;
MoveDownLabel: string;
PasswordModuleLabel: string;
UsernameModuleLabel: string;
NoteModuleLabel: string;
} }
declare module 'PasswordVaultWebPartStrings' { declare module 'PasswordVaultWebPartStrings' {