Commit 40c28d29 authored by David Burke's avatar David Burke

Fixed storybook

Started adding account page
parent ce55e695
Pipeline #37047398 failed with stage
in 2 minutes and 39 seconds
......@@ -96,3 +96,4 @@ archive.zip
documentation/
image
.cache
import { configure } from '@storybook/angular';
import { configure } from "@storybook/angular";
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
// automatically import all files ending in *.stories.ts
const req = require.context('../src/stories', true, /.stories.ts$/);
const req = require.context("../src/stories", true, /.stories.ts$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
......
# Passit Front
passit-frontend is the angular client for [Passit](https://passit.io).
passit-frontend is the angular client for [Passit](https://passit.io). It includes both the web version and mobile app.
We use smart and dumb components with ngrx/store.
Read about it [here](https://gist.github.com/btroncone/a6e4347326749f938510#utilizing-container-components)
API and crypto interaction are handled by passit-sdk-js which itself uses libsodium.js.
# Passit Web
## Install Extensions
- [Chrome Web Store](https://chrome.google.com/webstore/detail/passit/pgcleadjbkbghamecomebcdakdmahkeh)
......@@ -140,10 +142,25 @@ So instead we self host, signing it with the `web-ext` command in CI and creatin
6. Once all build steps finish, download the `passit.zip` to upload to the chrome webstore.
It is available as an artifact under the `build-ext-assets` job in the `test` stage.
7. Create a new release on the [Chrome web store](https://chrome.google.com/webstore/developer/dashboard)
# Mobile app
We use NativeScript for the [mobile app](https://gitlab.com/passit/passit-mobile/). At this time it's not ready to use.
Passit's mobile app runs via Nativescript. It uses a mono-repo approach described [here](https://docs.nativescript.org/angular/code-sharing/intro)
Basically a file like something.tns.ts will replace the web version of that file.
## Install
1. Install Nativescript [See instructions for Linux](https://docs.nativescript.org/start/ns-setup-linux)
2. Ensure `tns doctor` runs.
3. Set up an emulator or physical device.
## Running
Run `tns run android --bundle`
** Troubleshooting **
- Delete node modules and generated resources `rm -rf hooks platforms node_modules`
- Force a new apk build `tns build android`
### Technologies used
......
This diff is collapsed.
import { Routes } from "@angular/router";
import { LoginContainer } from "./login";
import { LoginComponent } from "./login/login.component";
import { RegisterComponent } from "./register/register.component";
import { RegisterContainer } from "./register/register.container";
export const componentDeclarations: any[] = [
LoginContainer,
LoginComponent,
RegisterComponent,
RegisterContainer
];
export const providerDeclarations: any[] = [];
export const routes: Routes = [];
......@@ -5,21 +5,13 @@ import { NativeScriptHttpModule } from "nativescript-angular/http";
import { StoreModule } from "@ngrx/store";
import { NgrxFormsModule } from "ngrx-forms";
import { LoginContainer } from "./login";
import { LoginComponent } from "./login/login.component";
import { reducers } from "./account.reducer";
import { SharedModule } from "../shared/shared.module";
import { DirectivesModule } from "../directives";
import { ProgressIndicatorModule } from "../progress-indicator";
import { RegisterComponent } from "./register/register.component";
import { RegisterContainer } from "./register/register.container";
import { componentDeclarations } from "./account.common";
export const COMPONENTS = [
LoginContainer,
LoginComponent,
RegisterComponent,
RegisterContainer
];
export const COMPONENTS = componentDeclarations;
export const SERVICES = [];
......
......@@ -17,15 +17,11 @@ import {
import { ConfirmEmailComponent, ConfirmEmailContainer } from "./confirm-email";
import { ConfirmEmailEffects } from "./confirm-email/confirm-email.effects";
import { DeleteComponent, DeleteContainer } from "./delete";
import { LoginContainer } from "./login";
import { RegisterEffects } from "./register/register.effects";
import { UserService } from "./user";
import { ProgressIndicatorModule } from "../progress-indicator";
import { LoginComponent } from "./login/login.component";
import { RegisterComponent } from "./register/register.component";
import { RegisterContainer } from "./register/register.container";
import { SharedModule } from "../shared";
import { LoginFormEffects } from "./login/login.effects";
import { ConfirmEmailGuard } from "./confirm-email/confirm-email.guard";
......@@ -49,6 +45,7 @@ import { SetPasswordComponent } from "./reset-password/set-password/set-password
import { SetPasswordContainer } from "./reset-password/set-password/set-password.container";
import { SetPasswordEffects } from "./reset-password/set-password/set-password.effects";
import { ServerSelectComponent } from "./shared/server-select.component";
import { componentDeclarations } from "./account.common";
export const COMPONENTS = [
AccountComponent,
......@@ -61,10 +58,6 @@ export const COMPONENTS = [
DeleteComponent,
ErrorReportingComponent,
ErrorReportingContainer,
LoginComponent,
LoginContainer,
RegisterComponent,
RegisterContainer,
BackupCodeComponent,
ResetPasswordComponent,
ResetPasswordContainer,
......@@ -77,7 +70,7 @@ export const COMPONENTS = [
ManageBackupCodeContainer,
MarketingFrameComponent,
ServerSelectComponent
];
].concat(componentDeclarations);
export const SERVICES = [UserService, ConfirmEmailGuard, BackupCodePdfService];
......
import { Action } from "@ngrx/store";
import { IUser } from "passit-sdk-js/js/api.interfaces";
import { IUser } from "../../../passit_sdk/api.interfaces";
export enum ErrorReportingTypes {
SAVE_FORM = "[error reporting] Save Form",
......
......@@ -75,7 +75,7 @@ export class RegisterComponent {
checked: boolean;
stages = RegisterStages;
passwordLengthHintText: FormattedString;
passwordLengthHintText: FormattedString | null;
scrollableHeight: number;
@ViewChild("emailInput")
......
......@@ -4,7 +4,8 @@ import { Routes } from "@angular/router";
import { LoginContainer } from "./account/login/login.container";
import { RegisterContainer } from "./account/register/register.container";
import { AlreadyLoggedInGuard } from "./guards";
import { SecretListContainer } from "./list/list.container";
import { AlreadyLoggedInGuard, LoggedInGuard } from "./guards";
export const routes: Routes = [
{
......@@ -29,6 +30,11 @@ export const routes: Routes = [
title: "Register",
showNavBar: false
}
},
{
path: "list",
component: SecretListContainer,
canActivate: [LoggedInGuard]
}
];
......
......@@ -4,12 +4,19 @@ require("nativescript-orientation");
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { StoreModule } from "@ngrx/store";
import { EffectsModule } from "@ngrx/effects";
import { AppRoutingModule } from "./app-routing.module.tns";
import { AppComponent } from "./app.component";
import { AccountModule } from "./account";
import { reducers, metaReducers } from "./app.reducers";
import { AlreadyLoggedInGuard, LoggedInGuard } from "./guards";
import { ListModule } from "./list";
import { GetConfEffects } from "./get-conf/conf.effects";
import { GetConfService } from "./get-conf/";
import { Api } from "./ngsdk/api";
import { NgPassitSDK } from "./ngsdk/sdk";
import { HttpClientModule } from "@angular/common/http";
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from 'nativescript-angular/forms';
......@@ -23,9 +30,18 @@ import { AlreadyLoggedInGuard, LoggedInGuard } from "./guards";
NativeScriptModule,
AppRoutingModule,
AccountModule,
StoreModule.forRoot(reducers, { metaReducers })
ListModule,
HttpClientModule,
StoreModule.forRoot(reducers, { metaReducers }),
EffectsModule.forRoot([GetConfEffects])
],
providers: [
AlreadyLoggedInGuard,
LoggedInGuard,
GetConfService,
{ provide: Api, useClass: Api },
{ provide: NgPassitSDK, useClass: NgPassitSDK }
],
providers: [AlreadyLoggedInGuard, LoggedInGuard],
bootstrap: [AppComponent],
schemas: [NO_ERRORS_SCHEMA]
})
......
import { Injectable } from "@angular/core";
import { saveAs } from "file-saver";
import { unparse } from "papaparse";
import { ISecret } from "passit-sdk-js/js/sdk.interfaces";
import { ISecret } from "../../passit_sdk/sdk.interfaces";
import { NgPassitSDK } from "../ngsdk/sdk";
@Injectable()
......
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from "@angular/core";
import { ISecret } from "passit-sdk-js/js/api.interfaces";
import {
Component,
EventEmitter,
Input,
Output,
ChangeDetectionStrategy
} from "@angular/core";
import { ISecret } from "../../../../passit_sdk/api.interfaces";
@Component({
selector: "app-popup-item",
......@@ -8,19 +14,32 @@ import { ISecret } from "passit-sdk-js/js/api.interfaces";
styleUrls: ["./popup-item.component.scss"]
})
export class PopupItemComponent {
@Input() secret: ISecret;
@Input() formFillMessage: string;
@Input() isMatched = false;
@Input() isSelected = false;
@Input() passwordCopied = false;
@Input() usernameCopied = false;
@Output() openUrl = new EventEmitter();
@Output() autofill = new EventEmitter();
@Output() onCopyUsername = new EventEmitter();
@Output() onCopyPassword = new EventEmitter();
@Output() onDetail = new EventEmitter();
@Output() setSelected = new EventEmitter<number>();
@Output() closeSelected = new EventEmitter();
@Input()
secret: ISecret;
@Input()
formFillMessage: string;
@Input()
isMatched = false;
@Input()
isSelected = false;
@Input()
passwordCopied = false;
@Input()
usernameCopied = false;
@Output()
openUrl = new EventEmitter();
@Output()
autofill = new EventEmitter();
@Output()
onCopyUsername = new EventEmitter();
@Output()
onCopyPassword = new EventEmitter();
@Output()
onDetail = new EventEmitter();
@Output()
setSelected = new EventEmitter<number>();
@Output()
closeSelected = new EventEmitter();
clickAutofill(event: Event) {
event.stopPropagation();
......
import { Action } from "@ngrx/store";
import { ISecret } from "passit-sdk-js/js/api.interfaces";
import { ISecret } from "../../../passit_sdk/api.interfaces";
export enum PopupActionTypes {
SET_SELECTED_SECRET = "[Popup] Set Selected Secret",
......
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from "@angular/core";
import {
Component,
EventEmitter,
Input,
Output,
ChangeDetectionStrategy
} from "@angular/core";
import { ISecret } from "passit-sdk-js/js/api.interfaces";
import { ISecret } from "../../../passit_sdk/api.interfaces";
@Component({
selector: "app-popup",
......@@ -9,21 +15,38 @@ import { ISecret } from "passit-sdk-js/js/api.interfaces";
styleUrls: ["./popup.component.scss"]
})
export class PopupComponent {
@Input() secrets: ISecret[];
@Input() selectedSecret: number | null;
@Input() formFillMessage: string;
@Input() search: string;
@Input() matchedSecrets: ISecret[];
@Input() usernameCopied: number | null;
@Input() passwordCopied: number | null;
@Output() setSelected = new EventEmitter<number>();
@Output() closeSelected = new EventEmitter();
@Output() searchUpdate = new EventEmitter<string>();
@Output() openFull = new EventEmitter();
@Output() openUrl = new EventEmitter<ISecret>();
@Output() signIn = new EventEmitter<ISecret>();
@Output() onCopyUsername = new EventEmitter<ISecret>();
@Output() onCopyPassword = new EventEmitter<ISecret>();
@Output() onDetail = new EventEmitter<ISecret>();
@Output() openFullApp = new EventEmitter();
@Input()
secrets: ISecret[];
@Input()
selectedSecret: number | null;
@Input()
formFillMessage: string;
@Input()
search: string;
@Input()
matchedSecrets: ISecret[];
@Input()
usernameCopied: number | null;
@Input()
passwordCopied: number | null;
@Output()
setSelected = new EventEmitter<number>();
@Output()
closeSelected = new EventEmitter();
@Output()
searchUpdate = new EventEmitter<string>();
@Output()
openFull = new EventEmitter();
@Output()
openUrl = new EventEmitter<ISecret>();
@Output()
signIn = new EventEmitter<ISecret>();
@Output()
onCopyUsername = new EventEmitter<ISecret>();
@Output()
onCopyPassword = new EventEmitter<ISecret>();
@Output()
onDetail = new EventEmitter<ISecret>();
@Output()
openFullApp = new EventEmitter();
}
......@@ -23,7 +23,7 @@ import {
} from "./popup.actions";
import { HotkeysService, Hotkey } from "angular2-hotkeys";
import { formFill } from "./autofill-compiled";
import { ISecret } from "passit-sdk-js/js/api.interfaces";
import { ISecret } from "../../../passit_sdk/api.interfaces";
@Component({
selector: "app-popup-container",
......
import { Action } from "@ngrx/store";
import { IConf } from "passit-sdk-js/js/api.interfaces";
import { IConf } from "../../passit_sdk/api.interfaces";
export enum ConfTypes {
SET_CONF = "[conf] Set Conf",
......
......@@ -10,7 +10,7 @@ import { GetConfService } from "./get-conf.service";
import { cold, hot } from "jasmine-marbles";
import { HandleAPIErrorAction } from "../account/account.actions";
import { IConf } from "passit-sdk-js/js/api.interfaces";
import { IConf } from "../../passit_sdk/api.interfaces";
const junkState: any = null;
......
......@@ -3,7 +3,7 @@ import { Component, EventEmitter, Input, Output } from "@angular/core";
import { IContact } from "../contacts/contacts.interfaces";
import { IGroup } from "../group.interfaces";
import { IGroupForm } from "../group.interfaces";
import { IGroupUser } from "passit-sdk-js/js/api.interfaces";
import { IGroupUser } from "../../../passit_sdk/api.interfaces";
interface ISelectOptions {
label: string;
......@@ -16,26 +16,41 @@ interface ISelectOptions {
"../../list/secret-row/secret-row.component.scss",
"../../list/list.component.scss"
],
templateUrl: "./group-add.component.html",
templateUrl: "./group-add.component.html"
})
export class GroupAddComponent {
group: IGroup;
@Input() contacts: IContact[];
@Input() groupIsUpdating: boolean;
@Input() groupIsUpdated: boolean;
@Input() searchedContacts: ISelectOptions[];
@Input() isPrivateOrgMode: boolean;
@Input() contactLookup: ISelectOptions[];
@Input() groupContacts: ISelectOptions[];
@Input() groupForm: IGroupForm;
@Input() showCreate: boolean;
@Input() singleGroupPendingContacts: IGroupUser[];
@Input()
contacts: IContact[];
@Input()
groupIsUpdating: boolean;
@Input()
groupIsUpdated: boolean;
@Input()
searchedContacts: ISelectOptions[];
@Input()
isPrivateOrgMode: boolean;
@Input()
contactLookup: ISelectOptions[];
@Input()
groupContacts: ISelectOptions[];
@Input()
groupForm: IGroupForm;
@Input()
showCreate: boolean;
@Input()
singleGroupPendingContacts: IGroupUser[];
@Output() saveNew = new EventEmitter();
@Output() hideAddSecretForm = new EventEmitter();
@Output() contactSearch = new EventEmitter<string>();
@Output() resetSearch = new EventEmitter();
@Output() updateFormValues = new EventEmitter<IGroupForm>();
@Output()
saveNew = new EventEmitter();
@Output()
hideAddSecretForm = new EventEmitter();
@Output()
contactSearch = new EventEmitter<string>();
@Output()
resetSearch = new EventEmitter();
@Output()
updateFormValues = new EventEmitter<IGroupForm>();
public onGroupCreated: EventEmitter<boolean>;
......
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { IGroup } from "passit-sdk-js/js/api.interfaces";
import { ChangeDetectionStrategy, Component, Input } from "@angular/core";
import { IGroup } from "../../../passit_sdk/api.interfaces";
@Component({
selector: 'app-group-empty-state',
templateUrl: './group-empty-state.component.html',
styleUrls: ['./group-empty-state.component.scss'],
selector: "app-group-empty-state",
templateUrl: "./group-empty-state.component.html",
styleUrls: ["./group-empty-state.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class GroupEmptyStateComponent {
@Input() showCreate: boolean;
@Input() groups: IGroup[];
@Input() pendingInviteGroups: IGroup[];
@Input()
showCreate: boolean;
@Input()
groups: IGroup[];
@Input()
pendingInviteGroups: IGroup[];
constructor() { }
constructor() {}
}
......@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { IGroup, IGroupForm } from "../group.interfaces";
import { ISelectOptions } from "./group-form.interfaces";
import { IGroupUser } from "passit-sdk-js/js/api.interfaces";
import { IGroupUser } from "../../../passit_sdk/api.interfaces";
@Component({
selector: "group-form",
......@@ -10,24 +10,41 @@ import { IGroupUser } from "passit-sdk-js/js/api.interfaces";
templateUrl: "./group-form.component.html"
})
export class GroupFormComponent implements OnInit {
@Output() back = new EventEmitter();
@Output() hideAddSecretForm = new EventEmitter();
@Output() save = new EventEmitter();
@Output() contactSearch = new EventEmitter<string>();
@Output() resetSearch = new EventEmitter();
@Output() delete = new EventEmitter<number>();
@Output() updateFormValues = new EventEmitter<IGroupForm>();
@Output()
back = new EventEmitter();
@Output()
hideAddSecretForm = new EventEmitter();
@Output()
save = new EventEmitter();
@Output()
contactSearch = new EventEmitter<string>();
@Output()
resetSearch = new EventEmitter();
@Output()
delete = new EventEmitter<number>();
@Output()
updateFormValues = new EventEmitter<IGroupForm>();
@Input() groupContacts: ISelectOptions[];
@Input() groupManaged: number;
@Input() isNew = false;
@Input() groupIsUpdating: boolean;
@Input() groupIsUpdated: boolean;
@Input() isPrivateOrgMode: boolean;
@Input() contactLookup: ISelectOptions[];
@Input() group: IGroup;
@Input() groupForm: IGroupForm;
@Input() singleGroupPendingContacts: IGroupUser[];
@Input()
groupContacts: ISelectOptions[];
@Input()
groupManaged: number;
@Input()
isNew = false;
@Input()
groupIsUpdating: boolean;
@Input()
groupIsUpdated: boolean;
@Input()
isPrivateOrgMode: boolean;
@Input()
contactLookup: ISelectOptions[];
@Input()
group: IGroup;
@Input()
groupForm: IGroupForm;
@Input()
singleGroupPendingContacts: IGroupUser[];
privateOrgMemberOptions: ISelectOptions[] = [];
memberOptions: ISelectOptions[] = [];
......
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { IGroup, IGroupUser } from "passit-sdk-js/js/api.interfaces";
import { IGroup, IGroupUser } from "../../passit_sdk/api.interfaces";
import { IContact } from "./contacts/contacts.interfaces";
import { IGroupForm } from "./group.interfaces";
......
import { Action } from "@ngrx/store";
import { IGroup } from "passit-sdk-js/js/api.interfaces";
import { IGroup } from "../../passit_sdk/api.interfaces";
import { IGroupForm } from "./group.interfaces";
export enum GroupActionTypes {
......
import { ChangeDetectionStrategy, Component, OnInit } from "@angular/core";
import { Store, select } from "@ngrx/store";
import { IGroup } from "passit-sdk-js/js/api.interfaces";
import { IGroup } from "../../passit_sdk/api.interfaces";
import { Observable } from "rxjs";
import * as fromRoot from "../app.reducers";
import { getIsPrivateOrgMode } from "../app.reducers";
......
import * as api from "passit-sdk-js/js/api.interfaces";
import * as api from "../../passit_sdk/api.interfaces";
export interface IGroupForm {
id?: number;
......
......@@ -3,7 +3,7 @@ import { Injectable } from "@angular/core";
import { NgPassitSDK } from "../ngsdk/sdk";
import { IGroupForm } from "./group.interfaces";
import { IContact } from "./contacts/contacts.interfaces";
import { IGroup } from "passit-sdk-js/js/api.interfaces";
import { IGroup } from "../../passit_sdk/api.interfaces";
@Injectable()
export class GroupService {
......
import { INewSecret } from "passit-sdk-js/js/sdk.interfaces";
import { INewSecret } from "../../passit_sdk/sdk.interfaces";
export interface ImportableSecret extends INewSecret {
doImport: boolean;
......
import { Routes } from "@angular/router";
import { SecretListContainer } from "./list.container";
export const componentDeclarations: any[] = [SecretListContainer];
export const providerDeclarations: any[] = [];
export const routes: Routes = [];
import {
Component,
Input,
Output,
EventEmitter,
AfterViewInit
} from "@angular/core";
import { DeviceType } from "ui/enums";
import { device } from "platform";