Added move and delete functionality
This commit is contained in:
parent
cd0e96834c
commit
2b3da349b0
|
@ -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>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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",
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -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",
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -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' {
|
||||||
|
|
Loading…
Reference in New Issue