Skip to content

Commit

Permalink
Client-2.4.23 Server-2.4.5
Browse files Browse the repository at this point in the history
  • Loading branch information
yaxin001 committed Nov 18, 2023
1 parent 0a11e20 commit e2b86ca
Show file tree
Hide file tree
Showing 649 changed files with 62,964 additions and 11,988 deletions.
1 change: 1 addition & 0 deletions client/.svn/entries
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
12
1 change: 1 addition & 0 deletions client/.svn/format
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
12
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { all, call, select, takeLatest } from 'redux-saga/effects';

import * as config from 'corla/config';

import createPollSaga from 'corla/saga/createPollSaga';

import dashboardRefresh from 'corla/action/county/dashboardRefresh';
import fetchAuditBoardASMState from 'corla/action/county/fetchAuditBoardASMState';
import fetchCountyASMState from 'corla/action/county/fetchCountyASMState';

import cvrExportUploadingSelector from 'corla/selector/county/cvrExportUploading';

const COUNTY_POLL_DELAY = config.pollDelay;

function* selectPollDelay() {
const countyState = yield select();

const isUploading = cvrExportUploadingSelector(countyState);

return isUploading ? 5000 : COUNTY_POLL_DELAY;
}

function* refreshCountyState() {
yield all([
call(dashboardRefresh),
call(fetchAuditBoardASMState),
call(fetchCountyASMState),
]);
}

function* auditPoll() {
const countyState = yield select();

const asmState = countyState.asm.auditBoard;
const shouldSync = asmState === 'WAITING_FOR_ROUND_START'
|| asmState === 'WAITING_FOR_ROUND_START_NO_AUDIT_BOARD';

if (shouldSync) {
yield call(refreshCountyState);
}
}

function* dashboardPoll() {
yield call(refreshCountyState);
}

const auditPollSaga = createPollSaga(
[auditPoll],
'COUNTY_AUDIT_POLL_START',
'COUNTY_AUDIT_POLL_STOP',
() => COUNTY_POLL_DELAY,
);

function* boardSignInSaga() {
yield takeLatest('COUNTY_BOARD_SIGN_IN_SYNC', refreshCountyState);
}

const dashboardPollSaga = createPollSaga(
[dashboardPoll],
'COUNTY_DASHBOARD_POLL_START',
'COUNTY_DASHBOARD_POLL_STOP',
selectPollDelay,
);

export default function* pollSaga() {
yield all([
call(auditPollSaga),
call(boardSignInSaga),
call(dashboardPollSaga),
]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const webpack = require('webpack');
const path = require('path');

module.exports = {
entry: [
// Activate HMR for React.
'react-hot-loader/patch',

// Bundle client for dev server, connect to provided endpoint.
'webpack-dev-server/client?http://localhost:3000',

// Bundle client for hot reloading. Only hot reload on
// successful updates.
'webpack/hot/only-dev-server',

// Actual app entry point.
'./src/index.tsx',

],

output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist'),
// Tell HMR where to load hot update chunks.
publicPath: '/static/',
},

resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: ['.ts', '.tsx', '.js', '.json'],

alias: {
// Add an import alias for the project root.
corla: path.join(__dirname, 'src'),
},
},

plugins: [
new webpack.DefinePlugin({
"process.env": {'DEBUG' : true},
global: {}
}),

// Enable HMR, needed by `react-hot-loader`.
new webpack.HotModuleReplacementPlugin(),

// Use readable module names in console.
//new webpack.NamedModulesPlugin(),

// Don't emit compiled assets that include errors.
new webpack.NoEmitOnErrorsPlugin(),
],

module: {
rules: [
{
test: /\.tsx?$/,
use: {loader: 'react-hot-loader/webpack'},
exclude: path.join(__dirname, 'node_modules'),
include: path.join(__dirname, 'src'),
},
{
test: /\.tsx?$/,
use: {loader: 'awesome-typescript-loader'},
exclude: path.join(__dirname, 'node_modules'),
include: path.join(__dirname, 'src'),
},

],
},

devServer: {
static: {
directory: path.join(__dirname, '/'),
},
host: 'localhost',
port: 3000,
open: true,
// Serve `index.html` on 404.
historyApiFallback: true,

// Support HMR on the dev server.
hot: true,
},

// Enable source maps.
devtool: 'inline-source-map',
mode: 'development',

};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { endpoint } from 'corla/config';
import { empty } from 'corla/util';

const appInfoUrl = endpoint('app-info');

async function getAppInfo() {
const init: RequestInit = {
credentials: 'include',
method: 'get',
};

try {
const r = await fetch(appInfoUrl, init);

const received = await r.json().catch(empty);

if (!r.ok) {
return {};
}

return received ;

} catch (e) {
return {exception: e};
}
}

export default getAppInfo;
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as React from 'react';

import { Button, Dialog, FormGroup, Intent, TextArea } from '@blueprintjs/core';

import action from 'corla/action/';

interface FinalReviewDialogProps {
cvr?: JSON.CVR;
onClose: () => void;
isOpen: boolean;
}

interface FinalReviewDialogState {
comment: string;
hasError: boolean;
}

class FinalReviewDialog extends React.Component<FinalReviewDialogProps, FinalReviewDialogState> {
constructor(props: FinalReviewDialogProps) {
super(props);

this.state = { comment: '', hasError: true };
}

public render() {
const cvr = this.props.cvr;

const title = cvr ? 'Re-audit ' + cvr.imprinted_id : 'Re-audit';

return (
<Dialog icon='confirm'
isOpen={ this.props.isOpen }
onClose={ this.handleCancel }
title={ title }>
<div className='pt-dialog-body'>
<p>
To re-audit this ballot, please explain your reason for
re-auditing this ballot in the space below and click
"Next". To go back, click "Back".
</p>
<FormGroup intent={ this.formIntent() }
label='Reason for re-audit '
labelFor='review-dialog-input'
requiredLabel={ true }>
<TextArea id='review-dialog-input'
className='pt-fill'
intent={ this.formIntent() }
value={ this.state.comment }
onChange={ this.handleCommentChange } />
</FormGroup>
</div>
<div className='pt-dialog-footer'>
<div className='pt-dialog-footer-actions'>
<Button text='Cancel'
onClick={ this.handleCancel } />
<Button intent={ Intent.PRIMARY }
onClick={ this.handleReAudit }
text='Next' />
</div>
</div>
</Dialog>
);
}

private formIntent = (): Intent => {
return this.state.hasError ? Intent.DANGER : Intent.NONE;
}

private handleCancel = () => {
this.props.onClose();
}

private handleCommentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
this.setState({
comment: e.target.value,
hasError: e.target.value.length < 1,
});
}

private handleReAudit = () => {
if (this.state.hasError) {
return;
}

const cvr = this.props.cvr;

if (cvr) {
action('RE_AUDIT_CVR', {
comment: this.state.comment,
cvrId: cvr.db_id,
});
}
}
}

export default FinalReviewDialog;
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from 'react';

import { NumericInput } from '@blueprintjs/core';

interface FormProps {
onChange: (r: number) => void;
riskLimit: number;
}

interface FormState {
riskLimitPercent: string;
}

const MIN_RISK_LIMIT = 0.0001;
const MAX_RISK_LIMIT = 1 - MIN_RISK_LIMIT;

function fromPercent(val: number) {
return val / 100;
}

function toPercent(val: number) {
return val * 100;
}

class RiskLimitForm extends React.Component<FormProps, FormState> {
constructor(props: FormProps) {
super(props);

this.state = {
riskLimitPercent: String(toPercent(props.riskLimit)),
};

this.onChange = this.onChange.bind(this);
}

public render() {
const { riskLimitPercent } = this.state;

return (
<div>
<label>
<div className='mb-default'>Comparison Audits (%)</div>
<NumericInput
min={ toPercent(MIN_RISK_LIMIT) }
max={ toPercent(MAX_RISK_LIMIT) }
stepSize={ 1 }
value={ riskLimitPercent }
onValueChange={ this.onChange } />
</label>
</div>
);
}

private onChange(valueAsNumber: number, valueAsString: string) {
this.setState({ riskLimitPercent: valueAsString });

this.props.onChange(fromPercent(valueAsNumber));
}
}

export default RiskLimitForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react';
import AuditReportForm from 'corla/component/AuditReportForm';

interface StatusProps {
auditIsComplete: boolean;
canRenderReport: boolean;
currentRound: number;
finishedCountiesCount: number;
totalCountiesCount: number;
}

const Status = (props: StatusProps) => {
const {
auditIsComplete,
canRenderReport,
currentRound,
finishedCountiesCount,
totalCountiesCount,
} = props;

return (
<div className='state-dashboard-round'>
<div>
{ !auditIsComplete && <h4>Round { currentRound } in progress</h4> }
{ auditIsComplete && <h4>Congratulations! The audit is complete.</h4> }
<span className='state-dashboard-round-summary'>
{ finishedCountiesCount } of { totalCountiesCount } counties
have finished this round.
</span>
</div>
<div>
{canRenderReport && (<AuditReportForm
canRenderReport={canRenderReport}
/>
)}
</div>
</div>
);
};

export default Status;
Loading

0 comments on commit e2b86ca

Please sign in to comment.