JIRA-1234 feat(lang): test test test

This commit is contained in:
bakhirev 2023-10-13 15:17:21 +03:00
parent 3d4cb821ac
commit 9f77159b31
18 changed files with 77 additions and 257 deletions

View file

@ -1,5 +1,6 @@
import React, { ReactNode } from 'react'; import React, { ReactNode } from 'react';
import localization from 'ts/helpers/Localization';
import style from '../styles/index.module.scss'; import style from '../styles/index.module.scss';
export interface IUiKitWrapperProps { export interface IUiKitWrapperProps {
@ -25,22 +26,22 @@ function UiKitWrapper({
return ( return (
<div <div
className={`${style.wrapper} ${className || ''}`} className={`${style.wrapper} ${className || ''}`}
title={help} title={localization.get(help)}
> >
{title && ( {title && (
<h6 className={style.title}> <h6 className={style.title}>
{title} {localization.get(title)}
</h6> </h6>
)} )}
{description && ( {description && (
<p className={style.description}> <p className={style.description}>
{description} {localization.get(description)}
</p> </p>
)} )}
{children} {children}
{help && ( {help && (
<p className={style.help}> <p className={style.help}>
{example} {localization.get(example)}
</p> </p>
)} )}
{error && ( {error && (

View file

@ -28,6 +28,16 @@ localization.parse('ru', `
§ sidebar.person.changes: Все изменения § sidebar.person.changes: Все изменения
§ sidebar.person.words: Популярные слова § sidebar.person.words: Популярные слова
§ sidebar.person.settings: Настройки § sidebar.person.settings: Настройки
§ page.welcome.step1: Выполните команду в корне вашего проекта
§ page.welcome.step2: Перетащите файл log.txt на эту страницу
§ page.welcome.description1: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл
§ page.welcome.description2: в корне проекта, чтобы обьединить статистику по сотрудникам.
§ page.welcome.description: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл [.mailmap|https://git-scm.com/docs/gitmailmap] в корне проекта, чтобы обьединить статистику по сотрудникам.
§ page.welcome.warning1: Сервис *НЕ ХРАНИТ* и *НЕ ПЕРЕДАЁТ* ваши данные. Все расчёты выполняются локально в вашем браузере прямо на вашей машине.
§ page.welcome.warning2: Сервис *НЕ СОБИРАЕТ СТАТИСТИКУ* по проектам. Вы можете отключить интернет, проверить трафик и даже собрать локальный билд из [исходников|https://github.com/bakhirev/assayo].
§ page.team.author.title: Статистика по сотрудникам
§ page.team.author.description1: *Часть статитики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помошник» не считается*, т.к. это эпизодическая роль в проекте. Предпологаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы.
§ page.team.author.description2: *Сортировка по умолчанию* это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники).
§ page.team.author.types: Тип работ § page.team.author.types: Тип работ
§ page.team.author.commits: Коммитов § page.team.author.commits: Коммитов
§ page.team.author.commitsSmall: коммитов § page.team.author.commitsSmall: коммитов
@ -41,6 +51,9 @@ localization.parse('ru', `
§ page.team.author.moneyAll: Получил § page.team.author.moneyAll: Получил
§ page.team.author.moneyWorked: Отработал § page.team.author.moneyWorked: Отработал
§ page.team.author.moneyLosses: Переплата § page.team.author.moneyLosses: Переплата
§ page.team.hours.title: Распределение коммитов в течении каждого дня недели
§ page.team.month.title: Календарь работы по проекту
§ page.team.scope.title: Статистика по фичам
§ page.team.scope.scope: Фича § page.team.scope.scope: Фича
§ page.team.scope.days: Раб. дней § page.team.scope.days: Раб. дней
§ page.team.scope.authorsDays: Человеко-дней § page.team.scope.authorsDays: Человеко-дней
@ -50,13 +63,18 @@ localization.parse('ru', `
§ page.team.scope.types: Тип работ § page.team.scope.types: Тип работ
§ page.team.scope.authors: Персональный вклад § page.team.scope.authors: Персональный вклад
§ page.team.scope.cost: Стоимость § page.team.scope.cost: Стоимость
§ page.team.type.title: Статистика по типам задач
§ page.team.type.description: *Персональный вклад* считается по количеству коммитов, а не объему измененных строк или файлов. Поэтому следует так же смотреть раздел «Анализ файлов», чтобы оценить масштаб изменений.
§ page.team.type.type: Тип работы § page.team.type.type: Тип работы
§ page.team.type.tasks: Задач § page.team.type.tasks: Задач
§ page.team.type.tasksSmall: задач
§ page.team.type.days: Дней § page.team.type.days: Дней
§ page.team.type.daysSmall: дней
§ page.team.type.authorsDays: Человеко-дней § page.team.type.authorsDays: Человеко-дней
§ page.team.type.commits: Коммитов § page.team.type.commits: Коммитов
§ page.team.type.commitsSmall: коммитов
§ page.team.type.authors: Персональный вклад § page.team.type.authors: Персональный вклад
§ page.team.total.titleA: Объём работ
§ page.team.total.titleB: Стоимость
§ page.team.total.daysWorked.title: человеко-дней § page.team.total.daysWorked.title: человеко-дней
§ page.team.total.daysWorked.description: Учтены только дни, в которые делались коммиты § page.team.total.daysWorked.description: Учтены только дни, в которые делались коммиты
§ page.team.total.commits.title: коммитов § page.team.total.commits.title: коммитов
@ -77,12 +95,16 @@ localization.parse('ru', `
§ page.team.total.workSpeed.description: Средняя скорость работы команды при текущем составе сотрудников § page.team.total.workSpeed.description: Средняя скорость работы команды при текущем составе сотрудников
§ page.team.total.moneySpeed.title: в месяц § page.team.total.moneySpeed.title: в месяц
§ page.team.total.moneySpeed.description: Прогнозируемая сумма выплаты на зп при текущем составе сотрудников без учета налогов и сопутствующих затрат § page.team.total.moneySpeed.description: Прогнозируемая сумма выплаты на зп при текущем составе сотрудников без учета налогов и сопутствующих затрат
§ page.team.total.titleA: Объём работ § page.team.total.description1: *Человеко-дни* это работа одного сотрудника в течение одного рабочего дня. Например, за один календарный день, команда из трех сотрудников выдает объем работы в три человеко-дня.
§ page.team.total.titleB: Стоимость § page.team.total.description2: *Днями прогулов* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют.
§ page.team.tree.filters1: Пользователь § page.team.total.description3: Карточка *работает и уволилось* показывает фактический состав сотрудников, которые постоянно участвуют в работе. Кроме этого, есть «помощники» это сотрудники, как правило другой специализации, которые могут иногда делать коммиты в проект.
§ page.team.tree.filters2: и более § page.team.total.description4: *Переплатой* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют. Именно поэтому переплата + фактическая стоимость != общей. В общей стоимости заложена оплата выходных, государственных праздников и отпусков.
§ page.team.tree.filters3: коммитов в файле или папке § page.team.total.description5: *Работой на выходных* считается по коэфициенту х2 от оплаты обычного дня. Выше отображена именно переплата (х1), т.к. сам факт переработки в данном контексте не интересен. Мы не смотрим скорость сжигания бюджета. Мы смотрим переплату при увеличении скорости работы.
§ page.team.tree.percent: Процент перезаписи § page.team.tree.title: Дерево проекта с учётом выбранных фильтров
§ page.team.tree.filters.author: Сотрудник
§ page.team.tree.filters.commits: Количество коммитов
§ page.team.tree.filters.help: Минимальное количество коммитов, которое сделал сотрудник в файле
§ page.team.tree.filters.all: Все сотрудники
§ page.team.tree.add: Кто добавлял § page.team.tree.add: Кто добавлял
§ page.team.tree.change: Кто менял § page.team.tree.change: Кто менял
§ page.team.tree.remove: Кто удалял § page.team.tree.remove: Кто удалял

View file

@ -8,7 +8,6 @@ import SplashScreen from 'ts/components/SplashScreen';
import Confirm from 'ts/components/ModalWindow/Confirm'; import Confirm from 'ts/components/ModalWindow/Confirm';
import PageWrapper from '../../PageWrapper'; import PageWrapper from '../../PageWrapper';
// import Main from '../../Main/index';
import Team from '../../Team/index'; import Team from '../../Team/index';
import Person from '../../Person/index'; import Person from '../../Person/index';
import Welcome from '../../Welcome/index'; import Welcome from '../../Welcome/index';

View file

@ -1,48 +0,0 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import UiKitButton from 'ts/components/UiKit/components/Button';
import localization from 'ts/helpers/Localization';
import style from '../styles/card.module.scss';
interface ICardProps {
icon: string;
title: string;
description: string;
link: string;
}
function Card({
icon,
title,
description,
link,
}: ICardProps): React.ReactElement | null {
const navigate = useNavigate();
return (
<figure className={style.card}>
<h4 className={style.card_title}>
{localization.get(title)}
</h4>
<img
className={style.card_icon}
src={icon}
/>
<figcaption className={style.card_description}>
{localization.get(description)}
</figcaption>
<UiKitButton
className={style.card_button}
onClick={() => {
navigate(link);
}}
>
Перейти в отчёт
</UiKitButton>
</figure>
);
}
export default Card;

View file

@ -1,31 +0,0 @@
import React from 'react';
import Card from './components/Card';
import style from './styles/index.module.scss';
function Main() {
return (
<section className={style.main}>
<h2 className={style.main_title}>
Выберите раздел аналити
</h2>
<div className={style.main_cards}>
<Card
icon="./assets/cards/money_lazy.png"
title="Команда"
description="Собраны метрики работы команды в целом, сумарные финансовые показатели, рекомендации для менеджера проекта."
link="/team/total"
/>
<Card
icon="./assets/cards/money_lazy.png"
title="Сотрудник"
description="Данные по каждому сотруднику отдельно. Личные достижения, характеристики, показатели работоспособности."
link="/person/total/0"
/>
</div>
</section>
);
}
export default Main;

View file

@ -1,86 +0,0 @@
@import '../../../../styles/variables';
.card {
display: inline-block;
width: 300px;
min-height: 270px;
margin: 0 24px 24px 0;
padding: 16px;
vertical-align: top;
box-sizing: border-box;
border-radius: 8px;
border: 1px solid var(--color-border);
background-color: #FFFFFF;
&_icon {
display: block;
width: auto;
height: 90px;
margin: 16px auto;
box-sizing: border-box;
vertical-align: top;
}
&_title,
&_description {
display: block;
margin: 0 auto;
padding: 0;
line-height: 1.3;
text-align: center;
text-decoration: none;
color: var(--color-black);
}
&_title {
font-size: 28px;
font-weight: bold;
color: var(--color-11);
}
&_description {
font-size: var(--font-xs);
font-weight: 100;
line-height: 16px;
color: var(--color-grey);
}
&_button {
padding: 0 16px;
margin-top: 16px;
}
}
@media (max-width: 900px) {
.card {
min-height: 220px;
padding: 16px 0;
&_title {
margin: 0;
}
&_description {
display: none;
}
}
}
@media (max-width: 650px) {
.card {
min-height: auto;
padding: 32px 0;
&_value {
font-size: 22px;
}
&_title {
font-size: var(--font-s);
}
&_icon {
display: none;
}
}
}

View file

@ -1,40 +0,0 @@
@import '../../../../styles/variables';
.main {
display: grid;
grid-template-areas: 'header' 'main';
grid-template-columns: 1fr;
grid-template-rows: 66px 1fr;
min-height: 100vh;
background-color: #F5F7F9;
&_title {
grid-area: header;
font-size: var(--font-l);
line-height: var(--font-l);
font-weight: 100;
display: block;
padding: 24px;
margin: 0;
box-sizing: border-box;
text-align: center;
color: #84858D;
background-color: #252735;
}
&_cards {
grid-area: main;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
min-height: calc(100vh - 60px);
text-align: center;
}
}
@media (max-width: 800px) {
}

View file

@ -162,7 +162,7 @@ const Author = observer(({
{mode !== 'print' && ( {mode !== 'print' && (
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<Title title="Статистика по сотрудникам"/> <Title title="page.team.author.title"/>
<PageWrapper template="table"> <PageWrapper template="table">
<DataLoader <DataLoader
to="response" to="response"
@ -177,12 +177,12 @@ const Author = observer(({
<PageWrapper> <PageWrapper>
<PageColumn> <PageColumn>
<Description <Description
text="*Часть статитики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помошник» не считается*, т.к. это эпизодическая роль в проекте. Предпологаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы." text={localization.get('page.team.author.description1')}
/> />
</PageColumn> </PageColumn>
<PageColumn> <PageColumn>
<Description <Description
text="*Сортировка по умолчанию* — это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники)." text={localization.get('page.team.author.description2')}
/> />
</PageColumn> </PageColumn>
</PageWrapper> </PageWrapper>

View file

@ -16,7 +16,7 @@ const Hours = observer((): React.ReactElement => {
return ( return (
<> <>
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
<Title title="Распределение коммитов в течении каждого дня недели"/> <Title title="page.team.hours.title"/>
<PageWrapper template="table"> <PageWrapper template="table">
<HoursChart statistic={statistic} /> <HoursChart statistic={statistic} />
</PageWrapper> </PageWrapper>

View file

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import localization from 'ts/helpers/Localization';
import dataGripStore from 'ts/store/DataGrip'; import dataGripStore from 'ts/store/DataGrip';
import RecommendationsWrapper from 'ts/components/Recommendations/wrapper'; import RecommendationsWrapper from 'ts/components/Recommendations/wrapper';
@ -24,7 +23,7 @@ const Month = observer(({
{mode !== 'print' && ( {mode !== 'print' && (
<RecommendationsWrapper recommendations={recommendations}/> <RecommendationsWrapper recommendations={recommendations}/>
)} )}
<Title title={localization.get('Календарь работы по проекту')}/> <Title title="page.team.month.title"/>
<PageWrapper template="table"> <PageWrapper template="table">
<YearChart <YearChart
maxCommits={max} maxCommits={max}

View file

@ -116,7 +116,7 @@ const Scope = observer(({
{mode !== 'print' && ( {mode !== 'print' && (
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<Title title="Статистика по фичам"/> <Title title="page.team.scope.title"/>
<PageWrapper template="table"> <PageWrapper template="table">
<DataLoader <DataLoader
to="response" to="response"

View file

@ -4,7 +4,6 @@ import { observer } from 'mobx-react-lite';
import { IPagination } from 'ts/interfaces/Pagination'; import { IPagination } from 'ts/interfaces/Pagination';
import dataGripStore from 'ts/store/DataGrip'; import dataGripStore from 'ts/store/DataGrip';
import { getShortDateRange } from 'ts/helpers/formatter'; import { getShortDateRange } from 'ts/helpers/formatter';
import localization from 'ts/helpers/Localization';
import UiKitButton from 'ts/components/UiKit/components/Button'; import UiKitButton from 'ts/components/UiKit/components/Button';
import UiKitSelect from 'ts/components/UiKit/components/Select'; import UiKitSelect from 'ts/components/UiKit/components/Select';
@ -60,7 +59,7 @@ const Tempo = observer((): React.ReactElement => {
if (!partOfData?.length) return (<NothingFound />); if (!partOfData?.length) return (<NothingFound />);
return ( return (
<> <>
<Title title={localization.get('common.filters')} /> <Title title="common.filters" />
<PageWrapper> <PageWrapper>
<div className={style.tempo_page_filters}> <div className={style.tempo_page_filters}>
<UiKitButton <UiKitButton

View file

@ -26,7 +26,7 @@ const Total = observer((): React.ReactElement => {
return ( return (
<PageWrapper> <PageWrapper>
<PageColumn> <PageColumn>
<Title title={localization.get('page.team.total.titleA')}/> <Title title="page.team.total.titleA"/>
<div> <div>
<CardWithIcon <CardWithIcon
value={statistic.daysWorked} value={statistic.daysWorked}
@ -61,17 +61,17 @@ const Total = observer((): React.ReactElement => {
/> />
</div> </div>
<Description <Description
text="*Человеко-дни* — это работа одного сотрудника в течение одного рабочего дня. Например, за один календарный день, команда из трех сотрудников выдает объем работы в три человеко-дня." text={localization.get('page.team.total.description1')}
/> />
<Description <Description
text="*Днями прогулов* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют." text={localization.get('page.team.total.description2')}
/> />
<Description <Description
text="Карточка *работает и уволилось* показывает фактический состав сотрудников, которые постоянно участвуют в работе. Кроме этого, есть «помощники» — это сотрудники, как правило другой специализации, которые могут иногда делать коммиты в проект." text={localization.get('page.team.total.description3')}
/> />
</PageColumn> </PageColumn>
<PageColumn> <PageColumn>
<Title title={localization.get('page.team.total.titleB')}/> <Title title="page.team.total.titleB"/>
<div> <div>
<CardWithIcon <CardWithIcon
value={getShortMoney(statistic.moneyAll)} value={getShortMoney(statistic.moneyAll)}
@ -106,10 +106,10 @@ const Total = observer((): React.ReactElement => {
/> />
</div> </div>
<Description <Description
text="*Переплатой* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют. Именно поэтому переплата + фактическая стоимость != общей. В общей стоимости заложена оплата выходных, государственных праздников и отпусков." text={localization.get('page.team.total.description4')}
/> />
<Description <Description
text="*Работой на выходных* считается по коэфициенту х2 от оплаты обычного дня. Выше отображена именно переплата (х1), т.к. сам факт переработки в данном контексте не интересен. Мы не смотрим скорость сжигания бюджета. Мы смотрим переплату при увеличении скорости работы." text={localization.get('page.team.total.description5')}
/> />
</PageColumn> </PageColumn>
</PageWrapper> </PageWrapper>

View file

@ -37,7 +37,10 @@ function TreeView({ response }: ITreeViewProps) {
}; };
const fileChart = getOptions({ order: dataGripStore.dataGrip.author.list, suffix: 'строк' }); const fileChart = getOptions({ order: dataGripStore.dataGrip.author.list, suffix: 'строк' });
const rewriteChart = getOptions({ order: ['добавили', 'изменили'], suffix: 'строк' }); const rewriteChart = getOptions({ order: [
'page.team.tree.lineAdd',
'page.team.tree.lineRemove',
], suffix: 'page.team.tree.line' });
return ( return (
<Table <Table
@ -69,14 +72,14 @@ function TreeView({ response }: ITreeViewProps) {
value={file ? 100 : 0} value={file ? 100 : 0}
options={rewriteChart} options={rewriteChart}
details={{ details={{
'добавили': file?.lines || 0, 'page.team.tree.lineAdd': file?.lines || 0,
'изменили': (file?.total?.changes || 0) + (file?.total?.removed || 0), 'page.team.tree.lineRemove': (file?.total?.changes || 0) + (file?.total?.removed || 0),
}} }}
/> />
)} )}
/> />
<Column <Column
title="Кто добавлял" title="page.team.tree.add"
properties="file" properties="file"
minWidth={200} minWidth={200}
template={(file: any) => ( template={(file: any) => (
@ -88,7 +91,7 @@ function TreeView({ response }: ITreeViewProps) {
)} )}
/> />
<Column <Column
title="Кто менял" title="page.team.tree.change"
properties="file" properties="file"
minWidth={200} minWidth={200}
template={(file: any) => ( template={(file: any) => (
@ -100,7 +103,7 @@ function TreeView({ response }: ITreeViewProps) {
)} )}
/> />
<Column <Column
title="Кто удалял" title="page.team.tree.remove"
properties="file" properties="file"
minWidth={200} minWidth={200}
template={(file: any) => ( template={(file: any) => (
@ -128,7 +131,7 @@ const Tree = observer((): React.ReactElement => {
<> <>
<Title title={localization.get('common.filters')} /> <Title title={localization.get('common.filters')} />
<TreeFilters/> <TreeFilters/>
<Title title="Дерево проекта с учётом выбранных фильтров"/> <Title title="page.team.tree.title"/>
<PageWrapper template="table"> <PageWrapper template="table">
<DataLoader <DataLoader
to="response" to="response"

View file

@ -4,6 +4,7 @@ import { observer } from 'mobx-react-lite';
import dataGripStore from 'ts/store/DataGrip'; import dataGripStore from 'ts/store/DataGrip';
import UiKitSelect from 'ts/components/UiKit/components/SelectWithButtons'; import UiKitSelect from 'ts/components/UiKit/components/SelectWithButtons';
import UiKitInputNumber from 'ts/components/UiKit/components/InputNumber'; import UiKitInputNumber from 'ts/components/UiKit/components/InputNumber';
import localization from 'ts/helpers/Localization';
import treeStore from '../store/Tree'; import treeStore from '../store/Tree';
import style from '../styles/filters.module.scss'; import style from '../styles/filters.module.scss';
@ -11,12 +12,12 @@ import style from '../styles/filters.module.scss';
const TreeFilters = observer((): React.ReactElement => { const TreeFilters = observer((): React.ReactElement => {
const authors = dataGripStore.dataGrip.author.list; const authors = dataGripStore.dataGrip.author.list;
const options = authors.map((title: string, id: number) => ({ id: id + 1, title })); const options = authors.map((title: string, id: number) => ({ id: id + 1, title }));
options.unshift({ id: 0, title: 'Все сотрудники' }); options.unshift({ id: 0, title: localization.get('page.team.tree.filters.all') });
return ( return (
<> <>
<UiKitSelect <UiKitSelect
title="Сотрудник" title="page.team.tree.filters.author"
value={treeStore.authorId} value={treeStore.authorId}
options={options} options={options}
className={style.filter} className={style.filter}
@ -25,8 +26,8 @@ const TreeFilters = observer((): React.ReactElement => {
}} }}
/> />
<UiKitInputNumber <UiKitInputNumber
title="Количество коммитов" title="page.team.tree.filters.commits"
help="Минимальное количество коммитов, которое сделал сотрудник в файле" help="page.team.tree.filters.help"
value={treeStore.minCommits} value={treeStore.minCommits}
className={style.filter} className={style.filter}
onChange={(minCommits: number) => { onChange={(minCommits: number) => {

View file

@ -22,6 +22,7 @@ import RecommendationsWrapper from 'ts/components/Recommendations/wrapper';
import Description from 'ts/components/Description'; import Description from 'ts/components/Description';
import { getMax } from 'ts/pages/Common/helpers/getMax'; import { getMax } from 'ts/pages/Common/helpers/getMax';
import localization from 'ts/helpers/Localization';
interface ITypeViewProps { interface ITypeViewProps {
response?: IPagination<any>; response?: IPagination<any>;
@ -31,8 +32,8 @@ interface ITypeViewProps {
function TypeView({ response, updateSort }: ITypeViewProps) { function TypeView({ response, updateSort }: ITypeViewProps) {
if (!response) return null; if (!response) return null;
const taskChart = getOptions({ max: getMax(response, 'tasks'), suffix: 'задач' }); const taskChart = getOptions({ max: getMax(response, 'tasks'), suffix: 'page.team.type.tasksSmall' });
const daysByAuthorsChart = getOptions({ max: getMax(response, 'daysByAuthorsTotal'), suffix: 'дней' }); const daysByAuthorsChart = getOptions({ max: getMax(response, 'daysByAuthorsTotal'), suffix: 'page.team.type.daysSmall' });
const authorChart = getOptions({ order: dataGripStore.dataGrip.author.list }); const authorChart = getOptions({ order: dataGripStore.dataGrip.author.list });
return ( return (
@ -121,7 +122,7 @@ const Type = observer(({
{mode !== 'print' && ( {mode !== 'print' && (
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<Title title="Статистика по типам задач"/> <Title title="page.team.type.title"/>
<PageWrapper template="table"> <PageWrapper template="table">
<DataLoader <DataLoader
to="response" to="response"
@ -135,7 +136,7 @@ const Type = observer(({
</PageWrapper> </PageWrapper>
<PageWrapper> <PageWrapper>
<Description <Description
text="*Персональный вклад* считается по количеству коммитов, а не объему измененных строк или файлов. Поэтому следует так же смотреть раздел «Анализ файлов», чтобы оценить масштаб изменений." text={localization.get('page.team.type.description')}
/> />
</PageWrapper> </PageWrapper>
</> </>

View file

@ -2,6 +2,8 @@ import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import Console from 'ts/components/Console'; import Console from 'ts/components/Console';
import localization from 'ts/helpers/Localization';
import style from './styles/index.module.scss'; import style from './styles/index.module.scss';
function WarningInfo() { function WarningInfo() {
@ -33,34 +35,32 @@ function WarningInfo() {
} }
function Welcome() { function Welcome() {
const canShowWarning = true;
const command = 'git --no-pager log --numstat --oneline --all --reverse --date=iso-strict --pretty=format:"%ad>%cN>%cE>%s" > log.txt\n'; const command = 'git --no-pager log --numstat --oneline --all --reverse --date=iso-strict --pretty=format:"%ad>%cN>%cE>%s" > log.txt\n';
return ( return (
<> <>
{true && (<WarningInfo />)} {canShowWarning && (<WarningInfo />)}
<section className={style.welcome}> <section className={style.welcome}>
<div className={style.welcome_row}> <div className={style.welcome_row}>
<h2 className={style.welcome_first_title}> <h2 className={style.welcome_first_title}>
Выполните команду в корне вашего проекта {localization.get('page.welcome.step1')}
</h2> </h2>
<Console <Console
className={style.welcome_console} className={style.welcome_console}
textForCopy={command} textForCopy={command}
/> />
<p className={style.welcome_description}> <p className={style.welcome_description}>
Git создаст файл log.txt. {localization.get('page.welcome.description1')}
Он содержит данные для построения отчёта.
Или git shortlog -s -n -e если отчёт вам не нужен.
Создайте файл
<Link <Link
className={`${style.welcome_link}`} className={`${style.welcome_link}`}
target="_blank" target="_blank"
to="https://git-scm.com/docs/gitmailmap"> to="https://git-scm.com/docs/gitmailmap">
.mailmap .mailmap
</Link> </Link>
{' в корне проекта, чтобы обьединить статистику по сотрудникам.'} {localization.get('page.welcome.description2')}
</p> </p>
<h2 className={style.welcome_last_title}> <h2 className={style.welcome_last_title}>
Перетащите файл log.txt на эту страницу {localization.get('page.welcome.step2')}
</h2> </h2>
</div> </div>
</section> </section>

View file

@ -84,7 +84,7 @@
&_link { &_link {
display: inline; display: inline;
margin: 16px 0 0 4px; margin: 16px 4px 0 4px;
text-decoration: underline; text-decoration: underline;
} }
} }