Skip to content

Commit ffe1188

Browse files
authored
Feature/conflict resolution page (#12)
Feature/conflict resolution page
2 parents d784b1e + efe5a9b commit ffe1188

File tree

29 files changed

+1962
-232
lines changed

29 files changed

+1962
-232
lines changed

.babelrc.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ module.exports = (api) => {
3939
['@babel/plugin-proposal-class-properties', { 'loose': false }],
4040
'@babel/plugin-proposal-json-strings',
4141

42+
'@babel/plugin-proposal-optional-chaining',
43+
4244
[
4345
'module-resolver',
4446
{

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"@babel/plugin-transform-runtime": "^7.5.5",
7070
"@babel/preset-env": "^7.4.5",
7171
"@babel/preset-react": "^7.0.0",
72-
"@babel/preset-typescript": "^7.3.3",
72+
"@babel/preset-typescript": "^7.7.4",
7373
"@babel/register": "^7.6.2",
7474
"@babel/runtime": "^7.5.5",
7575
"@babel/runtime-corejs3": "^7.5.5",
@@ -84,8 +84,8 @@
8484
"@types/react-loadable": "^5.5.1",
8585
"@types/react-redux": "^7.1.1",
8686
"@types/react-router-dom": "^4.3.4",
87-
"@typescript-eslint/eslint-plugin": "^1.13.0",
88-
"@typescript-eslint/parser": "^1.13.0",
87+
"@typescript-eslint/eslint-plugin": "^2.10.0",
88+
"@typescript-eslint/parser": "^2.10.0",
8989
"babel-core": "^7.0.0-bridge.0",
9090
"babel-eslint": "^10.0.2",
9191
"babel-jest": "^24.8.0",
@@ -135,7 +135,7 @@
135135
"stylelint-order": "^3.0.1",
136136
"stylelint-scss": "^3.9.3",
137137
"terser-webpack-plugin": "^1.4.1",
138-
"typescript": "^3.5.3",
138+
"typescript": "^3.7.3",
139139
"webpack": "^4.41.2",
140140
"webpack-bundle-analyzer": "^3.4.1",
141141
"webpack-cli": "^3.3.10",
@@ -144,6 +144,7 @@
144144
"workbox-webpack-plugin": "^4.3.1"
145145
},
146146
"dependencies": {
147+
"@babel/plugin-proposal-optional-chaining": "^7.7.5",
147148
"@reach/router": "^1.2.1",
148149
"@togglecorp/faram": "^1.2.1",
149150
"@togglecorp/fujs": "^1.8.0",

src/Root/App/Multiplexer/index.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import React from 'react';
33
import { Router } from '@reach/router';
44
import { _cs } from '@togglecorp/fujs';
55

6-
import DangerButton from '#rsca/Button/DangerButton';
6+
import Button from '#rsu/../v2/Action/Button';
7+
import LoadingAnimation from '#rscv/LoadingAnimation';
8+
import Message from '#rsu/../v2/View/Message';
79

810
import Navbar from '#components/Navbar';
911
import errorBound from '#components/errorBound';
1012
import helmetify from '#components/helmetify';
1113

12-
import LoadingAnimation from '#rscv/LoadingAnimation';
13-
import Message from '#rscv/Message';
1414

1515
import { routeSettings } from '#constants';
1616
import styles from './styles.scss';
@@ -38,13 +38,14 @@ const BaseErrorInPage = ({
3838
<div className={styles.message}>
3939
{ message }
4040
</div>
41-
<DangerButton
41+
<Button
4242
className={styles.reloadButton}
4343
transparent
4444
onClick={onReload}
45+
buttonType="button-danger"
4546
>
4647
Reload
47-
</DangerButton>
48+
</Button>
4849
</Message>
4950
);
5051

src/Root/App/Multiplexer/styles.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ body {
6464
flex-direction: column;
6565
background-color: var(--color-background);
6666
height: 100vh;
67+
overflow: auto;
6768

6869
.navbar {
6970
flex-shrink: 0;
@@ -80,6 +81,7 @@ body {
8081
position: relative;
8182
flex-direction: column;
8283
flex-grow: 1;
84+
overflow: auto;
8385

8486
.content {
8587
flex-grow: 1;

src/Root/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { Store } from 'redux';
33
import { Provider } from 'react-redux';
44
import { persistStore } from 'redux-persist';
5+
56
import { initializeStyles } from '#rsu/styles';
67

78
import store from '#store';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import { _cs } from '@togglecorp/fujs';
3+
4+
import styles from './styles.scss';
5+
6+
interface Props {
7+
className?: string;
8+
resolved: number;
9+
total: number;
10+
partiallyResolved: number;
11+
label: string;
12+
}
13+
14+
class ConflictStatus extends React.PureComponent<Props> {
15+
public static defaultProps = {
16+
resolved: 0,
17+
partiallyResolved: 0,
18+
total: 0,
19+
label: 'conflicts',
20+
};
21+
22+
public render() {
23+
const {
24+
className,
25+
resolved,
26+
label,
27+
total,
28+
} = this.props;
29+
30+
return (
31+
<div className={_cs(styles.conflictStatus, className)}>
32+
<div className={styles.resolvedConflicts}>
33+
{resolved}
34+
</div>
35+
<div className={styles.separator}>
36+
of
37+
</div>
38+
<div className={styles.totalConflicts}>
39+
{total}
40+
</div>
41+
<div className={styles.postLabel}>
42+
{`${label} resolved`}
43+
</div>
44+
</div>
45+
);
46+
}
47+
}
48+
49+
export default ConflictStatus;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.conflict-status {
2+
display: flex;
3+
4+
.resolved-conflicts {
5+
padding: 0 var(--spacing-extra-small);
6+
}
7+
8+
.separator {
9+
padding: 0 var(--spacing-extra-small);
10+
}
11+
12+
.total-conflicts {
13+
padding: 0 var(--spacing-extra-small);
14+
}
15+
16+
.post-label {
17+
padding: 0 var(--spacing-extra-small);
18+
}
19+
}

src/components/Navbar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { _cs } from '@togglecorp/fujs';
33

4-
import ListView from '#rscv/List/ListView';
4+
import ListView from '#rsu/../v2/View/ListView';
55
import POSMIcon from '#resources/posm.png';
66

77
import { routeSettings, hasNavbar, NavbarRoute } from '#constants';

src/components/ProgressBar/index.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ class ProgressBar extends React.PureComponent<Props> {
2727
style={{
2828
width: progressWidth,
2929
}}
30-
className={_cs(styles.progress, progressClassName)}
30+
className={
31+
_cs(
32+
styles.progress,
33+
progressClassName,
34+
progress === 100 && styles.completed,
35+
)
36+
}
3137
/>
3238
</div>
3339
);

src/components/ProgressBar/styles.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,9 @@
88
transition: var(--duration-transition-slow) width ease-in-out;
99
border-radius: var(--radius-border-progress-bar);
1010
background-color: var(--color-accent);
11+
12+
&.completed {
13+
background-color: var(--color-success);
14+
}
1115
}
1216
}

src/constants/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { default as iconNames } from './iconNames';
2+
export { default as pathNames } from './pathNames';
23
export { default as routeSettings } from './routeSettings';
34
export { default as styleProperties } from './styleProperties';
45

src/constants/pathNames.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { listToMap } from '@togglecorp/fujs';
2+
3+
import routeSettings, { isNotFallbackRoute } from './routeSettings';
4+
5+
// FIXME: pathNames is not exactly type-safe
6+
const mapping: {
7+
[key: string]: string;
8+
} = listToMap(
9+
routeSettings.filter(isNotFallbackRoute),
10+
item => item.name,
11+
item => item.path,
12+
);
13+
14+
export default mapping;

src/constants/routeSettings.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export function hasNavbar(route: SomeRoute): route is NavbarRoute {
2323

2424
export type SomeRoute = Route | NavbarRoute | FallbackRoute;
2525

26+
export function isNotFallbackRoute(route: SomeRoute): route is Route {
27+
return route.path !== undefined;
28+
}
29+
2630
const routeSettings: SomeRoute[] = [
2731
{
2832
path: '/',
@@ -32,7 +36,7 @@ const routeSettings: SomeRoute[] = [
3236
navbar: true,
3337
},
3438
{
35-
name: 'conflict-resolution',
39+
name: 'conflictResolution',
3640
title: 'Conflict Resolution',
3741
path: '/conflict-resolution/',
3842
load: () => import('../views/ConflictResolution'),

src/constants/styleProperties.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const styleProperties = {
1919

2020
heightProgressBar: '6px',
2121
radiusBorderProgressBar: '3px',
22+
23+
mapElementsZIndex: 11,
2224
};
2325

2426
export default styleProperties;

src/constants/types.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
export type ResolutionStatus = 'conflicted' | 'resolved' | 'partially-resolved';
2+
export type ElementType = 'point' | 'line' | 'area';
3+
export type Bounds = [number, number, number, number];
4+
5+
interface Meta {
6+
id: number;
7+
version: number;
8+
user?: string;
9+
uid?: number;
10+
timestamp?: string;
11+
visible?: boolean;
12+
changeset?: number;
13+
}
14+
15+
export interface Tags {
16+
[key: string]: string | undefined;
17+
}
18+
19+
export interface Content {
20+
meta: Meta;
21+
tags: Tags;
22+
bounds: Bounds;
23+
geoJSON?: GeoJSON.Feature<GeoJSON.Geometry> | GeoJSON.FeatureCollection<GeoJSON.Geometry>;
24+
}
25+
26+
export interface ConflictElement {
27+
id: string;
28+
title: string;
29+
resolutionStatus: ResolutionStatus;
30+
type: ElementType; // IDK about this
31+
32+
original: Content;
33+
theirs?: Content;
34+
ours?: Content;
35+
}
36+
37+
// For nodes:
38+
// Show the node; If part of way show them
39+
40+
// For way:
41+
// Show everything inside it
42+
43+
// For relation:
44+
// Show everything inside it
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React from 'react';
2+
import { _cs } from '@togglecorp/fujs';
3+
4+
import Icon from '#rscg/Icon';
5+
6+
import { ResolutionStatus, ElementType } from '#constants/types';
7+
8+
import styles from './styles.scss';
9+
10+
interface Props {
11+
className?: string;
12+
title: string;
13+
conflictId: string;
14+
onClick: (conflictId: string) => void;
15+
isActive: boolean;
16+
resolutionStatus: ResolutionStatus;
17+
type: ElementType;
18+
}
19+
20+
const iconNames: {
21+
[key in ResolutionStatus]: string;
22+
} = {
23+
conflicted: 'error',
24+
resolved: 'checkmarkCircle',
25+
'partially-resolved': 'checkmarkCircleEmpty',
26+
};
27+
const iconClassNames: {
28+
[key in ResolutionStatus]: string;
29+
} = {
30+
conflicted: styles.error,
31+
resolved: styles.success,
32+
'partially-resolved': styles.pending,
33+
};
34+
35+
class ConflictListItem extends React.PureComponent<Props> {
36+
private handleClick = () => {
37+
const {
38+
conflictId,
39+
onClick,
40+
} = this.props;
41+
42+
onClick(conflictId);
43+
}
44+
45+
public render() {
46+
const {
47+
className,
48+
title,
49+
isActive,
50+
resolutionStatus,
51+
type,
52+
} = this.props;
53+
54+
return (
55+
<button
56+
className={_cs(className, styles.conflictListItem, isActive && styles.active)}
57+
onClick={this.handleClick}
58+
type="button"
59+
>
60+
<Icon
61+
className={_cs(styles.icon, iconClassNames[resolutionStatus])}
62+
name={iconNames[resolutionStatus]}
63+
/>
64+
{`${title} (${type})`}
65+
</button>
66+
);
67+
}
68+
}
69+
70+
export default ConflictListItem;

0 commit comments

Comments
 (0)