✨. Joint key Setup & Setup for API Project(#63)
* working version * moved jointkey mocks to api * moving mocks and models to api project * adding joint key setup to the library webpage adding calling the backend server async to get the data adding the async http calls to be available change build to allow api to be built when the library is tested locally * Build fixes * build changes * Changed jsx setting to get builds to work * build issue not finding api package * getting ci/cd to recognize local package * Cleaned up the tsconfig files to make the api inherit the main one. Had to move jsx into each project separately * move storybook dependancies to just the library project * remove the util file that is not needed in the api project * Cleaned up mock names * clean up issues from review * change order on analysis * removed extra script * cleanup scripts * renamed the env variable to say mock or server * updating the analysis settings * cleanup for the code scanning
This commit is contained in:
Родитель
a819bb58be
Коммит
7ce17ceb35
|
@ -6,7 +6,7 @@ Dockerfile
|
|||
build
|
||||
node_modules
|
||||
storybook-static
|
||||
packages/api/build
|
||||
packages/api/dist
|
||||
packages/api/node_modules
|
||||
packages/library/build
|
||||
packages/library/node_modules
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
paths:
|
||||
- 'packages/**/src'
|
||||
paths-ignore:
|
||||
- 'packages/**/build'
|
||||
- 'packages/**/dist'
|
|
@ -1,40 +1,41 @@
|
|||
name: "CodeQL"
|
||||
name: 'CodeQL'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '35 6 * * 5'
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '35 6 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['javascript']
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
make install
|
||||
make build
|
||||
- name: Build
|
||||
run: |
|
||||
make install
|
||||
make build
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
run: make install
|
||||
- name: Lint
|
||||
run: make lint
|
||||
- name: Test
|
||||
run: make test
|
||||
- name: Build
|
||||
run: make build
|
||||
- name: Test
|
||||
run: make test
|
||||
|
|
|
@ -4,4 +4,7 @@
|
|||
**/storybook-static/
|
||||
|
||||
# ignore mac file
|
||||
.DS_store
|
||||
.DS_store
|
||||
|
||||
**/dist
|
||||
**/tsconfig.tsbuildinfo
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:14.10
|
||||
FROM node:14.15
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./package.json .
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:14.10
|
||||
FROM node:14.15
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./package.json .
|
||||
|
|
3
Makefile
3
Makefile
|
@ -22,6 +22,9 @@ build-storybook:
|
|||
test:
|
||||
lerna run test
|
||||
|
||||
local:
|
||||
lerna run local
|
||||
|
||||
# Docker
|
||||
docker-dev-app:
|
||||
@echo 🐳 Running app in Docker with live reload 🚀
|
||||
|
|
29
package.json
29
package.json
|
@ -6,7 +6,34 @@
|
|||
],
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"lerna": "^4.0.0"
|
||||
"@babel/core": "^7.13.15",
|
||||
"@prettier/plugin-xml": "^0.13.1",
|
||||
"@testing-library/dom": "^7.30.3",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"babel-loader": "8.1.0",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||
"eslint-config-prettier": "^8.2.0",
|
||||
"eslint-plugin-formatjs": "^2.14.10",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jest": "^24.3.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"husky": "^6.0.0",
|
||||
"import-sort-style-module": "^6.0.0",
|
||||
"jest": "26.6.0",
|
||||
"lerna": "^4.0.0",
|
||||
"prettier": "2.2.1",
|
||||
"prettier-plugin-import-sort": "^0.0.6",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"typescript": "^4.3.5",
|
||||
"webpack": "4.44.2"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
{
|
||||
"name": "@electionguard-ui/api",
|
||||
"version": "0.1.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
}
|
||||
"name": "@electionguard-ui/api",
|
||||
"version": "0.2.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"/dist"
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"build-local": "yarn build"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
export default interface Api {
|
||||
healthCheck: () => boolean;
|
||||
}
|
||||
import ElectionRow from './models/ElectionRow';
|
||||
import User from './models/user';
|
||||
import AssignedGuardian from './models/assignedGuardian';
|
||||
import { BaseJointKey, JointKey } from './models/jointKey';
|
||||
import ManifestPreview from './models/manifestPreview';
|
||||
import { KeyCeremony, KeyCeremonyGuardian } from './models/keyCeremony';
|
||||
import KeyCeremonyStep from './models/KeyCeremonyStep';
|
||||
|
||||
export default interface ElectionGuardApiClient {
|
||||
healthCheck: () => boolean;
|
||||
getUsersWithGuardianRole(): Promise<User[]>;
|
||||
createJointKey(data: BaseJointKey): Promise<boolean>;
|
||||
|
||||
getElections(): ElectionRow[];
|
||||
getAssignedGuardians(): AssignedGuardian[];
|
||||
getJointKeys(): JointKey[];
|
||||
getManifestPreview(): ManifestPreview;
|
||||
|
||||
// key ceremony methods
|
||||
getKeyCeremonyGuardians(): KeyCeremonyGuardian[];
|
||||
setKeyCeremonyGuardianToStep(
|
||||
guardian: KeyCeremonyGuardian,
|
||||
step: KeyCeremonyStep
|
||||
): KeyCeremonyGuardian;
|
||||
getKeyCeremonyGuardiansByStep(step: KeyCeremonyStep): KeyCeremonyGuardian[];
|
||||
getKeyCeremonies(): KeyCeremony[];
|
||||
createGuardian(id: string, name: string, sequenceOrder: number): void;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,33 @@
|
|||
import Api from "./Api";
|
||||
import ElectionGuardApiClient from "./Api";
|
||||
import { getElections as mockGetElections } from './mocks/elections';
|
||||
import { getJointKeys as mockGetJointKeys, getManifestPreview as mockGetManifestPreview } from './mocks/electionSetup';
|
||||
import { getUsersWithGuardianRole as mockGetUsersWithGuardianRole } from './mocks/users';
|
||||
import { getAssignedGuardians as mockGetAssignedGuardians, createGuardian as mockCreateGuardian } from './mocks/guardians';
|
||||
import { createJointKey as mockCreateJointKey } from './mocks/jointKey';
|
||||
import { getKeyCeremonies as mockGetKeyCeremonies, getKeyCeremonyGuardians as mockGetKeyCeremonyGuardians, setKeyCeremonyGuardianToStep as mockSetKeyCeremonyGuardianToStep, getKeyCeremonyGuardiansByStep as mockGetKeyCeremonyGuardiansByStep } from './mocks/keyCeremony';
|
||||
|
||||
export default class MockApi implements Api {
|
||||
healthCheck = () => true;
|
||||
export default class MockApi implements ElectionGuardApiClient {
|
||||
getElections = mockGetElections;
|
||||
|
||||
getUsersWithGuardianRole = mockGetUsersWithGuardianRole;
|
||||
|
||||
getAssignedGuardians = mockGetAssignedGuardians;
|
||||
|
||||
createJointKey = mockCreateJointKey;
|
||||
|
||||
getJointKeys = mockGetJointKeys;
|
||||
|
||||
getManifestPreview = mockGetManifestPreview;
|
||||
|
||||
getKeyCeremonyGuardians = mockGetKeyCeremonyGuardians;
|
||||
|
||||
setKeyCeremonyGuardianToStep = mockSetKeyCeremonyGuardianToStep;
|
||||
|
||||
getKeyCeremonyGuardiansByStep = mockGetKeyCeremonyGuardiansByStep;
|
||||
|
||||
getKeyCeremonies = mockGetKeyCeremonies;
|
||||
|
||||
createGuardian = mockCreateGuardian;
|
||||
|
||||
healthCheck = (): boolean => true;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import ElectionGuardApiClient from './Api';
|
||||
import { getUsersWithGuardianRole as serverGetUsersWithGuardianRole } from './server/users'
|
||||
import { createJointKey as serverCreateJointKey } from './server/jointKey'
|
||||
import { getElections as serverGetElections } from './server/elections';
|
||||
import { getAssignedGuardians as serverGetAssignedGuardians, createGuardian as serverCreateGuardian } from './server/guardians'
|
||||
import { getJointKeys as serverGetJointKeys, getManifestPreview as serverGetManifestPreview } from './server/electionSetup';
|
||||
import { getKeyCeremonies as serverGetKeyCeremonies, getKeyCeremonyGuardians as serverGetKeyCeremonyGuardians, setKeyCeremonyGuardianToStep as serverSetKeyCeremonyGuardianToStep, getKeyCeremonyGuardiansByStep as serverGetKeyCeremonyGuardiansByStep } from './server/keyCeremony';
|
||||
|
||||
export default class ServiceApi implements ElectionGuardApiClient {
|
||||
getElections = serverGetElections;
|
||||
|
||||
getUsersWithGuardianRole = serverGetUsersWithGuardianRole;
|
||||
|
||||
getAssignedGuardians = serverGetAssignedGuardians;
|
||||
|
||||
createJointKey = serverCreateJointKey;
|
||||
|
||||
getJointKeys = serverGetJointKeys;
|
||||
|
||||
getManifestPreview = serverGetManifestPreview;
|
||||
|
||||
getKeyCeremonyGuardians = serverGetKeyCeremonyGuardians;
|
||||
|
||||
setKeyCeremonyGuardianToStep = serverSetKeyCeremonyGuardianToStep;
|
||||
|
||||
getKeyCeremonyGuardiansByStep = serverGetKeyCeremonyGuardiansByStep;
|
||||
|
||||
getKeyCeremonies = serverGetKeyCeremonies;
|
||||
|
||||
createGuardian = serverCreateGuardian;
|
||||
|
||||
healthCheck = (): boolean => true;
|
||||
}
|
|
@ -1,2 +1,29 @@
|
|||
export type { default as Api } from './Api';
|
||||
export type { default as MockApi } from './MockApi';
|
||||
import ElectionGuardApiClient from "./Api"
|
||||
import MockApi from './MockApi';
|
||||
import ServiceApi from './ServiceApi';
|
||||
|
||||
export type { default as ElectionGuardApiClient } from './Api';
|
||||
export type { default as AssignedGuardian } from './models/assignedGuardian';
|
||||
export type { BaseJointKey, JointKey } from './models/jointKey';
|
||||
export type { default as User } from './models/user';
|
||||
export type { default as ManifestPreview } from './models/manifestPreview';
|
||||
export { default as TaskStatus } from './models/taskStatus';
|
||||
export type { KeyCeremony, BackupVerification, KeyCeremonyGuardian } from './models/keyCeremony';
|
||||
export { KeyCeremonyStatus } from './models/keyCeremony';
|
||||
|
||||
export { default as MockApi } from './MockApi';
|
||||
export { default as ServiceApi } from './ServiceApi';
|
||||
|
||||
let data: ElectionGuardApiClient;
|
||||
|
||||
export function getApiClient() : ElectionGuardApiClient {
|
||||
if(!data) {
|
||||
if (process.env.REACT_APP_MOCK_ENABLED === 'true') {
|
||||
data = new MockApi();
|
||||
}
|
||||
|
||||
data = new ServiceApi();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import JointKey from '../models/jointKey';
|
||||
import { JointKey } from '../models/jointKey';
|
||||
import ManifestPreview from '../models/manifestPreview';
|
||||
import { getAssignedGuardians } from './guardians';
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import ElectionRow from '../components/ElectionTable/ElectionRow';
|
||||
import ElectionRow from '../models/ElectionRow';
|
||||
|
||||
const getElections = (): ElectionRow[] => {
|
||||
export const getElections = (): ElectionRow[] => {
|
||||
const date = new Date();
|
||||
const laterDate = new Date();
|
||||
laterDate.setDate(date.getDate() + 10);
|
|
@ -0,0 +1,14 @@
|
|||
import AssignedGuardian from '../models/assignedGuardian';
|
||||
|
||||
export const getAssignedGuardians = (): AssignedGuardian[] => [
|
||||
{ sequenceOrder: 1, id: '1', name: 'Snow mock' },
|
||||
{ sequenceOrder: 2, id: '2', name: 'Lannister mock' },
|
||||
{ sequenceOrder: 3, id: '3', name: 'Magic mock' },
|
||||
{ sequenceOrder: 4, id: '4', name: 'Stark mock' },
|
||||
{ sequenceOrder: 5, id: '5', name: 'Targaryen mock' },
|
||||
];
|
||||
|
||||
export const createGuardian = (id: string, name: string, sequenceOrder: number): void => {
|
||||
}
|
||||
|
||||
export default getAssignedGuardians;
|
|
@ -0,0 +1,5 @@
|
|||
import { BaseJointKey } from '../models/jointKey';
|
||||
|
||||
export const createJointKey = async (data: BaseJointKey): Promise<boolean> => true;
|
||||
|
||||
export default createJointKey;
|
|
@ -1,4 +1,4 @@
|
|||
import KeyCeremonyStep from '../components/KeyCeremonyWizard/KeyCeremonyStep';
|
||||
import KeyCeremonyStep from '../models/KeyCeremonyStep';
|
||||
import { KeyCeremony, KeyCeremonyGuardian, KeyCeremonyStatus } from '../models/keyCeremony';
|
||||
import TaskStatus from '../models/taskStatus';
|
||||
import { getAssignedGuardians } from './guardians';
|
|
@ -0,0 +1,15 @@
|
|||
import User from '../models/user';
|
||||
|
||||
export const getUsersWithGuardianRole = async (): Promise<User[]> => [
|
||||
{ id: '1', name: 'Snow mock' },
|
||||
{ id: '2', name: 'Lannister mock' },
|
||||
{ id: '3', name: 'Magic mock' },
|
||||
{ id: '4', name: 'Stark mock' },
|
||||
{ id: '5', name: 'Targaryen mock' },
|
||||
{ id: '6', name: 'Melisandre mock' },
|
||||
{ id: '7', name: 'Clifford mock' },
|
||||
{ id: '8', name: 'Frances mock' },
|
||||
{ id: '9', name: 'Roxie mock' },
|
||||
];
|
||||
|
||||
export default getUsersWithGuardianRole;
|
|
@ -0,0 +1,36 @@
|
|||
import { ElectionRowData } from './ElectionRowData';
|
||||
|
||||
class ElectionRow implements ElectionRowData {
|
||||
/**
|
||||
* Row of Election Data
|
||||
*/
|
||||
constructor(
|
||||
id: string,
|
||||
name: string,
|
||||
state: string,
|
||||
jurisdiction: string,
|
||||
dateCreated: Date,
|
||||
isNew = false
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.state = state;
|
||||
this.jurisdiction = jurisdiction;
|
||||
this.dateCreated = dateCreated;
|
||||
this.isNew = isNew;
|
||||
}
|
||||
|
||||
id: string;
|
||||
|
||||
isNew: boolean;
|
||||
|
||||
name: string;
|
||||
|
||||
state: string;
|
||||
|
||||
jurisdiction: string;
|
||||
|
||||
dateCreated: Date;
|
||||
}
|
||||
|
||||
export default ElectionRow;
|
|
@ -0,0 +1,10 @@
|
|||
import { GridRowData } from '@material-ui/data-grid';
|
||||
|
||||
export interface ElectionRowData extends GridRowData {
|
||||
id: string;
|
||||
isNew: boolean;
|
||||
name: string;
|
||||
state: string;
|
||||
jurisdiction: string;
|
||||
dateCreated: Date;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
enum KeyCeremonyStep {
|
||||
Instructions = 0,
|
||||
MeetGuardians = 1,
|
||||
CreateKeyPair = 2,
|
||||
SharePublicKey = 3,
|
||||
CreateBackups = 4,
|
||||
ShareBackups = 5,
|
||||
VerifyBackups = 6,
|
||||
CombineKeys = 7,
|
||||
Complete = 8,
|
||||
}
|
||||
|
||||
export default KeyCeremonyStep;
|
|
@ -0,0 +1,6 @@
|
|||
import React, { SVGProps } from 'react';
|
||||
|
||||
export default interface Config {
|
||||
appName: string;
|
||||
logo: React.ComponentType<SVGProps<SVGSVGElement>>;
|
||||
}
|
|
@ -7,7 +7,8 @@ export interface BaseJointKey {
|
|||
guardians: AssignedGuardian[];
|
||||
}
|
||||
|
||||
export default interface JointKey extends BaseJointKey {
|
||||
export interface JointKey extends BaseJointKey {
|
||||
id: string;
|
||||
dateCreated: Date;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { Localization } from '@material-ui/core/locale';
|
||||
|
||||
export default interface Language {
|
||||
name: string;
|
||||
locale: string;
|
||||
messages: { [key: string]: string };
|
||||
mui: Localization;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { JointKey } from '../models/jointKey';
|
||||
import ManifestPreview from '../models/manifestPreview';
|
||||
import { getAssignedGuardians } from './guardians';
|
||||
|
||||
export const getManifestPreview = (): ManifestPreview => {
|
||||
const endDate = new Date();
|
||||
endDate.setDate(endDate.getDate() + 2);
|
||||
return {
|
||||
name: 'Montgomery County Election',
|
||||
numberOfContests: 5,
|
||||
numberOfStyles: 3,
|
||||
startDate: new Date(),
|
||||
endDate,
|
||||
fileHash: '1234lasdf98j3124klajksdflajsdfio',
|
||||
fileName: 'manifest.json',
|
||||
};
|
||||
};
|
||||
|
||||
export const getJointKeys = (): JointKey[] => [
|
||||
{
|
||||
id: 'joint-key-1',
|
||||
name: 'Joint Key 1',
|
||||
numberOfGuardians: 3,
|
||||
quorum: 2,
|
||||
guardians: getAssignedGuardians(),
|
||||
dateCreated: new Date(),
|
||||
},
|
||||
{
|
||||
id: 'joint-key-2',
|
||||
name: 'Joint Key 2',
|
||||
numberOfGuardians: 3,
|
||||
quorum: 2,
|
||||
guardians: getAssignedGuardians(),
|
||||
dateCreated: new Date(),
|
||||
},
|
||||
];
|
|
@ -0,0 +1,16 @@
|
|||
import ElectionRow from '../models/ElectionRow';
|
||||
|
||||
export const getElections = (): ElectionRow[] => {
|
||||
const date = new Date();
|
||||
const laterDate = new Date();
|
||||
laterDate.setDate(date.getDate() + 10);
|
||||
return [
|
||||
new ElectionRow('election-1s', 'Election 1 server', 'Maryland', 'Montgomery County', date, true),
|
||||
new ElectionRow('election-2s', 'Election 2 server', 'Maryland', 'Montgomery County', date),
|
||||
new ElectionRow('election-3s', 'Election 3 server', 'Maryland', 'Montgomery County', date),
|
||||
new ElectionRow('election-4s', 'Election 4 server', 'Maryland', 'Montgomery County', laterDate),
|
||||
new ElectionRow('election-5s', 'Election 5 server', 'Maryland', 'Montgomery County', laterDate),
|
||||
];
|
||||
};
|
||||
|
||||
export default getElections;
|
|
@ -0,0 +1,27 @@
|
|||
import AssignedGuardian from '../models/assignedGuardian';
|
||||
import { post } from '../utils/http';
|
||||
|
||||
export const getAssignedGuardians = (): AssignedGuardian[] => [
|
||||
{ sequenceOrder: 1, id: '1', name: 'Snow server' },
|
||||
{ sequenceOrder: 2, id: '2', name: 'Lannister server' },
|
||||
{ sequenceOrder: 3, id: '3', name: 'Magic server' },
|
||||
{ sequenceOrder: 4, id: '4', name: 'Stark server' },
|
||||
{ sequenceOrder: 5, id: '5', name: 'Targaryen server' },
|
||||
];
|
||||
|
||||
export const createGuardian = async (id: string, username: string, sequenceOrder: number): Promise<string> => {
|
||||
const data = {
|
||||
guardian_id: id,
|
||||
sequence_order: sequenceOrder,
|
||||
number_of_guardians: 3,
|
||||
quorum: 2,
|
||||
name: username,
|
||||
key_name: ""
|
||||
};
|
||||
const path = `${process.env.REACT_APP_GUARDIAN_SERVICE}guardian`;
|
||||
const response = await post<string>(path, data);
|
||||
|
||||
return response.arrayBuffer.toString();
|
||||
}
|
||||
|
||||
export default getAssignedGuardians;
|
|
@ -0,0 +1,18 @@
|
|||
import { BaseJointKey } from '../models/jointKey';
|
||||
import { put } from '../utils/http';
|
||||
|
||||
export const createJointKey = async (data: BaseJointKey): Promise<boolean> => {
|
||||
const submitData = {
|
||||
key_name: data.name,
|
||||
number_of_guardians: data.numberOfGuardians,
|
||||
quorum: data.quorum,
|
||||
guardian_ids: data.guardians.map((g) => g.id),
|
||||
};
|
||||
|
||||
const path = `${process.env.REACT_APP_MEDIATOR_SERVICE}key/ceremony`;
|
||||
const response = await put<string>(path, submitData);
|
||||
|
||||
return response.ok;
|
||||
};
|
||||
|
||||
export default createJointKey;
|
|
@ -0,0 +1,54 @@
|
|||
import KeyCeremonyStep from '../models/KeyCeremonyStep';
|
||||
import { KeyCeremony, KeyCeremonyGuardian, KeyCeremonyStatus } from '../models/keyCeremony';
|
||||
import TaskStatus from '../models/taskStatus';
|
||||
import { getAssignedGuardians } from './guardians';
|
||||
|
||||
export const getKeyCeremonyGuardians = (): KeyCeremonyGuardian[] =>
|
||||
getAssignedGuardians().map((guardian) => ({
|
||||
...guardian,
|
||||
keypairCreated: TaskStatus.Incomplete,
|
||||
backupsCreated: TaskStatus.Incomplete,
|
||||
publicKeyShared: TaskStatus.Incomplete,
|
||||
backupsShared: TaskStatus.Incomplete,
|
||||
backupsVerified: TaskStatus.Incomplete,
|
||||
verifications: [],
|
||||
}));
|
||||
|
||||
export const setKeyCeremonyGuardianToStep = (
|
||||
guardian: KeyCeremonyGuardian,
|
||||
step: KeyCeremonyStep
|
||||
): KeyCeremonyGuardian => ({
|
||||
...guardian,
|
||||
keypairCreated:
|
||||
step > KeyCeremonyStep.CreateKeyPair ? TaskStatus.Complete : TaskStatus.Incomplete,
|
||||
backupsCreated:
|
||||
step > KeyCeremonyStep.CreateBackups ? TaskStatus.Complete : TaskStatus.Incomplete,
|
||||
publicKeyShared:
|
||||
step > KeyCeremonyStep.SharePublicKey ? TaskStatus.Complete : TaskStatus.Incomplete,
|
||||
backupsShared:
|
||||
step > KeyCeremonyStep.ShareBackups ? TaskStatus.Complete : TaskStatus.Incomplete,
|
||||
backupsVerified:
|
||||
step > KeyCeremonyStep.VerifyBackups ? TaskStatus.Complete : TaskStatus.Incomplete,
|
||||
verifications: getAssignedGuardians()
|
||||
.filter((g) => g.id !== guardian.id)
|
||||
.map((g) => ({
|
||||
verifier: guardian,
|
||||
owner: g,
|
||||
verified: TaskStatus.Incomplete,
|
||||
})),
|
||||
});
|
||||
|
||||
export const getKeyCeremonyGuardiansByStep = (step: KeyCeremonyStep): KeyCeremonyGuardian[] =>
|
||||
getKeyCeremonyGuardians().map((guardian) => setKeyCeremonyGuardianToStep(guardian, step));
|
||||
|
||||
export const getKeyCeremonies = (): KeyCeremony[] => [
|
||||
{
|
||||
id: 'key-ceremony-1',
|
||||
status: KeyCeremonyStatus.Active,
|
||||
name: 'Montgomery County Election',
|
||||
numberOfGuardians: 5,
|
||||
quorum: 3,
|
||||
guardians: getKeyCeremonyGuardians(),
|
||||
dateCreated: new Date(),
|
||||
},
|
||||
];
|
|
@ -0,0 +1,19 @@
|
|||
import User from '../models/user';
|
||||
import { post } from '../utils/http';
|
||||
|
||||
export const getUsersWithGuardianRole = async (): Promise<User[]> => {
|
||||
const users: User[] = [];
|
||||
const data = {};
|
||||
const path = `${process.env.REACT_APP_GUARDIAN_SERVICE}guardian/find?skip=0&limit=100`;
|
||||
|
||||
const response = await post<{status:string, message:string, guardians:{guardian_id:string, name:string}[]}>(path, data);
|
||||
if(typeof response.parsedBody !== "undefined") {
|
||||
response.parsedBody.guardians.forEach((item) => {
|
||||
users.push({id: item.guardian_id, name: item.name});
|
||||
});
|
||||
}
|
||||
|
||||
return users;
|
||||
};
|
||||
|
||||
export default getUsersWithGuardianRole;
|
|
@ -0,0 +1,5 @@
|
|||
type EnumDictionary<T extends string | symbol | number, U> = {
|
||||
[K in T]: U;
|
||||
};
|
||||
|
||||
export default EnumDictionary;
|
|
@ -0,0 +1,3 @@
|
|||
const delay = (ms: number): Promise<unknown> => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
export default delay;
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
interface HttpResponse<T> extends Response {
|
||||
parsedBody?: T;
|
||||
}
|
||||
|
||||
async function http<T>(
|
||||
request: RequestInfo
|
||||
): Promise<HttpResponse<T>> {
|
||||
const response: HttpResponse<T> = await fetch(
|
||||
request
|
||||
);
|
||||
|
||||
try {
|
||||
// may error if there is no body
|
||||
response.parsedBody = await response.json();
|
||||
} catch (ex) {}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function get<T>(
|
||||
path: string,
|
||||
args: RequestInit = { method: "get" }
|
||||
): Promise<HttpResponse<T>> {
|
||||
return await http<T>(new Request(path, args));
|
||||
};
|
||||
|
||||
export async function post<T>(
|
||||
path: string,
|
||||
body: any,
|
||||
args: RequestInit = { method: "post", body: JSON.stringify(body) }
|
||||
): Promise<HttpResponse<T>> {
|
||||
return await http<T>(new Request(path, args));
|
||||
};
|
||||
|
||||
export async function put<T>(
|
||||
path: string,
|
||||
body: any,
|
||||
args: RequestInit = { method: "put", body: JSON.stringify(body) }
|
||||
): Promise<HttpResponse<T>> {
|
||||
return await http<T>(new Request(path, args));
|
||||
};
|
|
@ -2,7 +2,14 @@
|
|||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"outDir": "./build"
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"lib": ["dom", "ESNext"],
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"composite": false,
|
||||
"jsx": "react",
|
||||
"noEmit": false
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
REACT_APP_MEDIATOR_SERVICE=http://localhost:8000/api/v1/
|
||||
REACT_APP_GUARDIAN_SERVICE=http://localhost:8001/api/v1/
|
||||
REACT_APP_MOCK_ENABLED=false
|
|
@ -0,0 +1,3 @@
|
|||
REACT_APP_MEDIATOR_SERVICE=http://localhost:8000/api/v1/
|
||||
REACT_APP_GUARDIAN_SERVICE=http://localhost:8001/api/v1/
|
||||
REACT_APP_DATA=MOCK
|
|
@ -0,0 +1,3 @@
|
|||
REACT_APP_MEDIATOR_SERVICE=http://localhost:8000/api/v1/
|
||||
REACT_APP_GUARDIAN_SERVICE=http://localhost:8001/api/v1/
|
||||
REACT_APP_MOCK_ENABLED=false
|
|
@ -2,20 +2,36 @@
|
|||
"name": "@electionguard-ui/library",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.13.15",
|
||||
"@electionguard-ui/api": "0.2.0",
|
||||
"@material-ui/core": "^4.11.3",
|
||||
"@material-ui/data-grid": "^4.0.0-alpha.29",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.58",
|
||||
"@storybook/addon-actions": "^6.2.7",
|
||||
"@storybook/addon-essentials": "^6.2.7",
|
||||
"@storybook/addon-links": "^6.2.7",
|
||||
"@storybook/cli": "^6.2.7",
|
||||
"@storybook/node-logger": "^6.2.7",
|
||||
"@storybook/preset-create-react-app": "^3.1.7",
|
||||
"@storybook/react": "^6.2.7",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/react": "^17.0.2",
|
||||
"@types/react-dom": "^17.0.2",
|
||||
"@types/react-intl": "^3.0.0",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"clsx": "^1.1.1",
|
||||
"eslint-plugin-formatjs": "^2.14.10",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-intl": "^5.17.4",
|
||||
"react-query": "^3.23.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"typescript": "^4.3.5",
|
||||
|
@ -25,6 +41,7 @@
|
|||
"trim": "^0.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"local": "react-scripts start",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
|
@ -61,41 +78,6 @@
|
|||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.13.15",
|
||||
"@prettier/plugin-xml": "^0.13.1",
|
||||
"@storybook/addon-actions": "^6.2.7",
|
||||
"@storybook/addon-essentials": "^6.2.7",
|
||||
"@storybook/addon-links": "^6.2.7",
|
||||
"@storybook/cli": "^6.2.7",
|
||||
"@storybook/node-logger": "^6.2.7",
|
||||
"@storybook/preset-create-react-app": "^3.1.7",
|
||||
"@storybook/react": "^6.2.7",
|
||||
"@testing-library/dom": "^7.30.3",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"babel-loader": "8.1.0",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||
"eslint-config-prettier": "^8.2.0",
|
||||
"eslint-plugin-formatjs": "^2.14.10",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jest": "^24.3.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"husky": "^6.0.0",
|
||||
"import-sort-style-module": "^6.0.0",
|
||||
"jest": "26.6.0",
|
||||
"prettier": "2.2.1",
|
||||
"prettier-plugin-import-sort": "^0.0.6",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"webpack": "4.44.2"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged --pattern '{src,public}/**/*.{js,jsx,ts,tsx,css,html}'"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getUsersWithGuardianRole } from '../../mocks/users';
|
||||
import AssignmentTable, { AssignmentTableProps } from './AssignmentTable';
|
||||
|
||||
export default {
|
||||
|
@ -11,9 +11,12 @@ export default {
|
|||
} as Meta;
|
||||
|
||||
const Template: Story<AssignmentTableProps> = (props) => <AssignmentTable {...props} />;
|
||||
const service = getApiClient();
|
||||
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
const userData = await service.getUsersWithGuardianRole();
|
||||
|
||||
Standard.args = {
|
||||
data: getUsersWithGuardianRole(),
|
||||
data: userData,
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { User } from '@electionguard-ui/api';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef, GridRowId } from '@material-ui/data-grid';
|
||||
import * as React from 'react';
|
||||
|
||||
import User from '../../models/user';
|
||||
import FilterToolbar from '../FilterToolbar';
|
||||
|
||||
export interface AssignmentTableProps {
|
||||
|
@ -17,6 +17,7 @@ const columns: GridColDef[] = [
|
|||
|
||||
const AssignmentTable: React.FC<AssignmentTableProps> = ({ data, onChanged }) => {
|
||||
const [selectionModel, setSelectionModel] = React.useState<GridRowId[]>([]);
|
||||
|
||||
const onSelectionChange = (rows: GridRowId[]) => {
|
||||
setSelectionModel(rows);
|
||||
onChanged(rows.map((rowId: GridRowId) => rowId.toString()));
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react';
|
||||
|
||||
import { AsyncResult } from '../../data/AsyncResult';
|
||||
|
||||
// import InternationalText from '../InternationalText';
|
||||
|
||||
// import { Spinner, SpinnerSize, StackItem } from '@fluentui/react';
|
||||
|
||||
export interface AsyncContentProps<T> {
|
||||
children: (data: T) => React.ReactElement;
|
||||
errorMessage?: string;
|
||||
query: AsyncResult<T>;
|
||||
}
|
||||
|
||||
function AsyncContent<T>({
|
||||
children,
|
||||
errorMessage = 'Something went wrong!',
|
||||
query,
|
||||
}: AsyncContentProps<T>): React.ReactElement {
|
||||
const { data, isLoading, isError } = query;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<>
|
||||
<p>Loading</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (isError || data === undefined) {
|
||||
return (
|
||||
<>
|
||||
<p>Error {errorMessage}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <>{children(data)}</>;
|
||||
}
|
||||
|
||||
export default AsyncContent;
|
|
@ -0,0 +1,5 @@
|
|||
import AsyncContent from './AsyncContent';
|
||||
|
||||
export type { AsyncContentProps } from './AsyncContent';
|
||||
|
||||
export default AsyncContent;
|
|
@ -1,10 +1,10 @@
|
|||
import { TaskStatus } from '@electionguard-ui/api';
|
||||
import { Chip } from '@material-ui/core';
|
||||
import { GridCellParams } from '@material-ui/data-grid';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { IntlShape } from 'react-intl';
|
||||
|
||||
import { Message } from '../../lang';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import { getColor } from '../../theme';
|
||||
import FormattedButton from '../FormattedButton';
|
||||
import GuardianIcon from '../GuardianIcon';
|
||||
|
@ -19,7 +19,8 @@ export const NewCell = (params: GridCellParams): ReactElement => {
|
|||
|
||||
export const FormattedDateCell = (params: GridCellParams, intl: IntlShape): ReactElement => {
|
||||
const { value } = params;
|
||||
return <>{intl.formatDate(value?.toString())}</>;
|
||||
const { formatDate } = intl;
|
||||
return <>{formatDate(value?.toString())}</>;
|
||||
};
|
||||
|
||||
export const GuardianIconCell = (params: GridCellParams): ReactElement => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getJointKeys } from '../../mocks/electionSetup';
|
||||
import ElectionSetupWizard, { ElectionSetupWizardProps } from './ElectionSetupWizard';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<ElectionSetupWizardProps> = (props) => <ElectionSetupWizard {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
keys: getJointKeys(),
|
||||
keys: service.getJointKeys(),
|
||||
};
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { JointKey, getApiClient } from '@electionguard-ui/api';
|
||||
import { Box } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { getManifestPreview } from '../../mocks/electionSetup';
|
||||
import JointKey from '../../models/jointKey';
|
||||
import { createEnumStepper } from '../../utils/EnumStepper';
|
||||
import WizardStep from '../WizardStep';
|
||||
import {
|
||||
|
@ -37,6 +36,7 @@ const ElectionSetupWizard: React.FC<ElectionSetupWizardProps> = ({ keys }) => {
|
|||
const [step, setStep] = useState(ElectionSetupStep.Instructions);
|
||||
const { nextStep } = createEnumStepper(ElectionSetupStep);
|
||||
const next = () => setStep(nextStep(step));
|
||||
const service = getApiClient();
|
||||
return (
|
||||
<Box height="100%">
|
||||
<WizardStep active={step === ElectionSetupStep.Instructions}>
|
||||
|
@ -63,7 +63,7 @@ const ElectionSetupWizard: React.FC<ElectionSetupWizardProps> = ({ keys }) => {
|
|||
<ManifestPreviewStep
|
||||
onNext={next}
|
||||
backToMenu={() => setStep(ElectionSetupStep.ManifestMenu)}
|
||||
preview={getManifestPreview()}
|
||||
preview={service.getManifestPreview()}
|
||||
/>
|
||||
</WizardStep>
|
||||
<WizardStep active={step === ElectionSetupStep.SetupComplete}>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getJointKeys } from '../../../mocks/electionSetup';
|
||||
import JointKeySelectStep, { JointKeySelectStepProps } from './JointKeySelectStep';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<JointKeySelectStepProps> = (props) => <JointKeySelectStep {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
keys: getJointKeys(),
|
||||
keys: service.getJointKeys(),
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { JointKey } from '@electionguard-ui/api';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
|
@ -14,7 +15,6 @@ import React, { useState } from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Message, MessageId, loremIpsum } from '../../../lang';
|
||||
import JointKey from '../../../models/jointKey';
|
||||
import IconHeader from '../../IconHeader';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getManifestPreview } from '../../../mocks/electionSetup';
|
||||
import ManifestPreviewStep, { ManifestPreviewStepProps } from './ManifestPreviewStep';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<ManifestPreviewStepProps> = (props) => <ManifestPreviewStep {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
preview: getManifestPreview(),
|
||||
preview: service.getManifestPreview(),
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ManifestPreview } from '@electionguard-ui/api';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
|
@ -13,7 +14,6 @@ import React from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import ManifestPreview from '../../../models/manifestPreview';
|
||||
import IconHeader from '../../IconHeader';
|
||||
|
||||
export interface ManifestPreviewStepProps {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import getElections from '../../mocks/elections';
|
||||
import ElectionTable, { ElectionTableProps } from './ElectionTable';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<ElectionTableProps> = (props) => <ElectionTable {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
data: getElections(),
|
||||
data: service.getElections(),
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getAssignedGuardians } from '../../mocks/guardians';
|
||||
import GuardianTable, { GuardianTableProps } from './GuardianTable';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<GuardianTableProps> = (props) => <GuardianTable {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
data: getAssignedGuardians(),
|
||||
data: service.getAssignedGuardians(),
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { AssignedGuardian } from '@electionguard-ui/api';
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef } from '@material-ui/data-grid';
|
||||
import * as React from 'react';
|
||||
|
||||
import AssignedGuardian from '../../models/assignedGuardian';
|
||||
import { GuardianIconCell } from '../Cells';
|
||||
import FilterToolbar from '../FilterToolbar';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getJointKeys } from '../../mocks/electionSetup';
|
||||
import JointKeyTable, { JointKeyTableProps } from './JointKeyTable';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<JointKeyTableProps> = (props) => <JointKeyTable {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
data: getJointKeys(),
|
||||
data: service.getJointKeys(),
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { JointKey } from '@electionguard-ui/api';
|
||||
import { Box, Button, makeStyles } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef } from '@material-ui/data-grid';
|
||||
import * as React from 'react';
|
||||
import { IntlShape, useIntl } from 'react-intl';
|
||||
|
||||
import JointKey from '../../models/jointKey';
|
||||
import { FormattedDateCell } from '../Cells';
|
||||
import FilterToolbar from '../FilterToolbar';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getUsersWithGuardianRole } from '../../mocks/users';
|
||||
import { useCreateJointKey, useGetUsersWithGuardianRole } from '../../data/queries';
|
||||
import JointKeyWizard, { JointKeyWizardProps } from './JointKeyWizard';
|
||||
|
||||
export default {
|
||||
|
@ -15,6 +15,6 @@ const Template: Story<JointKeyWizardProps> = (props) => <JointKeyWizard {...prop
|
|||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
getGuardians: getUsersWithGuardianRole,
|
||||
createJointKey: () => {},
|
||||
getGuardians: useGetUsersWithGuardianRole,
|
||||
createJointKey: useCreateJointKey,
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { BaseJointKey, User } from '@electionguard-ui/api';
|
||||
import { Box } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { BaseJointKey } from '../../models/jointKey';
|
||||
import User from '../../models/user';
|
||||
import { AsyncResult } from '../../data/AsyncResult';
|
||||
import { createEnumStepper } from '../../utils/EnumStepper';
|
||||
import WizardStep from '../WizardStep';
|
||||
import {
|
||||
|
@ -20,7 +20,7 @@ export enum JointKeyStep {
|
|||
}
|
||||
|
||||
export interface JointKeyWizardProps {
|
||||
getGuardians: () => User[];
|
||||
getGuardians: () => AsyncResult<User[]>;
|
||||
createJointKey: (baseJointKey: BaseJointKey) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ const JointKeyWizard: React.FC<JointKeyWizardProps> = ({
|
|||
<WizardStep active={step === JointKeyStep.GuardianAssignment}>
|
||||
<GuardianAssignmentStep
|
||||
baseJointKey={baseJointKey}
|
||||
possibleGuardians={getGuardians()}
|
||||
getGuardians={getGuardians}
|
||||
onSubmit={(key) => {
|
||||
setBaseJointKey(key);
|
||||
next();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getAssignedGuardians } from '../../../mocks/guardians';
|
||||
import GuardianAssignmentReviewStep, {
|
||||
GuardianAssignmentReviewStepProps,
|
||||
} from './GuardianAssignmentReviewStep';
|
||||
|
@ -16,6 +16,7 @@ const Template: Story<GuardianAssignmentReviewStepProps> = (props) => (
|
|||
<GuardianAssignmentReviewStep {...props} />
|
||||
);
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
|
@ -23,6 +24,6 @@ Standard.args = {
|
|||
name: 'Montgomery School Board Key',
|
||||
numberOfGuardians: 3,
|
||||
quorum: 2,
|
||||
guardians: getAssignedGuardians(),
|
||||
guardians: service.getAssignedGuardians(),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { BaseJointKey } from '@electionguard-ui/api';
|
||||
import { Box, Button, Container, Typography, makeStyles } from '@material-ui/core';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import { BaseJointKey } from '../../../models/jointKey';
|
||||
import GuardianTable from '../../GuardianTable';
|
||||
import IconHeader from '../../IconHeader';
|
||||
import InternationalText from '../../InternationalText';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getUsersWithGuardianRole } from '../../../mocks/users';
|
||||
import { useGetUsersWithGuardianRole } from '../../../data/queries';
|
||||
import GuardianAssignmentStep, { GuardianAssignmentStepProps } from './GuardianAssignmentStep';
|
||||
|
||||
export default {
|
||||
|
@ -15,6 +15,7 @@ const Template: Story<GuardianAssignmentStepProps> = (props) => (
|
|||
);
|
||||
|
||||
export const Standard = Template.bind({});
|
||||
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
baseJointKey: {
|
||||
|
@ -23,5 +24,5 @@ Standard.args = {
|
|||
quorum: 2,
|
||||
guardians: [],
|
||||
},
|
||||
possibleGuardians: getUsersWithGuardianRole(),
|
||||
getGuardians: useGetUsersWithGuardianRole,
|
||||
};
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { AssignedGuardian, BaseJointKey, User } from '@electionguard-ui/api';
|
||||
import { Box, Button, Container, Typography, makeStyles } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
|
||||
import { AsyncResult } from '../../../data/AsyncResult';
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import { getUsersWithGuardianRole } from '../../../mocks/users';
|
||||
import AssignedGuardian from '../../../models/assignedGuardian';
|
||||
import { BaseJointKey } from '../../../models/jointKey';
|
||||
import User from '../../../models/user';
|
||||
import { getColor } from '../../../theme';
|
||||
import AssignmentTable from '../../AssignmentTable';
|
||||
import AsyncContent from '../../AsyncContent';
|
||||
import IconHeader from '../../IconHeader';
|
||||
import InternationalText from '../../InternationalText';
|
||||
|
||||
|
@ -54,7 +54,7 @@ export interface GuardianAssignmentStepProps {
|
|||
baseJointKey: BaseJointKey;
|
||||
onSubmit: (baseJointKey: BaseJointKey) => void;
|
||||
onCancel: () => void;
|
||||
possibleGuardians: User[];
|
||||
getGuardians: () => AsyncResult<User[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,13 +64,15 @@ const GuardianAssignmentStep: React.FC<GuardianAssignmentStepProps> = ({
|
|||
baseJointKey,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
possibleGuardians,
|
||||
getGuardians,
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const [assignedGuardians, setAssignedGuardians] = useState<AssignedGuardian[]>([]);
|
||||
// const [foundGuardians, setFoundGuardians] = useState<User[]>([]);
|
||||
let foundGuardians: User[] = [];
|
||||
const validate = (): boolean => assignedGuardians.length === baseJointKey.numberOfGuardians;
|
||||
const onAssign = (ids: string[]) => {
|
||||
const selected = possibleGuardians.filter((user) => ids.includes(user.id));
|
||||
const selected = foundGuardians.filter((user) => ids.includes(user.id));
|
||||
const assigned: AssignedGuardian[] = selected.map((user, i) => ({
|
||||
...user,
|
||||
sequenceOrder: i + 1,
|
||||
|
@ -87,90 +89,108 @@ const GuardianAssignmentStep: React.FC<GuardianAssignmentStepProps> = ({
|
|||
});
|
||||
};
|
||||
|
||||
const guardianQuery = getGuardians();
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
return (
|
||||
<Container maxWidth="md">
|
||||
<IconHeader title={new Message(MessageId.JointKeySetup_GuardianAssignment_Title)} />
|
||||
<form className={classes.form} onSubmit={handleSubmit}>
|
||||
<InternationalText
|
||||
className={classes.description}
|
||||
id={MessageId.JointKeySetup_GuardianAssignment_Description}
|
||||
/>
|
||||
<Box
|
||||
className={classes.jointKeyDisplay}
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
width="100%"
|
||||
>
|
||||
<Typography
|
||||
className={classes.heading}
|
||||
color="secondary"
|
||||
variant="h5"
|
||||
component="h2"
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<IconHeader title={new Message(MessageId.JointKeySetup_GuardianAssignment_Title)} />
|
||||
<form className={classes.form} onSubmit={handleSubmit}>
|
||||
<InternationalText
|
||||
className={classes.description}
|
||||
id={MessageId.JointKeySetup_GuardianAssignment_Description}
|
||||
/>
|
||||
<Box
|
||||
className={classes.jointKeyDisplay}
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
width="100%"
|
||||
>
|
||||
{baseJointKey.name}
|
||||
</Typography>
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box className={classes.numberContainer} display="flex">
|
||||
<InternationalText
|
||||
variant="h6"
|
||||
noWrap
|
||||
id={MessageId.JointKey_NumberOfGuardians}
|
||||
/>
|
||||
<Typography variant="h6">:</Typography>
|
||||
<Typography
|
||||
className={classes.numberDisplay}
|
||||
color="primary"
|
||||
variant="h6"
|
||||
>
|
||||
{baseJointKey.numberOfGuardians}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className={classes.numberContainer} display="flex">
|
||||
<InternationalText noWrap variant="h6" id={MessageId.JointKey_Quorum} />
|
||||
<Typography variant="h6">:</Typography>
|
||||
<Typography
|
||||
className={classes.numberDisplay}
|
||||
color="primary"
|
||||
variant="h6"
|
||||
>
|
||||
{baseJointKey.quorum}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className={classes.numberContainer} display="flex">
|
||||
<InternationalText
|
||||
noWrap
|
||||
variant="h6"
|
||||
id={MessageId.JointKeySetup_GuardianAssignment_AssignedLabel}
|
||||
/>
|
||||
<Typography variant="h6">:</Typography>
|
||||
<Typography
|
||||
className={classes.numberDisplay}
|
||||
color={validate() ? 'primary' : 'error'}
|
||||
variant="h6"
|
||||
>
|
||||
{assignedGuardians.length}
|
||||
</Typography>
|
||||
<Typography
|
||||
className={classes.heading}
|
||||
color="secondary"
|
||||
variant="h5"
|
||||
component="h2"
|
||||
>
|
||||
{baseJointKey.name}
|
||||
</Typography>
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box className={classes.numberContainer} display="flex">
|
||||
<InternationalText
|
||||
variant="h6"
|
||||
noWrap
|
||||
id={MessageId.JointKey_NumberOfGuardians}
|
||||
/>
|
||||
<Typography variant="h6">:</Typography>
|
||||
<Typography
|
||||
className={classes.numberDisplay}
|
||||
color="primary"
|
||||
variant="h6"
|
||||
>
|
||||
{baseJointKey.numberOfGuardians}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className={classes.numberContainer} display="flex">
|
||||
<InternationalText
|
||||
noWrap
|
||||
variant="h6"
|
||||
id={MessageId.JointKey_Quorum}
|
||||
/>
|
||||
<Typography variant="h6">:</Typography>
|
||||
<Typography
|
||||
className={classes.numberDisplay}
|
||||
color="primary"
|
||||
variant="h6"
|
||||
>
|
||||
{baseJointKey.quorum}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className={classes.numberContainer} display="flex">
|
||||
<InternationalText
|
||||
noWrap
|
||||
variant="h6"
|
||||
id={MessageId.JointKeySetup_GuardianAssignment_AssignedLabel}
|
||||
/>
|
||||
<Typography variant="h6">:</Typography>
|
||||
<Typography
|
||||
className={classes.numberDisplay}
|
||||
color={validate() ? 'primary' : 'error'}
|
||||
variant="h6"
|
||||
>
|
||||
{assignedGuardians.length}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className={classes.tableContainer} width="100%">
|
||||
<AssignmentTable data={getUsersWithGuardianRole()} onChanged={onAssign} />
|
||||
</Box>
|
||||
<Box className={classes.buttonContainer}>
|
||||
<Button
|
||||
disabled={!validate()}
|
||||
className={classes.button}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
>
|
||||
<FormattedMessage id={MessageId.Actions_Submit} />
|
||||
</Button>
|
||||
<Button className={classes.button} color="primary" onClick={onCancel}>
|
||||
<FormattedMessage id={MessageId.Actions_Cancel} />
|
||||
</Button>
|
||||
</Box>
|
||||
</form>
|
||||
<Box className={classes.tableContainer} width="100%">
|
||||
<AsyncContent query={guardianQuery} errorMessage="there was an error">
|
||||
{(usersFound) => {
|
||||
foundGuardians = usersFound;
|
||||
return (
|
||||
<>
|
||||
<AssignmentTable data={usersFound} onChanged={onAssign} />
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</AsyncContent>
|
||||
</Box>
|
||||
<Box className={classes.buttonContainer}>
|
||||
<Button
|
||||
disabled={!validate()}
|
||||
className={classes.button}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
>
|
||||
<FormattedMessage id={MessageId.Actions_Submit} />
|
||||
</Button>
|
||||
<Button className={classes.button} color="primary" onClick={onCancel}>
|
||||
<FormattedMessage id={MessageId.Actions_Cancel} />
|
||||
</Button>
|
||||
</Box>
|
||||
</form>
|
||||
</QueryClientProvider>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { BaseJointKey } from '@electionguard-ui/api';
|
||||
import { Box, Button, Container, Typography, makeStyles } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import { BaseJointKey } from '../../../models/jointKey';
|
||||
import IconHeader from '../../IconHeader';
|
||||
import InternationalText from '../../InternationalText';
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { BaseJointKey } from '@electionguard-ui/api';
|
||||
import { Box, Button, Container, TextField, makeStyles } from '@material-ui/core';
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import { BaseJointKey } from '../../../models/jointKey';
|
||||
import IconHeader from '../../IconHeader';
|
||||
import InternationalText from '../../InternationalText';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getKeyCeremonies } from '../../mocks/keyCeremony';
|
||||
import KeyCeremonyTable, { KeyCeremonyTableProps } from './KeyCeremonyTable';
|
||||
|
||||
export default {
|
||||
|
@ -12,8 +12,9 @@ export default {
|
|||
|
||||
const Template: Story<KeyCeremonyTableProps> = (props) => <KeyCeremonyTable {...props} />;
|
||||
|
||||
const service = getApiClient();
|
||||
export const Standard = Template.bind({});
|
||||
Standard.storyName = 'Standard';
|
||||
Standard.args = {
|
||||
data: getKeyCeremonies(),
|
||||
data: service.getKeyCeremonies(),
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { KeyCeremony } from '@electionguard-ui/api';
|
||||
import { Box, Button, makeStyles } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef } from '@material-ui/data-grid';
|
||||
import * as React from 'react';
|
||||
import { IntlShape, useIntl } from 'react-intl';
|
||||
|
||||
import { KeyCeremony } from '../../models/keyCeremony';
|
||||
import { FormattedDateCell } from '../Cells';
|
||||
import FilterToolbar from '../FilterToolbar';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BackupVerification } from '@electionguard-ui/api';
|
||||
import { Box } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
|
||||
import { BackupVerification } from '../../models/keyCeremony';
|
||||
import KeyCeremonyStep from './KeyCeremonyStep';
|
||||
import {
|
||||
CeremonyCompleteStep,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { KeyCeremonyGuardian } from '@electionguard-ui/api';
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef } from '@material-ui/data-grid';
|
||||
import * as React from 'react';
|
||||
|
||||
import { KeyCeremonyGuardian } from '../../models/keyCeremony';
|
||||
import { GuardianIconCell, TaskStatusCell } from '../Cells';
|
||||
import FilterToolbar from '../FilterToolbar';
|
||||
import InternationalText from '../InternationalText';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getApiClient } from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { getKeyCeremonyGuardiansByStep } from '../../mocks/keyCeremony';
|
||||
import KeyCeremonyStep from './KeyCeremonyStep';
|
||||
import KeyCeremonyVisualization, {
|
||||
KeyCeremonyVisualizationProps,
|
||||
|
@ -15,15 +15,17 @@ export default {
|
|||
|
||||
const Template: Story<KeyCeremonyVisualizationProps> = (props) => {
|
||||
const { activeStep } = props;
|
||||
const service = getApiClient();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<KeyCeremonyVisualization
|
||||
{...props}
|
||||
guardians={getKeyCeremonyGuardiansByStep(activeStep)}
|
||||
guardians={service.getKeyCeremonyGuardiansByStep(activeStep)}
|
||||
/>
|
||||
<KeyCeremonyVisualization
|
||||
{...props}
|
||||
guardians={getKeyCeremonyGuardiansByStep(activeStep + 1)}
|
||||
guardians={service.getKeyCeremonyGuardiansByStep(activeStep + 1)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { KeyCeremonyGuardian, TaskStatus } from '@electionguard-ui/api';
|
||||
import { Box, Container, makeStyles, useTheme } from '@material-ui/core';
|
||||
import { CheckCircle as CompleteIcon } from '@material-ui/icons';
|
||||
import React from 'react';
|
||||
|
||||
import { MessageId } from '../../lang';
|
||||
import { KeyCeremonyGuardian } from '../../models/keyCeremony';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import InternationalText from '../InternationalText';
|
||||
import SequenceOrderProgress from '../SequenceOrderProgress';
|
||||
import KeyCeremonyStep from './KeyCeremonyStep';
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import {
|
||||
BackupVerification,
|
||||
KeyCeremonyGuardian,
|
||||
TaskStatus,
|
||||
getApiClient,
|
||||
} from '@electionguard-ui/api';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { getKeyCeremonies, setKeyCeremonyGuardianToStep } from '../../mocks/keyCeremony';
|
||||
import { BackupVerification, KeyCeremonyGuardian } from '../../models/keyCeremony';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import delay from '../../utils/delay';
|
||||
import KeyCeremonyStep from './KeyCeremonyStep';
|
||||
import KeyCeremonyWizard, { KeyCeremonyWizardProps } from './KeyCeremonyWizard';
|
||||
|
@ -14,8 +17,9 @@ export default {
|
|||
parameters: { layout: 'fullscreen' },
|
||||
} as Meta;
|
||||
|
||||
const service = getApiClient();
|
||||
const Template: Story<KeyCeremonyWizardProps> = (props) => {
|
||||
const [keyCeremony, setKeyCeremony] = useState(getKeyCeremonies()[0]);
|
||||
const [keyCeremony, setKeyCeremony] = useState(service.getKeyCeremonies()[0]);
|
||||
const loggedInGuardian = keyCeremony.guardians.find(
|
||||
(i) => i.sequenceOrder === 1
|
||||
) as KeyCeremonyGuardian;
|
||||
|
@ -24,7 +28,7 @@ const Template: Story<KeyCeremonyWizardProps> = (props) => {
|
|||
const guardian = keyCeremony.guardians.find(
|
||||
(i) => i.sequenceOrder === 1
|
||||
) as KeyCeremonyGuardian;
|
||||
const updated = setKeyCeremonyGuardianToStep(guardian, step);
|
||||
const updated = service.setKeyCeremonyGuardianToStep(guardian, step);
|
||||
setKeyCeremony({
|
||||
...keyCeremony,
|
||||
guardians: [updated, ...keyCeremony.guardians.filter((i) => i.sequenceOrder !== 1)],
|
||||
|
@ -32,7 +36,9 @@ const Template: Story<KeyCeremonyWizardProps> = (props) => {
|
|||
};
|
||||
|
||||
const updateGuardians = (step: KeyCeremonyStep) => {
|
||||
const updated = keyCeremony.guardians.map((g) => setKeyCeremonyGuardianToStep(g, step));
|
||||
const updated = keyCeremony.guardians.map((g) =>
|
||||
service.setKeyCeremonyGuardianToStep(g, step)
|
||||
);
|
||||
setKeyCeremony({
|
||||
...keyCeremony,
|
||||
guardians: updated,
|
||||
|
@ -98,7 +104,7 @@ const Template: Story<KeyCeremonyWizardProps> = (props) => {
|
|||
};
|
||||
|
||||
const completeCeremony = async () => {
|
||||
setKeyCeremony(getKeyCeremonies()[0]);
|
||||
setKeyCeremony(service.getKeyCeremonies()[0]);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import {
|
||||
AssignedGuardian,
|
||||
KeyCeremony,
|
||||
KeyCeremonyStatus,
|
||||
TaskStatus,
|
||||
} from '@electionguard-ui/api';
|
||||
import { Box, Container } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import AssignedGuardian from '../../models/assignedGuardian';
|
||||
import { KeyCeremony, KeyCeremonyStatus } from '../../models/keyCeremony';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import { createEnumStepper } from '../../utils/EnumStepper';
|
||||
import WizardStep from '../WizardStep';
|
||||
import KeyCeremonyActiveStep from './KeyCeremonyActiveStep';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { AssignedGuardian } from '@electionguard-ui/api';
|
||||
import { Container, makeStyles } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import AssignedGuardian from '../../../models/assignedGuardian';
|
||||
import GuardianTable from '../../GuardianTable';
|
||||
import InternationalText from '../../InternationalText';
|
||||
import StepHeader from '../../StepHeader';
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { BackupVerification, TaskStatus } from '@electionguard-ui/api';
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { DataGrid, GridColDef, GridRowId, GridSortDirection } from '@material-ui/data-grid';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Message, MessageId } from '../../../lang';
|
||||
import { BackupVerification } from '../../../models/keyCeremony';
|
||||
import TaskStatus from '../../../models/taskStatus';
|
||||
import { GuardianIconCell, TaskStatusCell } from '../../Cells';
|
||||
import FilterToolbar from '../../FilterToolbar';
|
||||
import StepHeader from '../../StepHeader';
|
||||
|
|
|
@ -59,6 +59,11 @@ export const getPreset = (type: MenuOptionType): MenuOptionPreset => {
|
|||
title: new Message(MessageId.MenuOption_ManageElections),
|
||||
Icon: BallotOutlined,
|
||||
};
|
||||
case MenuOptionType.SetupJointKeys:
|
||||
return {
|
||||
title: new Message(MessageId.MenuOption_SetupJointKey),
|
||||
Icon: VpnKeyOutlined,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
title: new Message(OverloadMessageId, 'Unknown'),
|
||||
|
|
|
@ -7,6 +7,7 @@ export enum MenuOptionType {
|
|||
BuildManifest = 'build-manifest',
|
||||
ManageJointKeys = 'manage-joint-key',
|
||||
ManageElections = 'manage-elections',
|
||||
SetupJointKeys = 'setup-joint-key',
|
||||
}
|
||||
|
||||
export default MenuOptionType;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { TaskStatus } from '@electionguard-ui/api';
|
||||
import { BallotOutlined } from '@material-ui/icons';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Message, loremIpsum } from '../../lang';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import delay from '../../utils/delay';
|
||||
import Processor, { ProcessorProps } from './Processor';
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { TaskStatus } from '@electionguard-ui/api';
|
||||
import { Box, CircularProgress, Container, SvgIconProps, makeStyles } from '@material-ui/core';
|
||||
import {
|
||||
CheckCircle as DefaultCompleteIcon,
|
||||
|
@ -8,7 +9,6 @@ import clsx from 'clsx';
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import { Message, MessageId } from '../../lang';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import FormattedButton from '../FormattedButton';
|
||||
import InternationalText from '../InternationalText';
|
||||
import StepHeader from '../StepHeader';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { TaskStatus } from '@electionguard-ui/api';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import TaskStatusIcon, { TaskStatusIconProps } from './TaskStatusIcon';
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { TaskStatus } from '@electionguard-ui/api';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import {
|
||||
CheckCircleOutlined as CompleteIcon,
|
||||
|
@ -6,7 +7,6 @@ import {
|
|||
import React from 'react';
|
||||
|
||||
import { Message, MessageId } from '../../lang';
|
||||
import TaskStatus from '../../models/taskStatus';
|
||||
import FormattedButton from '../FormattedButton';
|
||||
import InternationalText from '../InternationalText';
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export interface AsyncResult<T> {
|
||||
data: T | undefined;
|
||||
isError: boolean;
|
||||
isLoading: boolean;
|
||||
isIdle: boolean;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { BaseJointKey, User, getApiClient } from '@electionguard-ui/api';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
import { AsyncResult } from './AsyncResult';
|
||||
import { QUERY_NAMES } from './query_names';
|
||||
|
||||
export function useGetUsersWithGuardianRole(): AsyncResult<User[]> {
|
||||
const service = getApiClient();
|
||||
return useQuery(QUERY_NAMES.GUARDIANS, () => service.getUsersWithGuardianRole());
|
||||
}
|
||||
|
||||
export function useCreateJointKey(data: BaseJointKey): Promise<boolean> {
|
||||
const service = getApiClient();
|
||||
return service.createJointKey(data);
|
||||
}
|
||||
|
||||
export default useGetUsersWithGuardianRole;
|
|
@ -0,0 +1,7 @@
|
|||
export const QUERY_NAMES = {
|
||||
GUARDIANS: 'GUARDIANS',
|
||||
ELECTIONS: 'ELECTIONS',
|
||||
CREATE_KEY: 'CREATE_KEY',
|
||||
};
|
||||
|
||||
export default QUERY_NAMES;
|
|
@ -2,6 +2,7 @@ import { CssBaseline, MuiThemeProvider } from '@material-ui/core';
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
|
||||
import App from './App';
|
||||
import { ConfigContext, defaultConfig } from './contexts/config';
|
||||
|
@ -10,21 +11,25 @@ import Language from './models/language';
|
|||
import reportWebVitals from './reportWebVitals';
|
||||
import theme from './theme';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<ConfigContext.Provider value={defaultConfig}>
|
||||
<LanguageContext.Provider value={defaultLanguage}>
|
||||
<LanguageContext.Consumer>
|
||||
{(language: Language) => (
|
||||
<IntlProvider locale={language.locale} messages={language.messages}>
|
||||
<MuiThemeProvider theme={theme(language.mui)}>
|
||||
<CssBaseline />
|
||||
<App />
|
||||
</MuiThemeProvider>
|
||||
</IntlProvider>
|
||||
)}
|
||||
</LanguageContext.Consumer>
|
||||
</LanguageContext.Provider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<LanguageContext.Provider value={defaultLanguage}>
|
||||
<LanguageContext.Consumer>
|
||||
{(language: Language) => (
|
||||
<IntlProvider locale={language.locale} messages={language.messages}>
|
||||
<MuiThemeProvider theme={theme(language.mui)}>
|
||||
<CssBaseline />
|
||||
<App />
|
||||
</MuiThemeProvider>
|
||||
</IntlProvider>
|
||||
)}
|
||||
</LanguageContext.Consumer>
|
||||
</LanguageContext.Provider>
|
||||
</QueryClientProvider>
|
||||
</ConfigContext.Provider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
|
|
|
@ -20,6 +20,7 @@ enum MessageId {
|
|||
MenuOption_BuildManifest = 'menu.option.build_manifest',
|
||||
MenuOption_ManageJointKeys = 'menu.option.manage_joint_keys',
|
||||
MenuOption_ManageElections = 'menu.option.manage_elections',
|
||||
MenuOption_SetupJointKey = 'menu.option.setup_joint_keys',
|
||||
|
||||
// Login Form
|
||||
LoginFormUsername = 'login_form.username',
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"menu.option.build_manifest": "Build Manifest",
|
||||
"menu.option.manage_joint_keys": "Manage Joint Keys",
|
||||
"menu.option.manage_elections": "Manage Elections",
|
||||
"menu.option.setup_joint_keys": "Setup Joint Keys",
|
||||
|
||||
"login_form.username": "Username",
|
||||
"login_form.password": "Password",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"menu.option.build_manifest": "Build Manifest",
|
||||
"menu.option.manage_joint_keys": "Manage Joint Keys",
|
||||
"menu.option.manage_elections": "Manage Elections",
|
||||
"menu.option.setup_joint_keys": "Setup Joint Keys",
|
||||
|
||||
"login_form.username": "Username",
|
||||
"login_form.password": "Password",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"menu.option.build_manifest": "Build Manifest",
|
||||
"menu.option.manage_joint_keys": "Manage Joint Keys",
|
||||
"menu.option.manage_elections": "Manage Elections",
|
||||
"menu.option.setup_joint_keys": "Setup Joint Keys",
|
||||
|
||||
"login_form.username": "Username",
|
||||
"login_form.password": "Password",
|
||||
|
@ -141,7 +142,6 @@
|
|||
"key_ceremony.complete.description": "You have successfully completed the key ceremony. Thanks for participating!",
|
||||
"key_ceremony.complete.button": "Return to Home",
|
||||
|
||||
|
||||
"key_ceremony.steps.instructions": "Steps",
|
||||
"key_ceremony.visualization_complete": "Joint Key Created",
|
||||
"key_ceremony.steps.meet_guardians": "Meet the Guardians",
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче