mirror of
https://github.com/bakhirev/assayo.git
synced 2025-09-04 03:29:45 +00:00
update
This commit is contained in:
parent
5d890b4848
commit
72d3c59f30
18 changed files with 250 additions and 145 deletions
|
@ -5,23 +5,24 @@ import Banner from 'ts/components/Banner';
|
||||||
import style from '../index.module.scss';
|
import style from '../index.module.scss';
|
||||||
|
|
||||||
interface ICardWithBannerProps {
|
interface ICardWithBannerProps {
|
||||||
long?: boolean;
|
size?: 's' | 'm' | 'l';
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardWithBanner({
|
function CardWithBanner({ size }: ICardWithBannerProps): React.ReactElement | null {
|
||||||
long = false,
|
const className = [
|
||||||
}: ICardWithBannerProps): React.ReactElement | null {
|
style.card_with_icon,
|
||||||
const className = long
|
style.card_with_icon_banner,
|
||||||
? style.card_with_icon_long
|
];
|
||||||
: style.card_with_icon;
|
if (size === 's') className.push(style.card_with_icon_small);
|
||||||
|
if (size === 'l') className.push(style.card_with_icon_long);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Banner className={`${className} ${style.card_with_icon_banner}`} />
|
<Banner className={className.join(' ')} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CardWithBanner.defaultProps = {
|
CardWithBanner.defaultProps = {
|
||||||
long: false,
|
size: 'm',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CardWithBanner;
|
export default CardWithBanner;
|
||||||
|
|
|
@ -15,6 +15,7 @@ function Scoring({
|
||||||
total,
|
total,
|
||||||
}: IScoringProps): React.ReactElement | null {
|
}: IScoringProps): React.ReactElement | null {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
@import 'src/styles/variables';
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
.card_with_icon,
|
.card_with_icon {
|
||||||
.card_with_icon_long {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: calc(50% - 12px);
|
width: calc(50% - 12px);
|
||||||
min-height: 270px;
|
min-height: 270px;
|
||||||
margin: 0 24px 24px 0;
|
margin: 0 var(--space-xxl) var(--space-xxl) 0;
|
||||||
padding: 16px;
|
padding: var(--space-l);
|
||||||
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -35,10 +34,13 @@
|
||||||
&_value {
|
&_value {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 0 4px 0;
|
margin: 0 0 var(--space-xxs) 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
color: var(--color-11);
|
color: var(--color-11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,19 +48,22 @@
|
||||||
&_description,
|
&_description,
|
||||||
&_scoring {
|
&_scoring {
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
color: var(--color-black);
|
color: var(--color-black);
|
||||||
}
|
}
|
||||||
|
|
||||||
&_title {
|
&_title {
|
||||||
font-size: var(--font-m);
|
font-size: var(--font-m);
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
margin: 0 0 4px 0;
|
margin: 0 0 var(--space-xxs) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&_description,
|
&_description,
|
||||||
|
@ -68,12 +73,6 @@
|
||||||
color: var(--color-grey);
|
color: var(--color-grey);
|
||||||
}
|
}
|
||||||
|
|
||||||
&_banner {
|
|
||||||
font-size: 32px;
|
|
||||||
padding: 0;
|
|
||||||
line-height: 270px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_scoring {
|
&_scoring {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -11px;
|
bottom: -11px;
|
||||||
|
@ -82,6 +81,7 @@
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: var(--space-xxxs) var(--space-xs);
|
padding: var(--space-xxxs) var(--space-xs);
|
||||||
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
@ -89,11 +89,31 @@
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
background-color: var(--color-white);
|
background-color: var(--color-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&_small {
|
||||||
|
min-height: auto;
|
||||||
|
padding: var(--space-l) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_long {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 0 var(--space-xxl) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_banner {
|
||||||
|
font-size: 32px;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 270px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card_with_icon_long {
|
.card_with_icon_small {
|
||||||
width: 100%;
|
.card_with_icon_value {
|
||||||
margin: 0 0 24px 0;
|
font-size: var(--font-m);
|
||||||
|
font-weight: 100;
|
||||||
|
margin-bottom: var(--space-m);
|
||||||
|
color: var(--color-button-2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card_with_icon:nth-child(2n+2) {
|
.card_with_icon:nth-child(2n+2) {
|
||||||
|
@ -101,10 +121,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.card_with_icon,
|
.card_with_icon {
|
||||||
.card_with_icon_long {
|
|
||||||
min-height: 220px;
|
min-height: 220px;
|
||||||
padding: 16px 0;
|
padding: var(--space-l) 0;
|
||||||
|
|
||||||
&_title {
|
&_title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -117,8 +136,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 650px) {
|
@media (max-width: 650px) {
|
||||||
.card_with_icon,
|
.card_with_icon {
|
||||||
.card_with_icon_long {
|
|
||||||
min-height: 190px;
|
min-height: 190px;
|
||||||
padding: 32px 0;
|
padding: 32px 0;
|
||||||
|
|
||||||
|
@ -139,10 +157,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.card_with_icon,
|
.card_with_icon {
|
||||||
.card_with_icon_long {
|
|
||||||
min-height: 220px;
|
min-height: 220px;
|
||||||
padding: 16px 0;
|
padding: var(--space-l) 0;
|
||||||
|
|
||||||
&_icon {
|
&_icon {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
|
@ -155,7 +172,7 @@
|
||||||
|
|
||||||
&_title {
|
&_title {
|
||||||
font-size: var(--font-s);
|
font-size: var(--font-s);
|
||||||
margin: 0 0 8px 0;
|
margin: 0 0 var(--space-s) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&_description {
|
&_description {
|
||||||
|
|
|
@ -10,9 +10,8 @@ interface ICardWithIconProps {
|
||||||
description?: string;
|
description?: string;
|
||||||
value: number | string | null;
|
value: number | string | null;
|
||||||
suffix?: string;
|
suffix?: string;
|
||||||
color?: string;
|
|
||||||
icon?: string;
|
icon?: string;
|
||||||
long?: boolean;
|
size?: 's' | 'm' | 'l';
|
||||||
scoring?: IScoringProps;
|
scoring?: IScoringProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,43 +20,47 @@ function CardWithIcon({
|
||||||
description,
|
description,
|
||||||
value,
|
value,
|
||||||
suffix,
|
suffix,
|
||||||
color,
|
|
||||||
icon,
|
icon,
|
||||||
long = false,
|
size,
|
||||||
scoring,
|
scoring,
|
||||||
}: ICardWithIconProps): React.ReactElement | null {
|
}: ICardWithIconProps): React.ReactElement | null {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!value && value !== 0) return null;
|
if (!value && value !== 0) return null;
|
||||||
|
|
||||||
|
const className = [style.card_with_icon];
|
||||||
|
if (size === 's') className.push(style.card_with_icon_small);
|
||||||
|
if (size === 'l') className.push(style.card_with_icon_long);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<figure className={long
|
<figure className={className.join(' ')}>
|
||||||
? style.card_with_icon_long
|
|
||||||
: style.card_with_icon}>
|
|
||||||
{icon && (
|
{icon && (
|
||||||
<img
|
<img
|
||||||
className={style.card_with_icon_icon}
|
className={style.card_with_icon_icon}
|
||||||
src={icon}
|
src={icon}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<p
|
|
||||||
className={style.card_with_icon_value}
|
<p className={style.card_with_icon_value}>
|
||||||
style={{ color: color || '' }}
|
|
||||||
>
|
|
||||||
{value}
|
{value}
|
||||||
{suffix || ''}
|
{suffix || ''}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h4 className={style.card_with_icon_title}>
|
<h4 className={style.card_with_icon_title}>
|
||||||
{t(title || '')}
|
{t(title || '')}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<figcaption className={style.card_with_icon_description}>
|
<figcaption className={style.card_with_icon_description}>
|
||||||
{t(description || '')}
|
{t(description || '')}
|
||||||
</figcaption>
|
</figcaption>
|
||||||
<Scoring
|
|
||||||
title={scoring?.title}
|
{scoring ? (
|
||||||
value={scoring?.value}
|
<Scoring
|
||||||
total={scoring?.total}
|
title={scoring?.title}
|
||||||
/>
|
value={scoring?.value}
|
||||||
|
total={scoring?.total}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</figure>
|
</figure>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -65,9 +68,8 @@ function CardWithIcon({
|
||||||
CardWithIcon.defaultProps = {
|
CardWithIcon.defaultProps = {
|
||||||
description: '',
|
description: '',
|
||||||
suffix: '',
|
suffix: '',
|
||||||
color: undefined,
|
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
long: false,
|
size: 'm',
|
||||||
scoring: undefined,
|
scoring: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { observer } from 'mobx-react-lite';
|
||||||
|
|
||||||
import Logo from 'ts/pages/PageWrapper/components/sidebar/Logo';
|
import Logo from 'ts/pages/PageWrapper/components/sidebar/Logo';
|
||||||
import globalScroll from 'ts/helpers/globalScroll';
|
|
||||||
|
|
||||||
|
import splashScreenStore from './store';
|
||||||
import style from './index.module.scss';
|
import style from './index.module.scss';
|
||||||
import progress from './progress.module.scss';
|
import progress from './progress.module.scss';
|
||||||
|
|
||||||
function SplashScreen(): React.ReactElement | null {
|
const SplashScreen = observer((): React.ReactElement | null => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
globalScroll.off(5400);
|
if (!splashScreenStore.isOpen) return;
|
||||||
}, []);
|
setTimeout(() => {
|
||||||
|
splashScreenStore.hide();
|
||||||
|
}, 5400);
|
||||||
|
}, [splashScreenStore.isOpen]);
|
||||||
|
|
||||||
|
if (!splashScreenStore.isOpen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.splash_screen}>
|
<div className={style.splash_screen}>
|
||||||
|
@ -20,6 +25,6 @@ function SplashScreen(): React.ReactElement | null {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default SplashScreen;
|
export default SplashScreen;
|
||||||
|
|
27
src/ts/components/SplashScreen/store/index.ts
Normal file
27
src/ts/components/SplashScreen/store/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { observable, action, makeObservable } from 'mobx';
|
||||||
|
import globalScroll from 'ts/helpers/globalScroll';
|
||||||
|
|
||||||
|
class SplashScreenStore {
|
||||||
|
isOpen: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeObservable(this, {
|
||||||
|
isOpen: observable,
|
||||||
|
show: action,
|
||||||
|
hide: action,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.isOpen = true;
|
||||||
|
globalScroll.off(5400);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.isOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const splashScreen = new SplashScreenStore();
|
||||||
|
|
||||||
|
export default splashScreen;
|
|
@ -26,16 +26,20 @@ export default class FileBuilderLineStat {
|
||||||
file.removedLines += fileChange.removedLines;
|
file.removedLines += fileChange.removedLines;
|
||||||
file.changedLines += fileChange.changedLines;
|
file.changedLines += fileChange.changedLines;
|
||||||
|
|
||||||
file.addedLinesByAuthor[commit.author] = file.addedLinesByAuthor[commit.author]
|
// TODO: performance
|
||||||
? (file.addedLinesByAuthor[commit.author] + fileChange.addedLines)
|
const addedLinesByAuthor = file.addedLinesByAuthor[commit.author];
|
||||||
|
file.addedLinesByAuthor[commit.author] = addedLinesByAuthor
|
||||||
|
? (addedLinesByAuthor + fileChange.addedLines)
|
||||||
: fileChange.addedLines;
|
: fileChange.addedLines;
|
||||||
|
|
||||||
file.removedLinesByAuthor[commit.author] = file.removedLinesByAuthor[commit.author]
|
const removedLinesByAuthor = file.removedLinesByAuthor[commit.author];
|
||||||
? (file.removedLinesByAuthor[commit.author] + fileChange.removedLines)
|
file.removedLinesByAuthor[commit.author] = removedLinesByAuthor
|
||||||
|
? (removedLinesByAuthor + fileChange.removedLines)
|
||||||
: fileChange.removedLines;
|
: fileChange.removedLines;
|
||||||
|
|
||||||
file.changedLinesByAuthor[commit.author] = file.changedLinesByAuthor[commit.author]
|
const changedLinesByAuthor = file.changedLinesByAuthor[commit.author];
|
||||||
? (file.changedLinesByAuthor[commit.author] + fileChange.changedLines)
|
file.changedLinesByAuthor[commit.author] = changedLinesByAuthor
|
||||||
|
? (changedLinesByAuthor + fileChange.changedLines)
|
||||||
: fileChange.changedLines;
|
: fileChange.changedLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ const MASTER_BRANCH = {
|
||||||
|
|
||||||
let prevDate = new Date();
|
let prevDate = new Date();
|
||||||
|
|
||||||
|
let refTimestampTime = {};
|
||||||
|
|
||||||
export default function getCommitInfo(
|
export default function getCommitInfo(
|
||||||
logString: string,
|
logString: string,
|
||||||
refEmailAuthor: IHashMap<string>,
|
refEmailAuthor: IHashMap<string>,
|
||||||
|
@ -18,7 +20,7 @@ export default function getCommitInfo(
|
||||||
// "2021-02-09T12:59:17+03:00>Frolov Ivan>frolov@mail.ru>profile"
|
// "2021-02-09T12:59:17+03:00>Frolov Ivan>frolov@mail.ru>profile"
|
||||||
const parts = logString.split('>');
|
const parts = logString.split('>');
|
||||||
|
|
||||||
const sourceDate = parts.shift() || '';
|
const sourceDate = parts[0] || '';
|
||||||
let date = new Date(sourceDate);
|
let date = new Date(sourceDate);
|
||||||
if (isNaN(date.getDay())) {
|
if (isNaN(date.getDay())) {
|
||||||
console.log(`PARSE ERROR: Date parse error for: "${logString}"`);
|
console.log(`PARSE ERROR: Date parse error for: "${logString}"`);
|
||||||
|
@ -26,11 +28,14 @@ export default function getCommitInfo(
|
||||||
}
|
}
|
||||||
prevDate = date;
|
prevDate = date;
|
||||||
const day = date.getDay() - 1;
|
const day = date.getDay() - 1;
|
||||||
const timestamp = sourceDate.split('T')[0];
|
const timestamp = sourceDate.substring(0, 10); // split('T')[0];
|
||||||
|
if (!refTimestampTime[timestamp]) {
|
||||||
|
refTimestampTime[timestamp] = (new Date(timestamp)).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
let author = parts.shift()?.replace(/[._]/gm, ' ') || '';
|
let author = parts[1]?.replace(/[._]/gm, ' ') || '';
|
||||||
let email = parts.shift() || '';
|
let email = parts[2] || '';
|
||||||
if (!(/@/gim).test(email)) email = '';
|
if (email.indexOf('@') === -1) email = '';
|
||||||
|
|
||||||
const authorID = author.replace(/\s|\t/gm, '');
|
const authorID = author.replace(/\s|\t/gm, '');
|
||||||
if (authorID && refEmailAuthor[authorID] && refEmailAuthor[authorID] !== author) {
|
if (authorID && refEmailAuthor[authorID] && refEmailAuthor[authorID] !== author) {
|
||||||
|
@ -52,7 +57,8 @@ export default function getCommitInfo(
|
||||||
refEmailAuthor[author] = email;
|
refEmailAuthor[author] = email;
|
||||||
refEmailAuthor[authorID] = author;
|
refEmailAuthor[authorID] = author;
|
||||||
|
|
||||||
const message = parts.join('>');
|
// performance
|
||||||
|
const message = logString.substring(parts[0]?.length + parts[1]?.length + parts[2]?.length + 3);
|
||||||
|
|
||||||
const commonInfo: any = {
|
const commonInfo: any = {
|
||||||
date: sourceDate,
|
date: sourceDate,
|
||||||
|
@ -64,7 +70,7 @@ export default function getCommitInfo(
|
||||||
year: date.getUTCFullYear(),
|
year: date.getUTCFullYear(),
|
||||||
week: 0,
|
week: 0,
|
||||||
timestamp,
|
timestamp,
|
||||||
milliseconds: (new Date(timestamp)).getTime(),
|
milliseconds: refTimestampTime[timestamp],
|
||||||
|
|
||||||
author,
|
author,
|
||||||
email,
|
email,
|
||||||
|
@ -99,7 +105,7 @@ export default function getCommitInfo(
|
||||||
task = getTask(branch);
|
task = getTask(branch);
|
||||||
} else if (isBitbucketPR) {
|
} else if (isBitbucketPR) {
|
||||||
commitType = COMMIT_TYPE.PR_BITBUCKET;
|
commitType = COMMIT_TYPE.PR_BITBUCKET;
|
||||||
const messageParts = message.substring(14, Infinity).split(':');
|
const messageParts = message.substring(14).split(':');
|
||||||
prId = messageParts.shift();
|
prId = messageParts.shift();
|
||||||
task = getTask(messageParts.join(':'));
|
task = getTask(messageParts.join(':'));
|
||||||
} else if (isAutoMerge) {
|
} else if (isAutoMerge) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ function getFilePath(path: string): string[] {
|
||||||
return [oldPath, newPath];
|
return [oldPath, newPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
// "38 9 src/app.css" -> [38, 9, 9, 'src/app.css']
|
// "38 9 src/app.css" -> [38, 9, 'src/app.css']
|
||||||
export function getNumStatInfo(message: string) {
|
export function getNumStatInfo(message: string) {
|
||||||
let [addedRaw, removedRaw, path] = message.split('\t');
|
let [addedRaw, removedRaw, path] = message.split('\t');
|
||||||
|
|
||||||
|
@ -50,16 +50,17 @@ export function getNumStatInfo(message: string) {
|
||||||
}
|
}
|
||||||
// ":000000 100644 000000000 fc44b0a37 A public/logo192.png" -> ['A', 'public/logo192.png']
|
// ":000000 100644 000000000 fc44b0a37 A public/logo192.png" -> ['A', 'public/logo192.png']
|
||||||
export function getRawInfo(message: string) {
|
export function getRawInfo(message: string) {
|
||||||
const action = message[35];
|
return {
|
||||||
const path = message.split('\t')[1];
|
action:message[35],
|
||||||
return { path, action };
|
path: message.substring(37),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// "src/AppGit.css" -> { id: 'src/appgit.css', path: 'src/AppGit.css' }
|
// "src/AppGit.css" -> { id: 'src/appgit.css', path: 'src/AppGit.css' }
|
||||||
export function getInfoFromPath(path: string): IFileChange {
|
export function getInfoFromPath(path: string): IFileChange {
|
||||||
const [oldPath, newPath] = getFilePath(path);
|
const [oldPath, newPath] = getFilePath(path);
|
||||||
|
|
||||||
const id = oldPath.toLowerCase();
|
const id = oldPath.toLowerCase(); // TODO: performance
|
||||||
const newId = newPath?.toLowerCase();
|
const newId = newPath?.toLowerCase();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -47,7 +47,7 @@ function getMenu(navigate: Function): any[] {
|
||||||
confirm.open({
|
confirm.open({
|
||||||
title: 'Вы уверены что хотите выйти?',
|
title: 'Вы уверены что хотите выйти?',
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
dataGripStore.setCommits([]);
|
dataGripStore.asyncSetCommits([]);
|
||||||
navigate('/');
|
navigate('/');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -82,7 +82,7 @@ const Money = observer(({ user }: IPersonCommonProps): React.ReactElement => {
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
size="l"
|
||||||
value={taskNumber
|
value={taskNumber
|
||||||
? getShortMoney(statistic.moneyWorked / taskNumber, 0)
|
? getShortMoney(statistic.moneyWorked / taskNumber, 0)
|
||||||
: null}
|
: null}
|
||||||
|
@ -91,7 +91,7 @@ const Money = observer(({ user }: IPersonCommonProps): React.ReactElement => {
|
||||||
description="page.person.money.tasks.description"
|
description="page.person.money.tasks.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
size="l"
|
||||||
value={taskNumber
|
value={taskNumber
|
||||||
? getShortMoney(statistic.moneyWorked / statistic.commits, 0)
|
? getShortMoney(statistic.moneyWorked / statistic.commits, 0)
|
||||||
: null}
|
: null}
|
||||||
|
|
|
@ -65,14 +65,14 @@ const Speed = observer(({ user }: IPersonCommonProps): React.ReactElement => {
|
||||||
<Title title="page.person.speed.max"/>
|
<Title title="page.person.speed.max"/>
|
||||||
<div>
|
<div>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
size="l"
|
||||||
value={byTimestamp.tasksByTimestampCounter.max}
|
value={byTimestamp.tasksByTimestampCounter.max}
|
||||||
icon="./assets/cards/tasks.png"
|
icon="./assets/cards/tasks.png"
|
||||||
title="page.person.speed.tasks.title"
|
title="page.person.speed.tasks.title"
|
||||||
description="page.person.speed.tasks.description"
|
description="page.person.speed.tasks.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
size="l"
|
||||||
value={byTimestamp.commitsByTimestampCounter.max}
|
value={byTimestamp.commitsByTimestampCounter.max}
|
||||||
icon="./assets/cards/commits.png"
|
icon="./assets/cards/commits.png"
|
||||||
title="page.person.speed.maxCommits.title"
|
title="page.person.speed.maxCommits.title"
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import achievementByAuthor from 'ts/helpers/achievement/byCompetition';
|
import achievementByAuthor from 'ts/helpers/achievement/byCompetition';
|
||||||
import ACHIEVEMENT_TYPE from 'ts/helpers/achievement/constants/type';
|
import ACHIEVEMENT_TYPE from 'ts/helpers/achievement/constants/type';
|
||||||
|
import { getDate } from 'ts/helpers/formatter';
|
||||||
|
|
||||||
import CardWithIcon from 'ts/components/CardWithIcon';
|
import CardWithIcon from 'ts/components/CardWithIcon';
|
||||||
import CardWithBanner from 'ts/components/CardWithIcon/components/Banner';
|
import CardWithBanner from 'ts/components/CardWithIcon/components/Banner';
|
||||||
|
@ -48,6 +49,20 @@ const Total = observer(({ user }: IPersonCommonProps): React.ReactElement => {
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title="page.person.total.title"/>
|
<Title title="page.person.total.title"/>
|
||||||
<div>
|
<div>
|
||||||
|
{false && (
|
||||||
|
<>
|
||||||
|
<CardWithIcon
|
||||||
|
size="s"
|
||||||
|
value={getDate(statistic.firstCommit.timestamp)}
|
||||||
|
title="page.team.tasks.from"
|
||||||
|
/>
|
||||||
|
<CardWithIcon
|
||||||
|
size="s"
|
||||||
|
value={getDate(statistic.lastCommit.timestamp)}
|
||||||
|
title="page.team.tasks.to"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={statistic.daysWorked}
|
value={statistic.daysWorked}
|
||||||
icon="./assets/cards/work_days.png"
|
icon="./assets/cards/work_days.png"
|
||||||
|
@ -88,7 +103,7 @@ const Total = observer(({ user }: IPersonCommonProps): React.ReactElement => {
|
||||||
total: scoringTotal.commits,
|
total: scoringTotal.commits,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CardWithBanner long />
|
<CardWithBanner size="l" />
|
||||||
</div>
|
</div>
|
||||||
{false && <Title title="page.person.character.title"/>}
|
{false && <Title title="page.person.character.title"/>}
|
||||||
{false && <Character user={statistic} />}
|
{false && <Character user={statistic} />}
|
||||||
|
|
|
@ -54,7 +54,7 @@ const Total = observer((): React.ReactElement => {
|
||||||
description="page.team.total.employment.description"
|
description="page.team.total.employment.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
size="l"
|
||||||
value={workSpeed}
|
value={workSpeed}
|
||||||
icon="./assets/cards/tasks_month.png"
|
icon="./assets/cards/tasks_month.png"
|
||||||
title="page.team.total.workSpeed.title"
|
title="page.team.total.workSpeed.title"
|
||||||
|
@ -99,7 +99,7 @@ const Total = observer((): React.ReactElement => {
|
||||||
description="page.team.total.weekendPayment.description"
|
description="page.team.total.weekendPayment.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
size="l"
|
||||||
value={getShortMoney(moneySpeed)}
|
value={getShortMoney(moneySpeed)}
|
||||||
icon="./assets/cards/money_month.png"
|
icon="./assets/cards/money_month.png"
|
||||||
title="page.team.total.moneySpeed.title"
|
title="page.team.total.moneySpeed.title"
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
|
|
||||||
import Console from 'ts/components/Console';
|
import Console from 'ts/components/Console';
|
||||||
import Description from 'ts/components/Description';
|
import Description from 'ts/components/Description';
|
||||||
|
import splashScreenStore from 'ts/components/SplashScreen/store';
|
||||||
import {
|
import {
|
||||||
getStringFromFileList,
|
getStringFromFileList,
|
||||||
getStringsForParser,
|
getStringsForParser,
|
||||||
|
@ -60,7 +61,8 @@ function Welcome() {
|
||||||
const files = Array.from(event.target.files);
|
const files = Array.from(event.target.files);
|
||||||
const text = await getStringFromFileList(files);
|
const text = await getStringFromFileList(files);
|
||||||
const report = getStringsForParser(text);
|
const report = getStringsForParser(text);
|
||||||
dataGripStore.setCommits(report);
|
splashScreenStore.show();
|
||||||
|
dataGripStore.asyncSetCommits(report);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Route, Routes } from 'react-router-dom';
|
import { Route, Routes } from 'react-router-dom';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
|
|
||||||
import dataGripStore, { DataParseStatusEnum } from 'ts/store/DataGrip';
|
import dataGripStore from 'ts/store/DataGrip';
|
||||||
|
import viewNameStore, { ViewNameEnum } from 'ts/store/ViewName';
|
||||||
import DropZone from 'ts/components/DropZone';
|
import DropZone from 'ts/components/DropZone';
|
||||||
import Sponsor from 'ts/components/Sponsor';
|
import Sponsor from 'ts/components/Sponsor';
|
||||||
import SplashScreen from 'ts/components/SplashScreen';
|
import SplashScreen from 'ts/components/SplashScreen';
|
||||||
|
@ -16,11 +17,7 @@ import Welcome from './Welcome/index';
|
||||||
import Settings from './Settings/index';
|
import Settings from './Settings/index';
|
||||||
import DebugPage from './Debug/index';
|
import DebugPage from './Debug/index';
|
||||||
|
|
||||||
interface IViewWithChartsProps {
|
function ViewWithCharts() {
|
||||||
showSplashScreen: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ViewWithCharts({ showSplashScreen }: IViewWithChartsProps) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Sponsor />
|
<Sponsor />
|
||||||
|
@ -75,7 +72,6 @@ function ViewWithCharts({ showSplashScreen }: IViewWithChartsProps) {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
{showSplashScreen && <SplashScreen />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -94,36 +90,38 @@ function ViewWithWelcome() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Main = observer(() => {
|
const Main = observer(() => {
|
||||||
const [showSplashScreen, setShowSplashScreen] = useState<boolean>(true);
|
const view = viewNameStore.view;
|
||||||
const status = dataGripStore.status;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
dataGripStore.setCommits(window?.report || []);
|
const list = window?.report || [];
|
||||||
|
if (list?.length) {
|
||||||
|
dataGripStore.asyncSetCommits(list);
|
||||||
|
} else {
|
||||||
|
viewNameStore.toggle(ViewNameEnum.WELCOME);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status !== DataParseStatusEnum.DONE || window.location.hash) return;
|
if (view !== ViewNameEnum.INFO || window.location.hash) return;
|
||||||
window.location.hash = '#/team/total';
|
window.location.hash = '#/team/total';
|
||||||
}, [status]);
|
}, [view]);
|
||||||
|
|
||||||
if (status === DataParseStatusEnum.PROCESSING) return null;
|
if (view === ViewNameEnum.EMPTY) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{status === DataParseStatusEnum.DONE && (
|
{view === ViewNameEnum.WELCOME && (
|
||||||
<ViewWithCharts showSplashScreen={showSplashScreen} />
|
|
||||||
)}
|
|
||||||
{status === DataParseStatusEnum.WAITING && (
|
|
||||||
<ViewWithWelcome />
|
<ViewWithWelcome />
|
||||||
)}
|
)}
|
||||||
|
{view === ViewNameEnum.INFO && (
|
||||||
|
<ViewWithCharts />
|
||||||
|
)}
|
||||||
|
<SplashScreen />
|
||||||
<DropZone
|
<DropZone
|
||||||
onChange={(type: string, data: any[]) => {
|
onChange={(type: string, data: any[]) => {
|
||||||
setShowSplashScreen(false);
|
if (type !== 'dump') return;
|
||||||
if (type === 'dump') dataGripStore.setCommits(data);
|
dataGripStore.asyncSetCommits(data);
|
||||||
setTimeout(() => {
|
|
||||||
setShowSplashScreen(true);
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { makeObservable, observable, action } from 'mobx';
|
import { action, makeObservable, observable } from 'mobx';
|
||||||
|
|
||||||
import ICommit, { ISystemCommit } from 'ts/interfaces/Commit';
|
import ICommit, { ISystemCommit } from 'ts/interfaces/Commit';
|
||||||
|
|
||||||
|
@ -9,27 +9,16 @@ import Parser from 'ts/helpers/Parser';
|
||||||
import getTitle from 'ts/helpers/Title';
|
import getTitle from 'ts/helpers/Title';
|
||||||
|
|
||||||
import { setDefaultValues } from 'ts/pages/Settings/helpers/getEmptySettings';
|
import { setDefaultValues } from 'ts/pages/Settings/helpers/getEmptySettings';
|
||||||
|
import splashScreenStore from 'ts/components/SplashScreen/store';
|
||||||
import { applicationHasCustom } from 'ts/helpers/RPC';
|
import { applicationHasCustom } from 'ts/helpers/RPC';
|
||||||
import Depersonalized from 'ts/helpers/Depersonalized';
|
import Depersonalized from 'ts/helpers/Depersonalized';
|
||||||
|
|
||||||
import filtersInHeaderStore from './FiltersInHeader';
|
import filtersInHeaderStore from './FiltersInHeader';
|
||||||
|
import viewNameStore, { ViewNameEnum } from './ViewName';
|
||||||
|
|
||||||
export enum DataParseStatusEnum {
|
const PROCESSING_DELAY = 300;
|
||||||
WAITING = 'waiting',
|
|
||||||
PROCESSING = 'processing',
|
|
||||||
DONE = 'done',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IDataGripStore {
|
class DataGripStore {
|
||||||
commits: ICommit[];
|
|
||||||
dataGrip: any;
|
|
||||||
fileGrip: any;
|
|
||||||
status: DataParseStatusEnum;
|
|
||||||
isDepersonalized: boolean;
|
|
||||||
setCommits: (log?: string[]) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
class DataGripStore implements IDataGripStore {
|
|
||||||
commits: any[] = [];
|
commits: any[] = [];
|
||||||
|
|
||||||
dataGrip: any = null;
|
dataGrip: any = null;
|
||||||
|
@ -40,55 +29,66 @@ class DataGripStore implements IDataGripStore {
|
||||||
|
|
||||||
isDepersonalized: boolean = false;
|
isDepersonalized: boolean = false;
|
||||||
|
|
||||||
status: DataParseStatusEnum = DataParseStatusEnum.PROCESSING;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
commits: observable,
|
|
||||||
dataGrip: observable,
|
dataGrip: observable,
|
||||||
|
fileGrip: observable,
|
||||||
hash: observable,
|
hash: observable,
|
||||||
isDepersonalized: observable,
|
isDepersonalized: observable,
|
||||||
status: observable,
|
asyncSetCommits: action,
|
||||||
setCommits: action,
|
processingStep01: action,
|
||||||
|
processingStep03: action,
|
||||||
depersonalized: action,
|
depersonalized: action,
|
||||||
updateStatistic: action,
|
updateStatistic: action,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setCommits(dump?: string[]) {
|
asyncSetCommits(dump?: string[]) {
|
||||||
|
if (!dump?.length) return;
|
||||||
|
splashScreenStore.show();
|
||||||
|
setTimeout(() => this.processingStep01(dump), PROCESSING_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
processingStep01(dump?: string[]) {
|
||||||
dataGrip.clear();
|
dataGrip.clear();
|
||||||
fileGrip.clear();
|
fileGrip.clear();
|
||||||
|
|
||||||
const commits = Parser(dump || []);
|
const commits = Parser(dump || []);
|
||||||
|
if (!commits.length) {
|
||||||
|
splashScreenStore.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => this.processingStep02(commits), PROCESSING_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
processingStep02(commits: (ICommit | ISystemCommit)[]) {
|
||||||
commits.sort((a, b) => a.milliseconds - b.milliseconds);
|
commits.sort((a, b) => a.milliseconds - b.milliseconds);
|
||||||
commits.forEach((commit: ICommit | ISystemCommit) => {
|
commits.forEach((commit: ICommit | ISystemCommit) => {
|
||||||
dataGrip.addCommit(commit);
|
dataGrip.addCommit(commit);
|
||||||
fileGrip.addCommit(commit);
|
fileGrip.addCommit(commit);
|
||||||
});
|
});
|
||||||
fileGrip.updateTotalInfo();
|
|
||||||
|
|
||||||
|
setTimeout(() => this.processingStep03(commits), PROCESSING_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
processingStep03(commits: (ICommit | ISystemCommit)[]) {
|
||||||
|
fileGrip.updateTotalInfo();
|
||||||
this.commits = commits;
|
this.commits = commits;
|
||||||
|
|
||||||
this.status = this.commits.length
|
filtersInHeaderStore.updateByCommits(
|
||||||
? DataParseStatusEnum.DONE
|
dataGrip.firstLastCommit.minData,
|
||||||
: DataParseStatusEnum.WAITING;
|
dataGrip.firstLastCommit.maxData,
|
||||||
|
);
|
||||||
|
setDefaultValues(dataGrip.firstLastCommit.minData, dataGrip.firstLastCommit.maxData);
|
||||||
|
|
||||||
if (this.status === DataParseStatusEnum.DONE) {
|
dataGrip.updateTotalInfo();
|
||||||
filtersInHeaderStore.updateByCommits(
|
achievements.updateByGrip(dataGrip, fileGrip);
|
||||||
dataGrip.firstLastCommit.minData,
|
|
||||||
dataGrip.firstLastCommit.maxData,
|
|
||||||
);
|
|
||||||
setDefaultValues(dataGrip.firstLastCommit.minData, dataGrip.firstLastCommit.maxData);
|
|
||||||
|
|
||||||
dataGrip.updateTotalInfo();
|
|
||||||
achievements.updateByGrip(dataGrip, fileGrip);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
viewNameStore.toggle(ViewNameEnum.INFO);
|
||||||
this.#updateRender();
|
this.#updateRender();
|
||||||
|
|
||||||
console.dir(this.dataGrip);
|
console.dir(this.dataGrip);
|
||||||
console.dir(this.fileGrip);
|
|
||||||
if (!applicationHasCustom.title) {
|
if (!applicationHasCustom.title) {
|
||||||
document.title = getTitle(this.dataGrip, this.fileGrip, this.commits);
|
document.title = getTitle(this.dataGrip, this.fileGrip, this.commits);
|
||||||
}
|
}
|
||||||
|
|
26
src/ts/store/ViewName.tsx
Normal file
26
src/ts/store/ViewName.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { observable, action, makeObservable } from 'mobx';
|
||||||
|
|
||||||
|
export enum ViewNameEnum {
|
||||||
|
EMPTY = 'empty',
|
||||||
|
WELCOME = 'welcome',
|
||||||
|
INFO = 'info',
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewNameStore {
|
||||||
|
view: ViewNameEnum = ViewNameEnum.EMPTY;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeObservable(this, {
|
||||||
|
view: observable,
|
||||||
|
toggle: action,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(view: ViewNameEnum) {
|
||||||
|
this.view = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewNameStore = new ViewNameStore();
|
||||||
|
|
||||||
|
export default viewNameStore;
|
Loading…
Add table
Reference in a new issue