Migration vers react/react-router
This commit is contained in:
parent
584f47bf84
commit
456d7d2999
599
client/package-lock.json
generated
599
client/package-lock.json
generated
@ -4,6 +4,61 @@
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz",
|
||||
"integrity": "sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@redux-saga/core": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
|
||||
"integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@redux-saga/deferred": "^1.1.2",
|
||||
"@redux-saga/delay-p": "^1.1.2",
|
||||
"@redux-saga/is": "^1.1.2",
|
||||
"@redux-saga/symbols": "^1.1.2",
|
||||
"@redux-saga/types": "^1.1.0",
|
||||
"redux": "^4.0.4",
|
||||
"typescript-tuple": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"@redux-saga/deferred": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz",
|
||||
"integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ=="
|
||||
},
|
||||
"@redux-saga/delay-p": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz",
|
||||
"integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
|
||||
"requires": {
|
||||
"@redux-saga/symbols": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"@redux-saga/is": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz",
|
||||
"integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
|
||||
"requires": {
|
||||
"@redux-saga/symbols": "^1.1.2",
|
||||
"@redux-saga/types": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@redux-saga/symbols": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz",
|
||||
"integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ=="
|
||||
},
|
||||
"@redux-saga/types": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz",
|
||||
"integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg=="
|
||||
},
|
||||
"@teamsupercell/typings-for-css-modules-loader": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@teamsupercell/typings-for-css-modules-loader/-/typings-for-css-modules-loader-2.1.1.tgz",
|
||||
@ -59,23 +114,21 @@
|
||||
"base-x": "^3.0.6"
|
||||
}
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
|
||||
"integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
|
||||
"integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/events": "*",
|
||||
"@types/minimatch": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/history": {
|
||||
"version": "4.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.6.tgz",
|
||||
"integrity": "sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w=="
|
||||
},
|
||||
"@types/html-minifier-terser": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.0.0.tgz",
|
||||
@ -102,19 +155,36 @@
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.9.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.34.tgz",
|
||||
"integrity": "sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz",
|
||||
"integrity": "sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==",
|
||||
"requires": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router-dom": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.5.tgz",
|
||||
"integrity": "sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==",
|
||||
"requires": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||
@ -1326,39 +1396,33 @@
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
|
||||
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
|
||||
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^2.1.1",
|
||||
"strip-ansi": "^4.0.0",
|
||||
"wrap-ansi": "^2.0.0"
|
||||
"string-width": "^3.1.0",
|
||||
"strip-ansi": "^5.2.0",
|
||||
"wrap-ansi": "^5.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"dev": true
|
||||
},
|
||||
"collection-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||
@ -1690,8 +1754,7 @@
|
||||
"csstype": {
|
||||
"version": "2.6.10",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz",
|
||||
"integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w=="
|
||||
},
|
||||
"cyclist": {
|
||||
"version": "1.0.1",
|
||||
@ -2150,9 +2213,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
|
||||
"integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz",
|
||||
"integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==",
|
||||
"dev": true
|
||||
},
|
||||
"events": {
|
||||
@ -2592,30 +2655,10 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
|
||||
"integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.12.1.tgz",
|
||||
"integrity": "sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
@ -3355,9 +3398,9 @@
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
||||
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-stream": {
|
||||
@ -3584,6 +3627,19 @@
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"history": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"loose-envify": "^1.2.0",
|
||||
"resolve-pathname": "^3.0.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0",
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
@ -3595,6 +3651,14 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"homedir-polyfill": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
|
||||
@ -3722,16 +3786,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"http-parser-js": {
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
|
||||
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
|
||||
"dev": true
|
||||
},
|
||||
"http-proxy": {
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
|
||||
"integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "^4.0.0",
|
||||
@ -4204,8 +4262,7 @@
|
||||
"js-tokens": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
|
||||
"dev": true
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
||||
},
|
||||
"json-merge-patch": {
|
||||
"version": "0.2.3",
|
||||
@ -4290,9 +4347,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"dev": true
|
||||
},
|
||||
"loglevel": {
|
||||
@ -4301,6 +4358,14 @@
|
||||
"integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==",
|
||||
"dev": true
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
|
||||
@ -4444,18 +4509,18 @@
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
|
||||
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.26",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
|
||||
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-db": "1.43.0"
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"mimic-fn": {
|
||||
@ -4464,6 +4529,15 @@
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"dev": true
|
||||
},
|
||||
"mini-create-react-context": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz",
|
||||
"integrity": "sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"tiny-warning": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"mini-css-extract-plugin": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz",
|
||||
@ -4727,17 +4801,10 @@
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
@ -5117,9 +5184,9 @@
|
||||
}
|
||||
},
|
||||
"portfinder": {
|
||||
"version": "1.0.25",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
|
||||
"integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==",
|
||||
"version": "1.0.26",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz",
|
||||
"integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async": "^2.6.2",
|
||||
@ -5236,32 +5303,6 @@
|
||||
"integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==",
|
||||
"dev": true
|
||||
},
|
||||
"preact": {
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.4.1.tgz",
|
||||
"integrity": "sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q=="
|
||||
},
|
||||
"preact-markup": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/preact-markup/-/preact-markup-1.6.0.tgz",
|
||||
"integrity": "sha1-n00oV2FTHdda8+HSzRIVBbCZhrw=",
|
||||
"requires": {
|
||||
"preact": "*"
|
||||
}
|
||||
},
|
||||
"preact-render-to-string": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.1.6.tgz",
|
||||
"integrity": "sha512-/8mDzzfMrxx5tzJazKGdyYADrmjzBR3QJsvdZs03aV9VjeXpDrzDHs6dhzlMA1EsdCBq4cqioKjVKUs58uNckg==",
|
||||
"requires": {
|
||||
"pretty-format": "^3.8.0"
|
||||
}
|
||||
},
|
||||
"preact-router": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/preact-router/-/preact-router-3.2.1.tgz",
|
||||
"integrity": "sha512-KEN2VN1DxUlTwzW5IFkF13YIA2OdQ2OvgJTkQREF+AA2NrHRLaGbB68EjS4IeZOa1shvQ1FvEm3bSLta4sXBhg=="
|
||||
},
|
||||
"prepend-http": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||
@ -5285,11 +5326,6 @@
|
||||
"utila": "~0.4"
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||
"integrity": "sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U="
|
||||
},
|
||||
"process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
@ -5308,6 +5344,16 @@
|
||||
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
|
||||
"dev": true
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
|
||||
@ -5455,6 +5501,90 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
|
||||
"integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz",
|
||||
"integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.9.0"
|
||||
}
|
||||
},
|
||||
"react-router": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
|
||||
"integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"history": "^4.9.0",
|
||||
"hoist-non-react-statics": "^3.1.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"mini-create-react-context": "^0.4.0",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.6.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
|
||||
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
|
||||
"requires": {
|
||||
"isarray": "0.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz",
|
||||
"integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"history": "^4.9.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-router": "5.2.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
@ -5586,6 +5716,28 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
|
||||
"integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"symbol-observable": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"redux-saga": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz",
|
||||
"integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
|
||||
"requires": {
|
||||
"@redux-saga/core": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
|
||||
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
|
||||
},
|
||||
"regex-not": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
|
||||
@ -5655,9 +5807,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
||||
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||
"dev": true
|
||||
},
|
||||
"requires-port": {
|
||||
@ -5704,6 +5856,11 @@
|
||||
"integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-pathname": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
|
||||
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
|
||||
},
|
||||
"resolve-url": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||
@ -5857,6 +6014,15 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
|
||||
@ -6157,13 +6323,14 @@
|
||||
}
|
||||
},
|
||||
"sockjs": {
|
||||
"version": "0.3.19",
|
||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
|
||||
"integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
|
||||
"version": "0.3.20",
|
||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz",
|
||||
"integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"faye-websocket": "^0.10.0",
|
||||
"uuid": "^3.0.1"
|
||||
"uuid": "^3.4.0",
|
||||
"websocket-driver": "0.6.5"
|
||||
}
|
||||
},
|
||||
"sockjs-client": {
|
||||
@ -6427,28 +6594,29 @@
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
"strip-ansi": "^5.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6562,6 +6730,11 @@
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||
},
|
||||
"tapable": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
|
||||
@ -6637,6 +6810,16 @@
|
||||
"setimmediate": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"tiny-invariant": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
|
||||
"integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||
},
|
||||
"to-arraybuffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
|
||||
@ -6742,6 +6925,27 @@
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w=="
|
||||
},
|
||||
"typescript-compare": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
|
||||
"integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
|
||||
"requires": {
|
||||
"typescript-logic": "^0.0.0"
|
||||
}
|
||||
},
|
||||
"typescript-logic": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
|
||||
"integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
|
||||
},
|
||||
"typescript-tuple": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
|
||||
"integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
|
||||
"requires": {
|
||||
"typescript-compare": "^0.0.2"
|
||||
}
|
||||
},
|
||||
"union-value": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
||||
@ -6935,6 +7139,11 @@
|
||||
"integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==",
|
||||
"dev": true
|
||||
},
|
||||
"value-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
|
||||
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
@ -7294,17 +7503,17 @@
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
|
||||
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
|
||||
"version": "2.4.6",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
|
||||
"integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
"version": "3.10.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz",
|
||||
"integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==",
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz",
|
||||
"integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-html": "0.0.7",
|
||||
@ -7315,31 +7524,31 @@
|
||||
"debug": "^4.1.1",
|
||||
"del": "^4.1.1",
|
||||
"express": "^4.17.1",
|
||||
"html-entities": "^1.2.1",
|
||||
"html-entities": "^1.3.1",
|
||||
"http-proxy-middleware": "0.19.1",
|
||||
"import-local": "^2.0.0",
|
||||
"internal-ip": "^4.3.0",
|
||||
"ip": "^1.1.5",
|
||||
"is-absolute-url": "^3.0.3",
|
||||
"killable": "^1.0.1",
|
||||
"loglevel": "^1.6.6",
|
||||
"loglevel": "^1.6.8",
|
||||
"opn": "^5.5.0",
|
||||
"p-retry": "^3.0.1",
|
||||
"portfinder": "^1.0.25",
|
||||
"portfinder": "^1.0.26",
|
||||
"schema-utils": "^1.0.0",
|
||||
"selfsigned": "^1.10.7",
|
||||
"semver": "^6.3.0",
|
||||
"serve-index": "^1.9.1",
|
||||
"sockjs": "0.3.19",
|
||||
"sockjs": "0.3.20",
|
||||
"sockjs-client": "1.4.0",
|
||||
"spdy": "^4.0.1",
|
||||
"spdy": "^4.0.2",
|
||||
"strip-ansi": "^3.0.1",
|
||||
"supports-color": "^6.1.0",
|
||||
"url": "^0.11.0",
|
||||
"webpack-dev-middleware": "^3.7.2",
|
||||
"webpack-log": "^2.0.0",
|
||||
"ws": "^6.2.1",
|
||||
"yargs": "12.0.5"
|
||||
"yargs": "^13.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@ -7397,20 +7606,18 @@
|
||||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
|
||||
"integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
|
||||
"version": "0.6.5",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
|
||||
"integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"http-parser-js": ">=0.4.0 <0.4.11",
|
||||
"safe-buffer": ">=5.1.0",
|
||||
"websocket-extensions": ">=0.1.1"
|
||||
}
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
|
||||
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
|
||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
@ -7447,33 +7654,29 @@
|
||||
}
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
||||
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^1.0.1",
|
||||
"strip-ansi": "^3.0.1"
|
||||
"ansi-styles": "^3.2.0",
|
||||
"string-width": "^3.0.0",
|
||||
"strip-ansi": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
"strip-ansi": "^3.0.0"
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7512,29 +7715,27 @@
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "12.0.5",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
|
||||
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
|
||||
"version": "13.3.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
|
||||
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^4.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"cliui": "^5.0.0",
|
||||
"find-up": "^3.0.0",
|
||||
"get-caller-file": "^1.0.1",
|
||||
"os-locale": "^3.0.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^1.0.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^2.0.0",
|
||||
"string-width": "^3.0.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^3.2.1 || ^4.0.0",
|
||||
"yargs-parser": "^11.1.1"
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^13.1.2"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
|
||||
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
|
||||
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
|
@ -6,14 +6,17 @@
|
||||
"dependencies": {
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/json-merge-patch": "0.0.4",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"bs58": "^4.0.1",
|
||||
"bulma": "^0.8.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"json-merge-patch": "^0.2.3",
|
||||
"preact": "^10.4.1",
|
||||
"preact-markup": "^1.6.0",
|
||||
"preact-render-to-string": "^5.1.6",
|
||||
"preact-router": "^3.2.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-redux": "^7.2.0",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"style-loader": "^1.1.4",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
@ -28,7 +31,7 @@
|
||||
"ts-loader": "^7.0.1",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3"
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "NODE_ENV=development webpack-dev-server --watch",
|
||||
|
@ -1,25 +1,22 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import { Route, Router, RouterOnChangeArgs } from "preact-router";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
|
||||
|
||||
import Home from "../routes/home/index";
|
||||
import Project from "../routes/project/index";
|
||||
import NotFoundPage from '../routes/notfound/index';
|
||||
import NotFound from '../routes/notfound/index';
|
||||
import Header from "./header/index";
|
||||
import Footer from "./footer";
|
||||
|
||||
const App: FunctionalComponent = () => {
|
||||
let currentUrl: string;
|
||||
const handleRoute = (e: RouterOnChangeArgs) => {
|
||||
currentUrl = e.url;
|
||||
};
|
||||
|
||||
const App: FunctionComponent = () => {
|
||||
return (
|
||||
<div id="app">
|
||||
<Header class="noPrint" />
|
||||
<Router onChange={handleRoute}>
|
||||
<Route path="/" component={Home} />
|
||||
<Route path="/p/:projectId" component={Project} />
|
||||
<NotFoundPage default />
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route exact path="/p/:projectId" component={Project} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
</Router>
|
||||
<Footer />
|
||||
</div>
|
||||
|
@ -1,16 +1,19 @@
|
||||
import { FunctionalComponent, h, Component, ComponentChild, Fragment } from "preact";
|
||||
import React, {
|
||||
FunctionComponent, Fragment,
|
||||
ReactNode, ChangeEvent,
|
||||
useState, useEffect
|
||||
} from "react";
|
||||
import * as style from "./style.module.css";
|
||||
import { useState, useEffect } from "preact/hooks";
|
||||
|
||||
export interface EditableTextProps {
|
||||
value: string
|
||||
class?: string
|
||||
editIconClass?: string
|
||||
onChange?: (value: string) => void
|
||||
render?: (value: string) => ComponentChild
|
||||
render?: (value: string) => ReactNode
|
||||
}
|
||||
|
||||
const EditableText: FunctionalComponent<EditableTextProps> = ({ onChange, value, render, ...props }) => {
|
||||
const EditableText: FunctionComponent<EditableTextProps> = ({ onChange, value, render, ...props }) => {
|
||||
const [ internalValue, setInternalValue ] = useState(value);
|
||||
const [ editMode, setEditMode ] = useState(false);
|
||||
|
||||
@ -31,28 +34,28 @@ const EditableText: FunctionalComponent<EditableTextProps> = ({ onChange, value,
|
||||
setEditMode(false);
|
||||
}
|
||||
|
||||
const onValueChange = (evt: Event) => {
|
||||
const onValueChange = (evt: ChangeEvent) => {
|
||||
const currentTarget = evt.currentTarget as HTMLInputElement;
|
||||
setInternalValue(currentTarget.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class={`${style.editableText} ${props.class ? props.class : ''}`}>
|
||||
{
|
||||
editMode ?
|
||||
<div class="field has-addons">
|
||||
<div class="control">
|
||||
<input class="input is-expanded" type="text" value={internalValue} onChange={onValueChange} />
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button" onClick={onValidateButtonClick}>✔️</a>
|
||||
</div>
|
||||
</div> :
|
||||
<Fragment>
|
||||
{ render ? render(internalValue) : <span>{internalValue}</span> }
|
||||
<i class={`${style.editIcon} icon ${props.editIconClass ? props.editIconClass : ''}`} onClick={onEditIconClick}>🖋️</i>
|
||||
</Fragment>
|
||||
}
|
||||
<div className={`${style.editableText} ${props.class ? props.class : ''}`}>
|
||||
{
|
||||
editMode ?
|
||||
<div className="field has-addons">
|
||||
<div className="control">
|
||||
<input className="input is-expanded" type="text" value={internalValue} onChange={onValueChange} />
|
||||
</div>
|
||||
<div className="control">
|
||||
<a className="button" onClick={onValidateButtonClick}>✔️</a>
|
||||
</div>
|
||||
</div> :
|
||||
<Fragment>
|
||||
{ render ? render(internalValue) : <span>{internalValue}</span> }
|
||||
<i className={`${style.editIcon} icon ${props.editIconClass ? props.editIconClass : ''}`} onClick={onEditIconClick}>🖋️</i>
|
||||
</Fragment>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import ProjectTimeUnit from "./project-time-unit";
|
||||
import { defaults, getRoundUpEstimations } from "../models/params";
|
||||
import { getRoundUpEstimations } from "../models/params";
|
||||
import { Project } from "../models/project";
|
||||
import { FunctionalComponent, Fragment, h } from "preact";
|
||||
import React, { Fragment,FunctionComponent } from "react";
|
||||
import { Estimation } from "../hooks/use-project-estimations";
|
||||
|
||||
export interface EstimationRangeProps {
|
||||
@ -9,7 +9,7 @@ export interface EstimationRangeProps {
|
||||
estimation: Estimation
|
||||
}
|
||||
|
||||
export const EstimationRange: FunctionalComponent<EstimationRangeProps> = ({ project, estimation }) => {
|
||||
export const EstimationRange: FunctionComponent<EstimationRangeProps> = ({ project, estimation }) => {
|
||||
const roundUp = getRoundUpEstimations(project);
|
||||
let e: number|string = estimation.e;
|
||||
let sd: number|string = estimation.sd;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import style from "./style.module.css";
|
||||
|
||||
declare var __BUILD__: any;
|
||||
@ -7,16 +7,15 @@ export interface FooterProps {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const Footer: FunctionalComponent<FooterProps> = ({ ...props}) => {
|
||||
console.log(__BUILD__)
|
||||
const Footer: FunctionComponent<FooterProps> = ({ ...props}) => {
|
||||
return (
|
||||
<div class={`container ${style.footer} ${props.class ? props.class : ''}`}>
|
||||
<div class="columns">
|
||||
<div class="column is-4 is-offset-8">
|
||||
<p class="has-text-right is-size-7">
|
||||
Propulsé par <a class="has-text-primary" href="https://forge.cadoles.com/wpetit/guesstimate">Guesstimate</a> et publié sous licence <a class="has-text-primary" href="https://www.gnu.org/licenses/agpl-3.0.txt">AGPL-3.0</a>.
|
||||
<div className={`container ${style.footer} ${props.class ? props.class : ''}`}>
|
||||
<div className="columns">
|
||||
<div className="column is-4 is-offset-8">
|
||||
<p className="has-text-right is-size-7">
|
||||
Propulsé par <a className="has-text-primary" href="https://forge.cadoles.com/wpetit/guesstimate">Guesstimate</a> et publié sous licence <a className="has-text-primary" href="https://www.gnu.org/licenses/agpl-3.0.txt">AGPL-3.0</a>.
|
||||
</p>
|
||||
<p class="has-text-right is-size-7">
|
||||
<p className="has-text-right is-size-7">
|
||||
Version: {__BUILD__.version} -
|
||||
Réf.: {__BUILD__.gitRef ? __BUILD__.gitRef : '??'} -
|
||||
Date de construction: {__BUILD__.buildDate ? __BUILD__.buildDate : '??'}
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import style from "./style.module.css";
|
||||
|
||||
export interface HeaderProps {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const Header: FunctionalComponent<HeaderProps> = ({ ...props}) => {
|
||||
const Header: FunctionComponent<HeaderProps> = ({ ...props}) => {
|
||||
return (
|
||||
<div class={`container ${style.header} ${props.class ? props.class : ''}`}>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="/">
|
||||
<h1 class="title is-size-4">⏱️ Guesstimate</h1>
|
||||
<div className={`container ${style.header} ${props.class ? props.class : ''}`}>
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
<nav className="navbar" role="navigation" aria-label="main navigation">
|
||||
<div className="navbar-brand">
|
||||
<a className="navbar-item" href="/">
|
||||
<h1 className="title is-size-4">⏱️ Guesstimate</h1>
|
||||
</a>
|
||||
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false">
|
||||
<a role="button" className="navbar-burger" aria-label="menu" aria-expanded="false">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Project } from "../models/project";
|
||||
import { getTimeUnit } from "../models/params";
|
||||
|
||||
@ -6,7 +6,7 @@ export interface ProjectTimeUnitProps {
|
||||
project: Project
|
||||
}
|
||||
|
||||
const ProjectTimeUnit: FunctionalComponent<ProjectTimeUnitProps> = ({ project }) => {
|
||||
const ProjectTimeUnit: FunctionComponent<ProjectTimeUnitProps> = ({ project }) => {
|
||||
const timeUnit = getTimeUnit(project);
|
||||
return (
|
||||
<abbr title={timeUnit.label}>{timeUnit.acronym}</abbr>
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { FunctionalComponent, h, ComponentChild } from "preact";
|
||||
import React, { FunctionComponent, useState, ReactNode } from "react";
|
||||
import style from "./style.module.css";
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
export interface TabItem {
|
||||
label: string
|
||||
icon?: string
|
||||
render: () => ComponentChild
|
||||
render: () => ReactNode
|
||||
}
|
||||
|
||||
export interface TabsProps {
|
||||
@ -13,7 +12,7 @@ export interface TabsProps {
|
||||
items: TabItem[]
|
||||
}
|
||||
|
||||
const Tabs: FunctionalComponent<TabsProps> = ({ items, ...props }) => {
|
||||
const Tabs: FunctionComponent<TabsProps> = ({ items, ...props }) => {
|
||||
const [ selectedTabIndex, setSelectedTabIndex ] = useState(0);
|
||||
|
||||
const onTabClick = (tabIndex: number) => {
|
||||
@ -23,16 +22,16 @@ const Tabs: FunctionalComponent<TabsProps> = ({ items, ...props }) => {
|
||||
const selectedTab = items[selectedTabIndex];
|
||||
|
||||
return (
|
||||
<div class={`${style.tabs} ${props.class}`}>
|
||||
<div class="tabs">
|
||||
<ul class={`noPrint`}>
|
||||
<div className={`${style.tabs} ${props.class}`}>
|
||||
<div className="tabs">
|
||||
<ul className={`noPrint`}>
|
||||
{
|
||||
items.map((tabItem, tabIndex) => (
|
||||
<li key={`tab-${tabIndex}`}
|
||||
onClick={onTabClick.bind(null, tabIndex)}
|
||||
class={`${selectedTabIndex === tabIndex ? 'is-active' : ''}`}>
|
||||
className={`${selectedTabIndex === tabIndex ? 'is-active' : ''}`}>
|
||||
<a>
|
||||
<span class="icon is-small">{tabItem.icon}</span>
|
||||
<span className="icon is-small">{tabItem.icon}</span>
|
||||
{tabItem.label}
|
||||
</a>
|
||||
</li>
|
||||
@ -40,7 +39,7 @@ const Tabs: FunctionalComponent<TabsProps> = ({ items, ...props }) => {
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<div class={style.tabContent}>
|
||||
<div className={style.tabContent}>
|
||||
{ selectedTab.render() }
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useMemo, useState } from "preact/hooks";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
export default function useDebounce(func: Function, delay: number) {
|
||||
const [id, setId] = useState<number|null>(null)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import { useState } from "react";
|
||||
|
||||
export function useLocalStorage<T>(key: string, initialValue: T) {
|
||||
// State to store our value
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useMediaQuery(query: string): boolean {
|
||||
const media = window.matchMedia(query);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useEffect, useRef } from "preact/hooks";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export function usePrevious<T>(value: T): T|undefined {
|
||||
const ref = useRef();
|
||||
const ref = useRef<T>();
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Project } from "../models/project";
|
||||
import { useState, useEffect } from "preact/hooks";
|
||||
import { useState, useEffect } from "react";
|
||||
import { getProjectWeightedMean, getProjectStandardDeviation } from "../util/stat";
|
||||
|
||||
export interface Estimation {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Project } from "../models/project";
|
||||
import { Task, TaskID, EstimationConfidence, TaskCategoryID, TaskCategory } from "../models/task";
|
||||
import { useReducer } from "preact/hooks";
|
||||
import { useReducer } from "react";
|
||||
import { generate as diff } from "json-merge-patch";
|
||||
import { applyPatch } from "../util/patch";
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { Project } from "../models/project";
|
||||
import { usePrevious } from "./use-previous";
|
||||
import { useEffect, useState, useRef } from "preact/hooks";
|
||||
import { useEffect, useState } from "react";
|
||||
import { generate as diff } from "json-merge-patch";
|
||||
import useDebounce from "./use-debounce";
|
||||
|
||||
export interface ServerSyncOptions {
|
||||
projectURL: string
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {Project} from "../models/project";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useState } from "react";
|
||||
import { ProjectStorageKeyPrefix } from "../util/storage";
|
||||
|
||||
export function loadStoredProjects(): Project[] {
|
||||
|
@ -2,13 +2,11 @@ import "./style/index.css";
|
||||
import "bulma/css/bulma.css";
|
||||
import "bulma-switch/dist/css/bulma-switch.min.css";
|
||||
|
||||
import { h, render } from 'preact'
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import App from "./components/app";
|
||||
|
||||
render(h(App, {}), document.getElementById('app'));
|
||||
|
||||
// Hot Module Replacement
|
||||
if (module.hot) {
|
||||
require("preact/debug");
|
||||
module.hot.accept();
|
||||
}
|
||||
render(
|
||||
React.createElement(App, {}, null),
|
||||
document.getElementById('app')
|
||||
);
|
@ -1,49 +1,50 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import style from "./style.module.css";
|
||||
import { route } from 'preact-router';
|
||||
import { useHistory } from 'react-router';
|
||||
import { base58UUID } from '../../util/uuid';
|
||||
import { useStoredProjectList } from "../../hooks/use-stored-project-list";
|
||||
|
||||
const Home: FunctionalComponent = () => {
|
||||
const Home: FunctionComponent = () => {
|
||||
const [ projects, refreshProjects ] = useStoredProjectList();
|
||||
const history = useHistory();
|
||||
|
||||
const openNewProject = () => {
|
||||
const uuid = base58UUID();
|
||||
route(`/p/${uuid}`);
|
||||
history.push(`/p/${uuid}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class={`container ${style.home}`}>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="buttons is-right">
|
||||
<button class="button is-primary"
|
||||
<div className={`container ${style.home}`}>
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
<div className="buttons is-right">
|
||||
<button className="button is-primary"
|
||||
onClick={openNewProject}>
|
||||
<strong>+</strong> Nouveau projet
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<p class="panel-heading">
|
||||
<div className="panel">
|
||||
<p className="panel-heading">
|
||||
Mes projets
|
||||
</p>
|
||||
{/* <div class="panel-block">
|
||||
<p class="control has-icons-left">
|
||||
<input class="input" type="text" placeholder="Search" />
|
||||
<span class="icon is-left">🔍</span>
|
||||
{/* <div className="panel-block">
|
||||
<p className="control has-icons-left">
|
||||
<input className="input" type="text" placeholder="Search" />
|
||||
<span className="icon is-left">🔍</span>
|
||||
</p>
|
||||
</div> */}
|
||||
{
|
||||
projects.map(p => (
|
||||
<a class="panel-block" href={`/p/${p.id}`}>
|
||||
<span class="panel-icon">🗒️</span>
|
||||
<a key={`project-${p.id}`} className="panel-block" href={`/p/${p.id}`}>
|
||||
<span className="panel-icon">🗒️</span>
|
||||
{ p.label ? p.label : "Projet sans nom" }
|
||||
</a>
|
||||
))
|
||||
}
|
||||
{
|
||||
projects.length === 0 ?
|
||||
<p class="panel-block">
|
||||
<div class={style.noProjects}>Aucun project pour l'instant.</div>
|
||||
<p className="panel-block">
|
||||
<div className={style.noProjects}>Aucun project pour l'instant.</div>
|
||||
</p> :
|
||||
null
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import { Link } from 'preact-router/match';
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Link } from 'react-router-dom';
|
||||
import style from "./style.module.css";
|
||||
|
||||
const Notfound: FunctionalComponent = () => {
|
||||
const NotFound: FunctionComponent = () => {
|
||||
return (
|
||||
<div class={style.notFound}>
|
||||
<div className={style.notFound}>
|
||||
<h1>Error 404</h1>
|
||||
<p>That page doesn't exist.</p>
|
||||
<Link href="/"><h4>Back to Home</h4></Link>
|
||||
<Link to="/"><h4>Back to Home</h4></Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notfound;
|
||||
export default NotFound;
|
@ -1,9 +1,9 @@
|
||||
import { FunctionalComponent, h, Fragment } from "preact";
|
||||
import React, { FunctionComponent, Fragment } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import TaskTable from "./tasks-table";
|
||||
import TimePreview from "./time-preview";
|
||||
import FinancialPreview from "./financial-preview";
|
||||
import { addTask, updateTaskEstimation, removeTask, updateProjectLabel, updateTaskLabel, ProjectReducerActions } from "../../hooks/use-project-reducer";
|
||||
import { addTask, updateTaskEstimation, removeTask, updateTaskLabel, ProjectReducerActions } from "../../hooks/use-project-reducer";
|
||||
import { Task, TaskID, EstimationConfidence } from "../../models/task";
|
||||
import RepartitionPreview from "./repartition-preview";
|
||||
import { getHideFinancialPreviewOnPrint } from "../../models/params";
|
||||
@ -13,7 +13,7 @@ export interface EstimationTabProps {
|
||||
dispatch: (action: ProjectReducerActions) => void
|
||||
}
|
||||
|
||||
const EstimationTab: FunctionalComponent<EstimationTabProps> = ({ project, dispatch }) => {
|
||||
const EstimationTab: FunctionComponent<EstimationTabProps> = ({ project, dispatch }) => {
|
||||
const onTaskAdd = (task: Task) => {
|
||||
dispatch(addTask(task));
|
||||
};
|
||||
@ -32,8 +32,8 @@ const EstimationTab: FunctionalComponent<EstimationTabProps> = ({ project, dispa
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div class="columns">
|
||||
<div class="column is-9">
|
||||
<div className="columns">
|
||||
<div className="column is-9">
|
||||
<TaskTable
|
||||
project={project}
|
||||
onTaskAdd={onTaskAdd}
|
||||
@ -41,20 +41,20 @@ const EstimationTab: FunctionalComponent<EstimationTabProps> = ({ project, dispa
|
||||
onTaskLabelUpdate={onTaskLabelUpdate}
|
||||
onEstimationChange={onEstimationChange} />
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<div className="column is-3">
|
||||
<TimePreview project={project} />
|
||||
<RepartitionPreview project={project} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class={`column ${getHideFinancialPreviewOnPrint(project) ? 'noPrint': ''}`}>
|
||||
<div className="columns">
|
||||
<div className={`column ${getHideFinancialPreviewOnPrint(project) ? 'noPrint': ''}`}>
|
||||
<FinancialPreview project={project} />
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
Object.keys(project.tasks).length <= 20 ?
|
||||
<div class="message noPrint">
|
||||
<div class="message-body">
|
||||
<div className="message noPrint">
|
||||
<div className="message-body">
|
||||
<p><strong>⚠️ Attention</strong></p>
|
||||
<p>Votre projet ne contient pas assez de tâches pour que les niveaux de confiance soient fiables. Un minimum de 20 tâches est conseillé pour obtenir une estimation pertinente.</p>
|
||||
</div>
|
||||
|
@ -1,15 +1,14 @@
|
||||
import { FunctionalComponent, h, Fragment } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import { useProjectEstimations, Estimation } from "../../hooks/use-project-estimations";
|
||||
|
||||
export interface ExportTabProps {
|
||||
project: Project
|
||||
}
|
||||
|
||||
const ExportTab: FunctionalComponent<ExportTabProps> = ({ project }) => {
|
||||
const ExportTab: FunctionComponent<ExportTabProps> = ({ project }) => {
|
||||
return (
|
||||
<div>
|
||||
<label class="label is-size-4">Format JSON</label>
|
||||
<label className="label is-size-4">Format JSON</label>
|
||||
<pre>{ JSON.stringify(project, null, 2) }</pre>
|
||||
<hr />
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import { useProjectEstimations } from "../../hooks/use-project-estimations";
|
||||
import { getCurrency, defaults, getTaskCategoryCost, getRoundUpEstimations } from "../../models/params";
|
||||
@ -10,34 +10,34 @@ export interface FinancialPreviewProps {
|
||||
project: Project
|
||||
}
|
||||
|
||||
const FinancialPreview: FunctionalComponent<FinancialPreviewProps> = ({ project }) => {
|
||||
const FinancialPreview: FunctionComponent<FinancialPreviewProps> = ({ project }) => {
|
||||
const estimations = useProjectEstimations(project);
|
||||
const costs = getMinMaxCosts(project, estimations.p99);
|
||||
const roundUp = getRoundUpEstimations(project);
|
||||
return (
|
||||
<div class="table-container">
|
||||
<table class="table is-bordered is-striped is-fullwidth">
|
||||
<div className="table-container">
|
||||
<table className="table is-bordered is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2}>
|
||||
<span>Prévisionnel financier</span><br />
|
||||
<span class="is-size-7 has-text-weight-normal">confiance >= 99.7%</span>
|
||||
<span className="is-size-7 has-text-weight-normal">confiance >= 99.7%</span>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="is-narrow">Temps</th>
|
||||
<th className="is-narrow">Temps</th>
|
||||
<th>Coût</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="is-narrow">Maximum</td>
|
||||
<td className="is-narrow">Maximum</td>
|
||||
<td>
|
||||
<CostDetails project={project} cost={costs.max} roundUp={roundUp} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="is-narrow">Minimum</td>
|
||||
<td className="is-narrow">Minimum</td>
|
||||
<td>
|
||||
<CostDetails project={project} cost={costs.min} roundUp={roundUp} />
|
||||
</td>
|
||||
@ -54,14 +54,14 @@ export interface CostDetailsProps {
|
||||
roundUp: boolean
|
||||
}
|
||||
|
||||
export const CostDetails:FunctionalComponent<CostDetailsProps> = ({ project, cost, roundUp }) => {
|
||||
export const CostDetails:FunctionComponent<CostDetailsProps> = ({ project, cost, roundUp }) => {
|
||||
return (
|
||||
<details>
|
||||
<summary><strong>
|
||||
≈ {cost.totalCost} {getCurrency(project)}</strong>
|
||||
<span class="is-pulled-right">{ roundUp ? Math.ceil(cost.totalTime) : cost.totalTime.toFixed(2) } <ProjectTimeUnit project={project} /></span>
|
||||
<span className="is-pulled-right">{ roundUp ? Math.ceil(cost.totalTime) : cost.totalTime.toFixed(2) } <ProjectTimeUnit project={project} /></span>
|
||||
</summary>
|
||||
<table class={`table is-fullwidth`}>
|
||||
<table className={`table is-fullwidth`}>
|
||||
<tbody>
|
||||
{
|
||||
Object.keys(cost.details).map(taskCategoryId => {
|
||||
@ -69,9 +69,9 @@ export const CostDetails:FunctionalComponent<CostDetailsProps> = ({ project, cos
|
||||
const details = cost.details[taskCategoryId];
|
||||
return (
|
||||
<tr key={`task-category-cost-${taskCategory.id}`}>
|
||||
<td class={`${style.noBorder} is-size-6`}>{taskCategory.label}</td>
|
||||
<td class={`${style.noBorder} is-size-6`}>{details.cost} {getCurrency(project)}</td>
|
||||
<td class={`${style.noBorder} is-size-6`}>{ roundUp ? Math.ceil(details.time) : details.time.toFixed(2) } <ProjectTimeUnit project={project} /> × {getTaskCategoryCost(taskCategory)} {getCurrency(project)}</td>
|
||||
<td className={`${style.noBorder} is-size-6`}>{taskCategory.label}</td>
|
||||
<td className={`${style.noBorder} is-size-6`}>{details.cost} {getCurrency(project)}</td>
|
||||
<td className={`${style.noBorder} is-size-6`}>{ roundUp ? Math.ceil(details.time) : details.time.toFixed(2) } <ProjectTimeUnit project={project} /> × {getTaskCategoryCost(taskCategory)} {getCurrency(project)}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import { useEffect } from "preact/hooks";
|
||||
import React, { FunctionComponent, useEffect } from "react";
|
||||
import style from "./style.module.css";
|
||||
import { newProject, Project } from "../../models/project";
|
||||
import { useProjectReducer, updateProjectLabel, patchProject } from "../../hooks/use-project-reducer";
|
||||
@ -11,58 +10,60 @@ import EstimationTab from "./estimation-tab";
|
||||
import ParamsTab from "./params-tab";
|
||||
import ExportTab from "./export-tab";
|
||||
import { useServerSync } from "../../hooks/use-server-sync";
|
||||
import { RouteChildrenProps, RouteProps, useParams } from "react-router";
|
||||
|
||||
export interface ProjectProps {
|
||||
projectId: string
|
||||
projectId: string
|
||||
}
|
||||
|
||||
const Project: FunctionalComponent<ProjectProps> = ({ projectId }) => {
|
||||
const projectStorageKey = getProjectStorageKey(projectId);
|
||||
const [ storedProject, storeProject ] = useLocalStorage(projectStorageKey, newProject(projectId));
|
||||
const [ project, dispatch ] = useProjectReducer(storedProject);
|
||||
|
||||
useServerSync(project, (project: Project) => {
|
||||
dispatch(patchProject(project));
|
||||
});
|
||||
|
||||
const onProjectLabelChange = (projectLabel: string) => {
|
||||
dispatch(updateProjectLabel(projectLabel));
|
||||
};
|
||||
|
||||
// Save project in local storage on change
|
||||
useEffect(()=> {
|
||||
storeProject(project);
|
||||
}, [project]);
|
||||
|
||||
return (
|
||||
<div class={`container ${style.estimation}`}>
|
||||
<EditableText
|
||||
editIconClass="is-size-4"
|
||||
render={(value) => (<h2 class="is-size-3">{value}</h2>)}
|
||||
onChange={onProjectLabelChange}
|
||||
value={project.label ? project.label : "Projet sans nom"} />
|
||||
<div class={style.tabContainer}>
|
||||
<Tabs items={[
|
||||
{
|
||||
label: 'Estimation',
|
||||
icon: '📋',
|
||||
render: () => <EstimationTab project={project} dispatch={dispatch} />
|
||||
},
|
||||
{
|
||||
label: 'Options avancées',
|
||||
icon: '⚙️',
|
||||
render: () => <ParamsTab project={project} dispatch={dispatch} />
|
||||
},
|
||||
{
|
||||
label: 'Exporter',
|
||||
icon: '↗️',
|
||||
render: () => <ExportTab project={project} />
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const Project: FunctionComponent<ProjectProps> = () => {
|
||||
const { projectId } = useParams();
|
||||
const projectStorageKey = getProjectStorageKey(projectId);
|
||||
const [ storedProject, storeProject ] = useLocalStorage(projectStorageKey, newProject(projectId));
|
||||
const [ project, dispatch ] = useProjectReducer(storedProject);
|
||||
|
||||
useServerSync(project, (project: Project) => {
|
||||
dispatch(patchProject(project));
|
||||
});
|
||||
|
||||
const onProjectLabelChange = (projectLabel: string) => {
|
||||
dispatch(updateProjectLabel(projectLabel));
|
||||
};
|
||||
|
||||
// Save project in local storage on change
|
||||
useEffect(()=> {
|
||||
storeProject(project);
|
||||
}, [project]);
|
||||
|
||||
return (
|
||||
<div className={`container ${style.estimation}`}>
|
||||
<EditableText
|
||||
editIconClass="is-size-4"
|
||||
render={(value) => (<h2 className="is-size-3">{value}</h2>)}
|
||||
onChange={onProjectLabelChange}
|
||||
value={project.label ? project.label : "Projet sans nom"}
|
||||
/>
|
||||
<div className={style.tabContainer}>
|
||||
<Tabs items={[
|
||||
{
|
||||
label: 'Estimation',
|
||||
icon: '📋',
|
||||
render: () => <EstimationTab project={project} dispatch={dispatch} />
|
||||
},
|
||||
{
|
||||
label: 'Options avancées',
|
||||
icon: '⚙️',
|
||||
render: () => <ParamsTab project={project} dispatch={dispatch} />
|
||||
},
|
||||
{
|
||||
label: 'Exporter',
|
||||
icon: '↗️',
|
||||
render: () => <ExportTab project={project} />
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default Project;
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { FunctionalComponent, h, Fragment } from "preact";
|
||||
import React, { FunctionComponent, Fragment, useState, ChangeEvent, MouseEvent } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import { ProjectReducerActions, updateParam } from "../../hooks/use-project-reducer";
|
||||
import { getRoundUpEstimations, getCurrency, getTimeUnit, getHideFinancialPreviewOnPrint } from "../../models/params";
|
||||
import TaskCategoriesTable from "./task-categories-table";
|
||||
import { useState } from "preact/hooks";
|
||||
import { route } from "preact-router";
|
||||
import { useHistory } from "react-router";
|
||||
import { getProjectStorageKey } from "../../util/storage";
|
||||
|
||||
export interface ParamsTabProps {
|
||||
@ -12,88 +11,89 @@ export interface ParamsTabProps {
|
||||
dispatch: (action: ProjectReducerActions) => void
|
||||
}
|
||||
|
||||
const ParamsTab: FunctionalComponent<ParamsTabProps> = ({ project, dispatch }) => {
|
||||
const ParamsTab: FunctionComponent<ParamsTabProps> = ({ project, dispatch }) => {
|
||||
const [ deleteButtonEnabled, setDeleteButtonEnabled ] = useState(false);
|
||||
const history = useHistory();
|
||||
|
||||
const onEnableDeleteButtonChange = (evt: Event) => {
|
||||
const onEnableDeleteButtonChange = (evt: ChangeEvent) => {
|
||||
const checked = (evt.currentTarget as HTMLInputElement).checked;
|
||||
setDeleteButtonEnabled(checked);
|
||||
}
|
||||
|
||||
const onRoundUpChange = (evt: Event) => {
|
||||
const onRoundUpChange = (evt: ChangeEvent) => {
|
||||
const checked = (evt.currentTarget as HTMLInputElement).checked;
|
||||
dispatch(updateParam("roundUpEstimations", checked));
|
||||
};
|
||||
|
||||
const onHideFinancialPreview = (evt: Event) => {
|
||||
const onHideFinancialPreview = (evt: ChangeEvent) => {
|
||||
const checked = (evt.currentTarget as HTMLInputElement).checked;
|
||||
dispatch(updateParam("hideFinancialPreviewOnPrint", checked));
|
||||
};
|
||||
|
||||
const onCurrencyChange = (evt: Event) => {
|
||||
const onCurrencyChange = (evt: ChangeEvent) => {
|
||||
const value = (evt.currentTarget as HTMLInputElement).value;
|
||||
dispatch(updateParam("currency", value));
|
||||
};
|
||||
|
||||
const timeUnit = getTimeUnit(project);
|
||||
|
||||
const onTimeUnitLabelChange = (evt: Event) => {
|
||||
const onTimeUnitLabelChange = (evt: ChangeEvent) => {
|
||||
const value = (evt.currentTarget as HTMLInputElement).value;
|
||||
dispatch(updateParam("timeUnit", { ...timeUnit, label: value }));
|
||||
};
|
||||
|
||||
const onTimeUnitAcronymChange = (evt: Event) => {
|
||||
const onTimeUnitAcronymChange = (evt: ChangeEvent) => {
|
||||
const value = (evt.currentTarget as HTMLInputElement).value;
|
||||
dispatch(updateParam("timeUnit", { ...timeUnit, acronym: value }));
|
||||
};
|
||||
|
||||
const onDeleteProjectClick = (evt: Event) => {
|
||||
const onDeleteProjectClick = (evt: MouseEvent) => {
|
||||
const projectStorageKey = getProjectStorageKey(project.id);
|
||||
window.localStorage.removeItem(projectStorageKey);
|
||||
route('/');
|
||||
history.push('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<label class="label is-size-5">Impression</label>
|
||||
<div class="field">
|
||||
<label className="label is-size-5">Impression</label>
|
||||
<div className="field">
|
||||
<input type="checkbox"
|
||||
id="hideFinancialPreview"
|
||||
name="hideFinancialPreview"
|
||||
class="switch"
|
||||
className="switch"
|
||||
onChange={onHideFinancialPreview}
|
||||
checked={getHideFinancialPreviewOnPrint(project)} />
|
||||
<label for="hideFinancialPreview">Cacher le prévisionnel financier lors de l'impression</label>
|
||||
<label htmlFor="hideFinancialPreview">Cacher le prévisionnel financier lors de l'impression</label>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="field">
|
||||
<label class="label is-size-5">Unité de temps</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text"
|
||||
<div className="field">
|
||||
<label className="label is-size-5">Unité de temps</label>
|
||||
<div className="control">
|
||||
<input className="input" type="text"
|
||||
onChange={onTimeUnitLabelChange}
|
||||
value={timeUnit.label} />
|
||||
</div>
|
||||
<label class="label is-size-6">Acronyme</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text"
|
||||
<label className="label is-size-6">Acronyme</label>
|
||||
<div className="control">
|
||||
<input className="input" type="text"
|
||||
onChange={onTimeUnitAcronymChange}
|
||||
value={timeUnit.acronym} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div className="field">
|
||||
<input type="checkbox"
|
||||
id="roundUpEstimations"
|
||||
name="roundUpEstimations"
|
||||
class="switch"
|
||||
className="switch"
|
||||
onChange={onRoundUpChange}
|
||||
checked={getRoundUpEstimations(project)} />
|
||||
<label for="roundUpEstimations">Arrondir les estimations de temps à l'entier supérieur</label>
|
||||
<label htmlFor="roundUpEstimations">Arrondir les estimations de temps à l'entier supérieur</label>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="field">
|
||||
<label class="label is-size-5">Devise</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text"
|
||||
<div className="field">
|
||||
<label className="label is-size-5">Devise</label>
|
||||
<div className="control">
|
||||
<input className="input" type="text"
|
||||
onChange={onCurrencyChange}
|
||||
value={getCurrency(project)} />
|
||||
</div>
|
||||
@ -102,17 +102,17 @@ const ParamsTab: FunctionalComponent<ParamsTabProps> = ({ project, dispatch }) =
|
||||
<TaskCategoriesTable project={project} dispatch={dispatch} />
|
||||
<hr />
|
||||
<div>
|
||||
<label class="label is-size-5">Supprimer le projet</label>
|
||||
<div class="field">
|
||||
<label className="label is-size-5">Supprimer le projet</label>
|
||||
<div className="field">
|
||||
<input type="checkbox"
|
||||
id="enableDeleteButton"
|
||||
name="enableDeleteButton"
|
||||
class="switch is-warning"
|
||||
className="switch is-warning"
|
||||
onChange={onEnableDeleteButtonChange}
|
||||
checked={deleteButtonEnabled} />
|
||||
<label for="enableDeleteButton">Supprimer ce projet ?</label>
|
||||
<label htmlFor="enableDeleteButton">Supprimer ce projet ?</label>
|
||||
</div>
|
||||
<button class="button is-danger"
|
||||
<button className="button is-danger"
|
||||
onClick={onDeleteProjectClick}
|
||||
disabled={!deleteButtonEnabled}>
|
||||
🗑️ Supprimer
|
||||
|
@ -1,19 +1,16 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import { useProjectEstimations } from "../../hooks/use-project-estimations";
|
||||
import { getCurrency, getRoundUpEstimations } from "../../models/params";
|
||||
import ProjectTimeUnit from "../../components/project-time-unit";
|
||||
import { getTaskCategoryWeightedMean, getProjectWeightedMean, getTaskCategoriesMeanRepartition } from "../../util/stat";
|
||||
import { getTaskCategoriesMeanRepartition } from "../../util/stat";
|
||||
|
||||
export interface RepartitionPreviewProps {
|
||||
project: Project
|
||||
}
|
||||
|
||||
const RepartitionPreview: FunctionalComponent<RepartitionPreviewProps> = ({ project }) => {
|
||||
const RepartitionPreview: FunctionComponent<RepartitionPreviewProps> = ({ project }) => {
|
||||
const repartition = getTaskCategoriesMeanRepartition(project);
|
||||
return (
|
||||
<div class="table-container">
|
||||
<table class="table is-bordered is-striped is-fullwidth">
|
||||
<div className="table-container">
|
||||
<table className="table is-bordered is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2}>Répartition moyenne</th>
|
||||
|
@ -1,18 +1,17 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import React, { FunctionComponent, useState, MouseEvent, ChangeEvent } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import style from './style.module.css';
|
||||
import { ProjectReducerActions, updateTaskCategoryCost, updateTaskCategoryLabel, removeTaskCategory, addTaskCategory } from "../../hooks/use-project-reducer";
|
||||
import EditableText from "../../components/editable-text";
|
||||
import { TaskCategoryID, createTaskCategory } from "../../models/task";
|
||||
import { getCurrency, getTaskCategoryCost } from "../../models/params";
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
export interface TaskCategoriesTableProps {
|
||||
project: Project
|
||||
dispatch: (action: ProjectReducerActions) => void
|
||||
}
|
||||
|
||||
const TaskCategoriesTable: FunctionalComponent<TaskCategoriesTableProps> = ({ project, dispatch }) => {
|
||||
const TaskCategoriesTable: FunctionComponent<TaskCategoriesTableProps> = ({ project, dispatch }) => {
|
||||
const [ newTaskCategory, setNewTaskCategory ] = useState(createTaskCategory());
|
||||
|
||||
const onTaskCategoryRemove = (categoryId: TaskCategoryID) => {
|
||||
@ -28,28 +27,28 @@ const TaskCategoriesTable: FunctionalComponent<TaskCategoriesTableProps> = ({ pr
|
||||
dispatch(updateTaskCategoryCost(categoryId, cost));
|
||||
};
|
||||
|
||||
const onNewTaskCategoryCostChange = (evt: Event) => {
|
||||
const onNewTaskCategoryCostChange = (evt: ChangeEvent) => {
|
||||
const costPerTimeUnit = parseFloat((evt.currentTarget as HTMLInputElement).value);
|
||||
setNewTaskCategory(newTaskCategory => ({ ...newTaskCategory, costPerTimeUnit }));
|
||||
};
|
||||
|
||||
const onNewTaskCategoryLabelChange = (evt: Event) => {
|
||||
const onNewTaskCategoryLabelChange = (evt: ChangeEvent) => {
|
||||
const label = (evt.currentTarget as HTMLInputElement).value;
|
||||
setNewTaskCategory(newTaskCategory => ({ ...newTaskCategory, label }));
|
||||
};
|
||||
|
||||
const onNewTaskCategoryAddClick = (evt: Event) => {
|
||||
const onNewTaskCategoryAddClick = (evt: MouseEvent) => {
|
||||
dispatch(addTaskCategory(newTaskCategory));
|
||||
setNewTaskCategory(createTaskCategory());
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="table-container">
|
||||
<label class="label is-size-5">Catégories de tâche</label>
|
||||
<table class={`table is-bordered is-striped" ${style.middleTable}`}>
|
||||
<div className="table-container">
|
||||
<label className="label is-size-5">Catégories de tâche</label>
|
||||
<table className={`table is-bordered is-striped" ${style.middleTable}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class={`${style.noBorder} is-narrow`}></th>
|
||||
<th className={`${style.noBorder} is-narrow`}></th>
|
||||
<th>Catégorie</th>
|
||||
<th>Coût par unité de temps</th>
|
||||
</tr>
|
||||
@ -62,7 +61,7 @@ const TaskCategoriesTable: FunctionalComponent<TaskCategoriesTableProps> = ({ pr
|
||||
<td>
|
||||
<button
|
||||
onClick={onTaskCategoryRemove.bind(null, tc.id)}
|
||||
class="button is-danger is-small is-outlined">
|
||||
className="button is-danger is-small is-outlined">
|
||||
🗑️
|
||||
</button>
|
||||
</td>
|
||||
@ -82,22 +81,22 @@ const TaskCategoriesTable: FunctionalComponent<TaskCategoriesTableProps> = ({ pr
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td class={`${style.noBorder}`}></td>
|
||||
<td className={`${style.noBorder}`}></td>
|
||||
<td colSpan={2}>
|
||||
<div class="field has-addons">
|
||||
<p class="control is-expanded">
|
||||
<input class="input" type="text" placeholder="Nouvelle catégorie"
|
||||
<div className="field has-addons">
|
||||
<p className="control is-expanded">
|
||||
<input className="input" type="text" placeholder="Nouvelle catégorie"
|
||||
value={newTaskCategory.label} onChange={onNewTaskCategoryLabelChange} />
|
||||
</p>
|
||||
<p class="control">
|
||||
<input class="input" type="number"
|
||||
<p className="control">
|
||||
<input className="input" type="number"
|
||||
value={newTaskCategory.costPerTimeUnit} onChange={onNewTaskCategoryCostChange} />
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-static">{getCurrency(project)}</a>
|
||||
<p className="control">
|
||||
<a className="button is-static">{getCurrency(project)}</a>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-primary" onClick={onNewTaskCategoryAddClick}>
|
||||
<p className="control">
|
||||
<a className="button is-primary" onClick={onNewTaskCategoryAddClick}>
|
||||
Ajouter
|
||||
</a>
|
||||
</p>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { FunctionalComponent, h } from "preact";
|
||||
import { useState, useEffect } from "preact/hooks";
|
||||
import React, { FunctionComponent, useState, useEffect, ChangeEvent, MouseEvent } from "react";
|
||||
import style from "./style.module.css";
|
||||
import { Project } from "../../models/project";
|
||||
import { newTask, Task, TaskID, EstimationConfidence } from "../../models/task";
|
||||
@ -18,7 +17,7 @@ export interface TaskTableProps {
|
||||
|
||||
export type EstimationTotals = { [confidence in EstimationConfidence]: number }
|
||||
|
||||
const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, onEstimationChange, onTaskRemove, onTaskLabelUpdate }) => {
|
||||
const TaskTable: FunctionComponent<TaskTableProps> = ({ project, onTaskAdd, onEstimationChange, onTaskRemove, onTaskLabelUpdate }) => {
|
||||
|
||||
const defaultTaskCategory = Object.keys(project.params.taskCategories)[0];
|
||||
const [ task, setTask ] = useState(newTask("", defaultTaskCategory));
|
||||
@ -44,12 +43,12 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
setTotals({ optimistic, likely, pessimistic });
|
||||
}, [project.tasks]);
|
||||
|
||||
const onNewTaskLabelChange = (evt: Event) => {
|
||||
const onNewTaskLabelChange = (evt: ChangeEvent) => {
|
||||
const value = (evt.currentTarget as HTMLInputElement).value;
|
||||
setTask({...task, label: value});
|
||||
};
|
||||
|
||||
const onNewTaskCategoryChange = (evt: Event) => {
|
||||
const onNewTaskCategoryChange = (evt: ChangeEvent) => {
|
||||
const value = (evt.currentTarget as HTMLInputElement).value;
|
||||
setTask({...task, category: value});
|
||||
};
|
||||
@ -58,16 +57,16 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
onTaskLabelUpdate(taskId, value);
|
||||
};
|
||||
|
||||
const onAddTaskClick = (evt: Event) => {
|
||||
const onAddTaskClick = (evt: MouseEvent) => {
|
||||
onTaskAdd(task);
|
||||
setTask(newTask("", defaultTaskCategory));
|
||||
};
|
||||
|
||||
const onTaskRemoveClick = (taskId: TaskID, evt: Event) => {
|
||||
const onTaskRemoveClick = (taskId: TaskID, evt: MouseEvent) => {
|
||||
onTaskRemove(taskId);
|
||||
};
|
||||
|
||||
const withEstimationChange = (confidence: EstimationConfidence, taskID: TaskID, evt: Event) => {
|
||||
const withEstimationChange = (confidence: EstimationConfidence, taskID: TaskID, evt: ChangeEvent) => {
|
||||
const textValue = (evt.currentTarget as HTMLInputElement).value;
|
||||
const value = parseFloat(textValue);
|
||||
onEstimationChange(taskID, confidence, value);
|
||||
@ -78,12 +77,12 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
const onPessimisticChange = withEstimationChange.bind(null, EstimationConfidence.Pessimistic);
|
||||
|
||||
return (
|
||||
<div class="table-container">
|
||||
<table class={`table is-bordered is-striped is-hoverable is-fullwidth ${style.middleTable}`}>
|
||||
<div className="table-container">
|
||||
<table className={`table is-bordered is-striped is-hoverable is-fullwidth ${style.middleTable}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class={`${style.noBorder} noPrint`} rowSpan={2}></th>
|
||||
<th class={style.mainColumn} rowSpan={2}>Tâche</th>
|
||||
<th className={`${style.noBorder} noPrint`} rowSpan={2}></th>
|
||||
<th className={style.mainColumn} rowSpan={2}>Tâche</th>
|
||||
<th rowSpan={2}>Catégorie</th>
|
||||
<th colSpan={3}>Estimation (en <ProjectTimeUnit project={project} />)</th>
|
||||
</tr>
|
||||
@ -100,14 +99,14 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
const categoryLabel = category ? category.label : '???';
|
||||
return (
|
||||
<tr key={`taks-${t.id}`}>
|
||||
<td class={`is-narrow noPrint`}>
|
||||
<td className={`is-narrow noPrint`}>
|
||||
<button
|
||||
onClick={onTaskRemoveClick.bind(null, t.id)}
|
||||
class="button is-danger is-small is-outlined">
|
||||
className="button is-danger is-small is-outlined">
|
||||
🗑️
|
||||
</button>
|
||||
</td>
|
||||
<td class={style.mainColumn}>
|
||||
<td className={style.mainColumn}>
|
||||
<EditableText
|
||||
render={(value) => (<span>{value}</span>)}
|
||||
onChange={onTaskLabelChange.bind(null, t.id)}
|
||||
@ -118,7 +117,7 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
{
|
||||
isPrint ?
|
||||
<span>{t.estimations.optimistic}</span> :
|
||||
<input class="input" type="number" value={t.estimations.optimistic}
|
||||
<input className="input" type="number" value={t.estimations.optimistic}
|
||||
min={0}
|
||||
onChange={onOptimisticChange.bind(null, t.id)} />
|
||||
}
|
||||
@ -127,7 +126,7 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
{
|
||||
isPrint ?
|
||||
<span>{t.estimations.likely}</span> :
|
||||
<input class="input" type="number" value={t.estimations.likely}
|
||||
<input className="input" type="number" value={t.estimations.likely}
|
||||
min={0}
|
||||
onChange={onLikelyChange.bind(null, t.id)} />
|
||||
}
|
||||
@ -136,7 +135,7 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
{
|
||||
isPrint ?
|
||||
<span>{t.estimations.pessimistic}</span> :
|
||||
<input class="input" type="number" value={t.estimations.pessimistic}
|
||||
<input className="input" type="number" value={t.estimations.pessimistic}
|
||||
min={0}
|
||||
onChange={onPessimisticChange.bind(null, t.id)} />
|
||||
}
|
||||
@ -148,23 +147,23 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
{
|
||||
Object.keys(project.tasks).length === 0 ?
|
||||
<tr>
|
||||
<td class={`${style.noBorder} noPrint`}></td>
|
||||
<td class={style.noTasks} colSpan={5}>Aucune tâche pour l'instant.</td>
|
||||
<td className={`${style.noBorder} noPrint`}></td>
|
||||
<td className={style.noTasks} colSpan={5}>Aucune tâche pour l'instant.</td>
|
||||
</tr> :
|
||||
null
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td class={`${style.noBorder} noPrint`}></td>
|
||||
<td colSpan={2} class={isPrint ? style.noBorder : ''}>
|
||||
<div class="field has-addons noPrint">
|
||||
<p class="control is-expanded">
|
||||
<input class="input" type="text" placeholder="Nouvelle tâche"
|
||||
<td className={`${style.noBorder} noPrint`}></td>
|
||||
<td colSpan={2} className={isPrint ? style.noBorder : ''}>
|
||||
<div className="field has-addons noPrint">
|
||||
<p className="control is-expanded">
|
||||
<input className="input" type="text" placeholder="Nouvelle tâche"
|
||||
value={task.label} onChange={onNewTaskLabelChange} />
|
||||
</p>
|
||||
<p class="control">
|
||||
<span class="select">
|
||||
<p className="control">
|
||||
<span className="select">
|
||||
<select onChange={onNewTaskCategoryChange} value={task.category}>
|
||||
{
|
||||
Object.values(project.params.taskCategories).map(tc => {
|
||||
@ -176,8 +175,8 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-primary" onClick={onAddTaskClick}>
|
||||
<p className="control">
|
||||
<a className="button is-primary" onClick={onAddTaskClick}>
|
||||
Ajouter
|
||||
</a>
|
||||
</p>
|
||||
@ -186,7 +185,7 @@ const TaskTable: FunctionalComponent<TaskTableProps> = ({ project, onTaskAdd, on
|
||||
<th colSpan={3}>Total</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan={isPrint ? 2 : 3} class={style.noBorder}></td>
|
||||
<td colSpan={isPrint ? 2 : 3} className={style.noBorder}></td>
|
||||
<td>{totals.optimistic} <ProjectTimeUnit project={project} /></td>
|
||||
<td>{totals.likely} <ProjectTimeUnit project={project} /></td>
|
||||
<td>{totals.pessimistic} <ProjectTimeUnit project={project} /></td>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FunctionalComponent, h, Fragment } from "preact";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Project } from "../../models/project";
|
||||
import { useProjectEstimations, Estimation } from "../../hooks/use-project-estimations";
|
||||
import EstimationRange from "../../components/estimation-range";
|
||||
@ -7,38 +7,38 @@ export interface TimePreviewProps {
|
||||
project: Project
|
||||
}
|
||||
|
||||
const TimePreview: FunctionalComponent<TimePreviewProps> = ({ project }) => {
|
||||
const TimePreview: FunctionComponent<TimePreviewProps> = ({ project }) => {
|
||||
const estimations = useProjectEstimations(project);
|
||||
return (
|
||||
<div class="table-container">
|
||||
<table class="table is-bordered is-striped is-fullwidth">
|
||||
<div className="table-container">
|
||||
<table className="table is-bordered is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2}>Prévisionnel temps</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="is-narrow">Confiance</th>
|
||||
<th className="is-narrow">Confiance</th>
|
||||
<th>Estimation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="is-narrow">>= 99.7%</td>
|
||||
<td className="is-narrow">>= 99.7%</td>
|
||||
<td><EstimationRange project={project} estimation={estimations.p99} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="is-narrow">>= 90%</td>
|
||||
<td className="is-narrow">>= 90%</td>
|
||||
<td><EstimationRange project={project} estimation={estimations.p90} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="is-narrow">>= 68%</td>
|
||||
<td className="is-narrow">>= 68%</td>
|
||||
<td><EstimationRange project={project} estimation={estimations.p68} /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="noPrint">
|
||||
<tfoot className="noPrint">
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<a class="is-small is-pulled-right" href="https://en.wikipedia.org/wiki/Three-point_estimation" target="_blank">❓ Estimation à 3 points</a>
|
||||
<a className="is-small is-pulled-right" href="https://en.wikipedia.org/wiki/Three-point_estimation" target="_blank">❓ Estimation à 3 points</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useState } from "preact/hooks/src";
|
||||
import { ProjectID } from "../models/project";
|
||||
|
||||
export const ProjectStorageKeyPrefix = "project-";
|
||||
|
@ -6,7 +6,6 @@
|
||||
"moduleResolution": "node",
|
||||
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
|
Loading…
Reference in New Issue
Block a user