This commit is contained in:
bakhirev 2025-02-06 17:08:54 +03:00
parent 9bd2675129
commit 88452159ae
42 changed files with 634 additions and 412 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -77,7 +77,7 @@
} }
&_body { &_body {
max-height: calc(60vh - 200px); max-height: calc(100vh - 200px);
padding: 0 24px; padding: 0 24px;
overflow: auto; overflow: auto;
line-height: 1.5; line-height: 1.5;

View file

@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import Description from 'ts/components/Description'; import Description from 'ts/components/Description';
import UiKitButton from 'ts/components/UiKit/components/Button'; import UiKitButton from 'ts/components/UiKit/components/Button';
import localization from 'ts/helpers/Localization'; import localization from 'ts/helpers/Localization';
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants'; import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
import isMobile from 'ts/helpers/isMobile'; import isMobile from 'ts/helpers/isMobile';
import { getFormattedTitle, getDescriptionText } from '../helpers'; import { getFormattedTitle, getDescriptionText } from '../helpers';

View file

@ -2,7 +2,7 @@ import React from 'react';
import Description from 'ts/components/Description'; import Description from 'ts/components/Description';
import localization from 'ts/helpers/Localization'; import localization from 'ts/helpers/Localization';
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants'; import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
import { getFormattedTitle, getDescriptionText } from '../helpers'; import { getFormattedTitle, getDescriptionText } from '../helpers';
import style from '../styles/card.module.scss'; import style from '../styles/card.module.scss';

View file

@ -4,7 +4,7 @@ import { observer } from 'mobx-react-lite';
import UiKitButton from 'ts/components/UiKit/components/Button'; import UiKitButton from 'ts/components/UiKit/components/Button';
import { Modal, Header, Body, Footer } from 'ts/components/ModalWindow'; import { Modal, Header, Body, Footer } from 'ts/components/ModalWindow';
import Description from 'ts/components/Description'; import Description from 'ts/components/Description';
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants'; import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
import localization from 'ts/helpers/Localization'; import localization from 'ts/helpers/Localization';
import { getFormattedTitle, getDescriptionText } from '../helpers'; import { getFormattedTitle, getDescriptionText } from '../helpers';

View file

@ -1,5 +1,10 @@
import { getDateByTimestamp } from 'ts/helpers/formatter'; import { getDateByTimestamp } from 'ts/helpers/formatter';
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const {
getArgTitle,
getTitleArgDescription,
} = getBuilder('timestamp');
export default class RecommendationsPersonByTimestamp { export default class RecommendationsPersonByTimestamp {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -10,35 +15,14 @@ export default class RecommendationsPersonByTimestamp {
acc[name] = []; acc[name] = [];
if (workInWeek) { if (workInWeek) {
acc[name].push({ acc[name].push(getArgTitle('weekendDays', [workInWeek]));
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.weekendDays.description',
type: RECOMMENDATION_TYPES.ALERT,
arguments: {
title: [workInWeek],
},
});
} }
if (byAuthor.daysLosses) { if (byAuthor.daysLosses) {
acc[name].push({ acc[name].push(getArgTitle('lossesDays', [byAuthor.daysLosses]));
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.lossesDays.description',
type: RECOMMENDATION_TYPES.WARNING,
arguments: {
title: [byAuthor.daysLosses],
},
});
} }
acc[name].push({ acc[name].push(getArgTitle('allDays', [byAuthor.daysAll]));
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.allDays.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: [byAuthor.daysAll],
},
});
acc[name].push(this.getFirstDay(byTimestamp)); acc[name].push(this.getFirstDay(byTimestamp));
@ -51,28 +35,12 @@ export default class RecommendationsPersonByTimestamp {
getFirstDay(byTimestamp: any) { getFirstDay(byTimestamp: any) {
const commit = byTimestamp.allCommitsByTimestamp[0]; const commit = byTimestamp.allCommitsByTimestamp[0];
const [date, day] = getDateByTimestamp(commit.timestamp); const [date, day] = getDateByTimestamp(commit.timestamp);
return { return getTitleArgDescription('firstCommit', date, [day]);
title: date,
description: 'recommendations.timestamp.firstCommit.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
description: [day],
},
};
} }
getLastDay(byTimestamp: any) { getLastDay(byTimestamp: any) {
const commit = byTimestamp.allCommitsByTimestamp[(byTimestamp.allCommitsByTimestamp.length - 1)]; const commit = byTimestamp.allCommitsByTimestamp[(byTimestamp.allCommitsByTimestamp.length - 1)];
const [date, day] = getDateByTimestamp(commit.timestamp); const [date, day] = getDateByTimestamp(commit.timestamp);
return { return getTitleArgDescription('lastCommit', date, [day]);
title: date,
description: 'recommendations.timestamp.lastCommit.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
description: [day],
},
};
} }
} }

View file

@ -1,4 +1,6 @@
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const { getItem } = getBuilder('week');
export default class RecommendationsPersonByWeek { export default class RecommendationsPersonByWeek {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -16,63 +18,39 @@ export default class RecommendationsPersonByWeek {
getLazyDays(lastWeeks: any[], name: string) { getLazyDays(lastWeeks: any[], name: string) {
const lazyDays = lastWeeks.map(statistic => statistic.lazyDays[name]); const lazyDays = lastWeeks.map(statistic => statistic.lazyDays[name]);
if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) {
if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) return { return getItem('lazyDaysDown');
title: 'recommendations.week.lazyDays.down.title', }
description: 'recommendations.week.lazyDays.down.description', if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) {
type: RECOMMENDATION_TYPES.FACT, return getItem('lazyDaysUp');
}; }
if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) return {
title: 'recommendations.week.lazyDays.up.title',
description: 'recommendations.week.lazyDays.up.description',
type: RECOMMENDATION_TYPES.ALERT,
};
return null; return null;
} }
getNotWork(lastWeeks: any[], name: string) { getNotWork(lastWeeks: any[], name: string) {
const lazyDays = lastWeeks.map(statistic => statistic.lazyDays[name]); const lazyDays = lastWeeks.map(statistic => statistic.lazyDays[name]);
if (lazyDays[0] && lazyDays[1] && lazyDays[2]) {
if (lazyDays[0] && lazyDays[1] && lazyDays[2]) return { return getItem('notWork');
title: 'recommendations.week.notWork.title', }
description: 'recommendations.week.notWork.description',
type: RECOMMENDATION_TYPES.ALERT,
};
return null; return null;
} }
getUpWork(lastWeeks: any[], name: string) { getUpWork(lastWeeks: any[], name: string) {
const weekDays = lastWeeks.map(statistic => statistic.weekDays[name]); const weekDays = lastWeeks.map(statistic => statistic.weekDays[name]);
if (weekDays[0] && weekDays[1] && weekDays[2]) {
if (weekDays[0] && weekDays[1] && weekDays[2]) return { return getItem('upWork');
title: 'recommendations.week.upWork.title', }
description: 'recommendations.week.upWork.description',
type: RECOMMENDATION_TYPES.ALERT,
};
return null; return null;
} }
getTasks(lastWeeks: any[], name: string) { // TODO: спорно, это видно по количеству изменений getTasks(lastWeeks: any[], name: string) { // TODO: спорно, это видно по количеству изменений
const lazyDays = lastWeeks.map(statistic => statistic.taskInDay[name]); const lazyDays = lastWeeks.map(statistic => statistic.taskInDay[name]);
if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) {
if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) return { return getItem('taskUp');
title: 'recommendations.week.task.up.title', }
description: 'recommendations.week.task.up.description', if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) {
type: RECOMMENDATION_TYPES.FACT, return getItem('taskDown');
}; }
if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) return {
title: 'recommendations.week.task.down.title',
description: 'recommendations.week.task.down.description',
type: RECOMMENDATION_TYPES.ALERT,
};
return null; return null;
} }
} }

View file

@ -1,4 +1,10 @@
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const {
getItem,
getTitle,
getArgTitleDescription,
} = getBuilder('author');
export default class RecommendationsTeamByAuthor { export default class RecommendationsTeamByAuthor {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -41,106 +47,27 @@ export default class RecommendationsTeamByAuthor {
return [ return [
projectType, projectType,
(lotOfLazy.length ? { (lotOfLazy.length ? getArgTitleDescription('lotOfLazy', lotOfLazy.length, lotOfLazy.join(';\n- ')) : null),
title: 'recommendations.author.lotOfLazy.title', (manyLazy.length ? getArgTitleDescription('manyLazy', manyLazy.length, manyLazy.join(';\n- ')) : null),
description: 'recommendations.author.lotOfLazy.description', (oneTypeMans.length ? getTitle('oneTypeMans', oneTypeMans) : null),
type: RECOMMENDATION_TYPES.ALERT, (worker.length ? getArgTitleDescription('workToday', worker.length, worker.join(';\n- ')) : null),
arguments: { (dismissed.length ? getArgTitleDescription('dismissed', dismissed.length, dismissed.join(';\n- ')) : null),
title: lotOfLazy.length, (staff.length ? getArgTitleDescription('staff', staff.length, staff.join(';\n- ')) : null),
description: lotOfLazy.join(';\n- '),
},
} : null),
(manyLazy.length ? {
title: 'recommendations.author.manyLazy.title',
description: 'recommendations.author.manyLazy.description',
type: RECOMMENDATION_TYPES.WARNING,
arguments: {
title: manyLazy.length,
description: manyLazy.join(';\n- '),
},
} : null),
(oneTypeMans.length ? {
title: oneTypeMans,
description: 'recommendations.author.oneTypeMans',
type: RECOMMENDATION_TYPES.WARNING,
} : null),
(worker.length ? {
title: 'recommendations.author.workToday.title',
description: 'recommendations.author.workToday.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: worker.length,
description: worker.join(';\n- '),
},
} : null),
(dismissed.length ? {
title: 'recommendations.author.dismissed.title',
description: 'recommendations.author.dismissed.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: dismissed.length,
description: dismissed.join(';\n- '),
},
} : null),
(staff.length ? {
title: 'recommendations.author.staff.title',
description: 'recommendations.author.staff.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: staff.length,
description: staff.join(';\n- '),
},
} : null),
// ['Планирование', 'Задачи распределены довольно равномерно', 'info'], // ['Планирование', 'Задачи распределены довольно равномерно', 'info'],
{ getItem('manager'),
title: 'recommendations.author.manager.title', getItem('shorTalk'),
description: 'recommendations.author.manager.description', getItem('ipr'),
type: RECOMMENDATION_TYPES.INFO, getItem('oneToOne'),
}, getItem('club'),
{
title: 'recommendations.author.shorTalk.title',
description: 'recommendations.author.shorTalk.description',
type: RECOMMENDATION_TYPES.INFO,
},
{
title: 'recommendations.author.ipr.title',
description: 'recommendations.author.ipr.description',
type: RECOMMENDATION_TYPES.INFO,
},
{
title: 'recommendations.author.oneToOne.title',
description: 'recommendations.author.oneToOne.description',
type: RECOMMENDATION_TYPES.INFO,
},
{
title: 'recommendations.author.club.title',
description: 'recommendations.author.club.description',
type: RECOMMENDATION_TYPES.INFO,
},
].filter(item => item); ].filter(item => item);
} }
getProjectType(workLazyTotal: number) { getProjectType(workLazyTotal: number) {
if (workLazyTotal < 1) return { if (workLazyTotal < 1) return getItem('projectTypeOpenSource');
title: 'recommendations.author.projectType.openSource.title',
description: 'recommendations.author.projectType.openSource.description',
type: RECOMMENDATION_TYPES.FACT,
};
if (workLazyTotal < 5) return { if (workLazyTotal < 5) return getItem('projectTypeEasy');
title: 'recommendations.author.projectType.easy.title',
description: 'recommendations.author.projectType.easy.description',
type: RECOMMENDATION_TYPES.ALERT,
};
return null; return null;
} }
} }

View file

@ -1,4 +1,6 @@
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const { getItem } = getBuilder('hour');
export default class RecommendationsTeamByHour { export default class RecommendationsTeamByHour {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -16,23 +18,9 @@ export default class RecommendationsTeamByHour {
const weekends = Math.max(...statistic.commitsByDayAndHourTotal.slice(5, 7)); const weekends = Math.max(...statistic.commitsByDayAndHourTotal.slice(5, 7));
const workAndWeekends = weekends / weekday; const workAndWeekends = weekends / weekday;
if (workAndWeekends > 0.45) return { if (workAndWeekends > 0.45) return getItem('onlyWork');
title: 'recommendations.hour.onlyWork.title', if (workAndWeekends > 0.2) return getItem('weekends');
description: 'recommendations.hour.onlyWork.description', if (workAndWeekends > 0) return getItem('easy');
type: RECOMMENDATION_TYPES.ALERT,
};
if (workAndWeekends > 0.2) return {
title: 'recommendations.hour.weekends.title',
description: 'recommendations.hour.weekends.description',
type: RECOMMENDATION_TYPES.ALERT,
};
if (workAndWeekends > 0) return {
title: 'recommendations.hour.easy.title',
description: 'recommendations.hour.easy.description',
type: RECOMMENDATION_TYPES.WARNING,
};
return null; return null;
} }

View file

@ -1,5 +1,7 @@
import { getMoney } from 'ts/helpers/formatter'; import { getMoney } from 'ts/helpers/formatter';
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const { getItem, getTitle } = getBuilder('scope');
export default class RecommendationsTeamByScope { export default class RecommendationsTeamByScope {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -8,21 +10,9 @@ export default class RecommendationsTeamByScope {
this.getBusFactor(dataGrip), this.getBusFactor(dataGrip),
this.getManyTypes(dataGrip), this.getManyTypes(dataGrip),
this.getParallelism(dataGrip), this.getParallelism(dataGrip),
{ getTitle('money', money),
title: money, getItem('plan'),
description: 'recommendations.scope.money', getItem('cost'),
type: RECOMMENDATION_TYPES.FACT,
},
{
title: 'recommendations.scope.plan.title',
description: 'recommendations.scope.plan.description',
type: RECOMMENDATION_TYPES.INFO,
},
{
title: 'recommendations.scope.cost.title',
description: 'recommendations.scope.cost.description',
type: RECOMMENDATION_TYPES.INFO,
},
].filter(item => item); ].filter(item => item);
} }
@ -42,23 +32,10 @@ export default class RecommendationsTeamByScope {
const total = data.reduce((sum, value) => sum + value, 0); const total = data.reduce((sum, value) => sum + value, 0);
const parallelism = total / data.length; const parallelism = total / data.length;
if (parallelism < 1.3) return { if (parallelism < 1.3) return getItem('parallelismNot');
title: 'recommendations.scope.parallelism.not.title', if (parallelism < 2) return getItem('parallelismHas');
description: 'recommendations.scope.parallelism.not.description',
type: RECOMMENDATION_TYPES.FACT,
};
if (parallelism < 2) return { return getItem('parallelismEvery');
title: 'recommendations.scope.parallelism.has.title',
description: 'recommendations.scope.parallelism.has.description',
type: RECOMMENDATION_TYPES.FACT,
};
return {
title: 'recommendations.scope.parallelism.every.title',
description: 'recommendations.scope.parallelism.every.description',
type: RECOMMENDATION_TYPES.FACT,
};
} }
getBusFactor(dataGrip: any) { getBusFactor(dataGrip: any) {
@ -73,17 +50,9 @@ export default class RecommendationsTeamByScope {
if (!oneMaintainer.length) return null; if (!oneMaintainer.length) return null;
const everyHasOne = oneMaintainer.length > dataGrip.scope.statistic.length * 0.6; const everyHasOne = oneMaintainer.length > dataGrip.scope.statistic.length * 0.6;
if (everyHasOne) return { return everyHasOne
title: 'recommendations.scope.bus.everyHasOne.title', ? getItem('busEveryHasOne')
description: 'recommendations.scope.bus.everyHasOne.description', : getTitle('busOneMaintainer', oneMaintainer);
type: RECOMMENDATION_TYPES.WARNING,
};
return {
title: oneMaintainer,
description: 'recommendations.scope.bus.oneMaintainer',
type: RECOMMENDATION_TYPES.ALERT,
};
} }
getManyTypes(dataGrip: any) { getManyTypes(dataGrip: any) {
@ -96,22 +65,8 @@ export default class RecommendationsTeamByScope {
const everyHasOne = oneType.length > dataGrip.scope.statistic.length * 0.6; const everyHasOne = oneType.length > dataGrip.scope.statistic.length * 0.6;
if (everyHasOne) return { return everyHasOne
title: 'recommendations.scope.types.process.title', ? getItem('typesProcess')
description: [ : getTitle('typesOne', oneType);
'recommendations.scope.types.process.description',
'recommendations.scope.types.common',
],
type: RECOMMENDATION_TYPES.WARNING,
};
return {
title: oneType,
description: [
'recommendations.scope.types.one',
'recommendations.scope.types.common',
],
type: RECOMMENDATION_TYPES.WARNING,
};
} }
} }

View file

@ -1,5 +1,11 @@
import { getDateByTimestamp } from 'ts/helpers/formatter'; import { getDateByTimestamp } from 'ts/helpers/formatter';
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const {
getItem,
getArgTitle,
getTitleArgDescription,
} = getBuilder('timestamp');
export default class RecommendationsTeamByTimestamp { export default class RecommendationsTeamByTimestamp {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -11,26 +17,9 @@ export default class RecommendationsTeamByTimestamp {
// TODO: all days не верный, я вывожу рабочие дни, а не выходные. // TODO: all days не верный, я вывожу рабочие дни, а не выходные.
return [ return [
(workInWeek ? { (workInWeek ? getArgTitle('weekendDays', [workInWeek]) : null),
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.weekendDays.description',
type: RECOMMENDATION_TYPES.ALERT,
arguments: {
title: [workInWeek],
},
} : null),
this.getWorkOnWeek(byTimestamp.allCommitsByTimestamp.length, workInWeek), this.getWorkOnWeek(byTimestamp.allCommitsByTimestamp.length, workInWeek),
getArgTitle('allDays', [totalDays]),
{
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.allDays.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: [totalDays],
},
},
this.getFirstDay(byTimestamp), this.getFirstDay(byTimestamp),
this.getLastDay(byTimestamp), this.getLastDay(byTimestamp),
].filter(item => item); ].filter(item => item);
@ -38,61 +27,21 @@ export default class RecommendationsTeamByTimestamp {
getWorkOnWeek(allWorkDays: number, workOnWeek: number) { getWorkOnWeek(allWorkDays: number, workOnWeek: number) {
const percent = (workOnWeek * 100) / allWorkDays; const percent = (workOnWeek * 100) / allWorkDays;
if (percent > 13) return getItem('regularWeekendWord');
if (percent > 13) { if (percent > 7) return getItem('sometimeWeekendWord');
return { if (percent > 2) return getItem('neverWeekendWord');
title: 'recommendations.timestamp.regularWeekendWord.title',
description: 'recommendations.timestamp.weekendWord.description',
type: RECOMMENDATION_TYPES.ALERT,
};
}
if (percent > 7) {
return {
title: 'recommendations.timestamp.sometimeWeekendWord.title',
description: 'recommendations.timestamp.weekendWord.description',
type: RECOMMENDATION_TYPES.ALERT,
};
}
if (percent > 2) {
return {
title: 'recommendations.timestamp.neverWeekendWord.title',
description: 'recommendations.timestamp.neverWeekendWord.description',
type: RECOMMENDATION_TYPES.FACT,
};
}
return null; return null;
} }
getFirstDay(byTimestamp: any) { getFirstDay(byTimestamp: any) {
const commit = byTimestamp.allCommitsByTimestamp[0]; const commit = byTimestamp.allCommitsByTimestamp[0];
const [ date, day ] = getDateByTimestamp(commit.timestamp); const [ date, day ] = getDateByTimestamp(commit.timestamp);
return getTitleArgDescription('firstCommit', date, [day]);
return {
title: date,
description: 'recommendations.timestamp.firstCommit.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
description: [day],
},
};
} }
getLastDay(byTimestamp: any) { getLastDay(byTimestamp: any) {
const commit = byTimestamp.allCommitsByTimestamp[(byTimestamp.allCommitsByTimestamp.length - 1)]; const commit = byTimestamp.allCommitsByTimestamp[(byTimestamp.allCommitsByTimestamp.length - 1)];
const [ date, day ] = getDateByTimestamp(commit.timestamp); const [ date, day ] = getDateByTimestamp(commit.timestamp);
return getTitleArgDescription('lastCommit', date, [day]);
return {
title: date,
description: 'recommendations.timestamp.lastCommit.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
description: [day],
},
};
} }
} }

View file

@ -1,4 +1,6 @@
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const { getItem, getArgDescription } = getBuilder('type');
export default class RecommendationsTeamByType { export default class RecommendationsTeamByType {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -8,21 +10,9 @@ export default class RecommendationsTeamByType {
return [ return [
this.getBusFactor(dataGrip), this.getBusFactor(dataGrip),
(fewTypes ? { (fewTypes ? getItem('fewTypes') : null),
title: 'recommendations.type.fewTypes.title', getItem('diff'),
description: 'recommendations.type.fewTypes.description', getItem('buddy'),
type: RECOMMENDATION_TYPES.FACT,
} : null),
{
title: 'recommendations.type.diff.title',
description: 'recommendations.type.diff.description',
type: RECOMMENDATION_TYPES.INFO,
},
{
title: 'recommendations.type.buddy.title',
description: 'recommendations.type.buddy.description',
type: RECOMMENDATION_TYPES.INFO,
},
].filter(item => item); ].filter(item => item);
} }
@ -39,27 +29,8 @@ export default class RecommendationsTeamByType {
if (!oneMaintainer.length) return null; if (!oneMaintainer.length) return null;
const everyHasOne = oneMaintainer.length > dataGrip.type.statistic.length * 0.6; const everyHasOne = oneMaintainer.length > dataGrip.type.statistic.length * 0.6;
if (everyHasOne) return { return everyHasOne
title: 'recommendations.type.everyHasOne.title', ? getItem('everyHasOne')
description: [ : getArgDescription('oneMaintainer', [`- ${oneMaintainer.join(';\n- ')}`]);
'recommendations.type.everyHasOne.description',
'recommendations.type.common',
],
type: RECOMMENDATION_TYPES.WARNING,
};
return {
title: 'recommendations.type.oneMaintainer.title',
description: [
'recommendations.type.oneMaintainer.description',
'recommendations.type.common',
],
type: RECOMMENDATION_TYPES.ALERT,
arguments: {
description: [`- ${oneMaintainer.join(';\n- ')}`],
},
};
} }
} }

View file

@ -1,4 +1,6 @@
import RECOMMENDATION_TYPES from '../contstants'; import { getBuilder } from '../helpers';
const { getItem, getTitle } = getBuilder('week');
export default class RecommendationsTeamByWeek { export default class RecommendationsTeamByWeek {
getTotalInfo(dataGrip: any) { getTotalInfo(dataGrip: any) {
@ -14,45 +16,23 @@ export default class RecommendationsTeamByWeek {
getLazyDays(dataGrip: any, lastWeek: any) { getLazyDays(dataGrip: any, lastWeek: any) {
const lazyDays = lastWeek.map((statistic: any) => statistic.lazyDaysTotal / statistic.authorsLength); const lazyDays = lastWeek.map((statistic: any) => statistic.lazyDaysTotal / statistic.authorsLength);
if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) { if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) {
return { return getItem('lazyDaysDown');
title: 'recommendations.week.lazyDays.down.title',
description: 'recommendations.week.lazyDays.down.description',
type: RECOMMENDATION_TYPES.FACT,
};
} }
if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) { if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) {
return { return getItem('lazyDaysUp');
title: 'recommendations.week.lazyDays.up.title',
description: 'recommendations.week.lazyDays.up.description',
type: RECOMMENDATION_TYPES.ALERT,
};
} }
return null; return null;
} }
getTasks(dataGrip: any, lastWeek: any) { // TODO: спорно, это видно по количеству изменений getTasks(dataGrip: any, lastWeek: any) { // TODO: спорно, это видно по количеству изменений
const lazyDays = lastWeek.map((statistic: any) => statistic.tasks / statistic.authorsLength); const lazyDays = lastWeek.map((statistic: any) => statistic.tasks / statistic.authorsLength);
if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) { if (lazyDays[0] < lazyDays[1] && lazyDays[1] < lazyDays[2]) {
return { return getItem('taskUp');
title: 'recommendations.week.task.up.title',
description: 'recommendations.week.task.up.description',
type: RECOMMENDATION_TYPES.FACT,
};
} }
if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) { if (lazyDays[0] > lazyDays[1] && lazyDays[1] > lazyDays[2]) {
return { return getItem('taskDown');
title: 'recommendations.week.task.down.title',
description: 'recommendations.week.task.down.description',
type: RECOMMENDATION_TYPES.ALERT,
};
} }
return null; return null;
} }
@ -64,15 +44,9 @@ export default class RecommendationsTeamByWeek {
// TODO: неверный расчет // TODO: неверный расчет
// нужен человек, который встречается в трех массивах лидеров прогула // нужен человек, который встречается в трех массивах лидеров прогула
if (lazyMaintainer[0] === lazyMaintainer[1] === lazyMaintainer[2]) { if (lazyMaintainer[0] === lazyMaintainer[1] === lazyMaintainer[2]) {
return { return getTitle('taskLazyMaintainer', lazyMaintainer[0]);
title: lazyMaintainer[0],
description: 'recommendations.week.task.lazyMaintainer.description',
type: RECOMMENDATION_TYPES.ALERT,
};
} }
return null; return null;
} }
} }

View file

@ -1,6 +0,0 @@
export default {
ALERT: 'error',
WARNING: 'warning',
FACT: 'fact',
INFO: 'info',
};

View file

@ -0,0 +1,296 @@
export const RECOMMENDATION_TYPES = {
ALERT: 'error',
WARNING: 'warning',
FACT: 'fact',
INFO: 'info',
};
export const RECOMMENDATIONS_BY_VIEW = {
timestamp: {
weekendDays: {
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.weekendDays.description',
type: RECOMMENDATION_TYPES.ALERT,
arguments: {
title: [],
},
},
lossesDays: {
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.lossesDays.description',
type: RECOMMENDATION_TYPES.WARNING,
arguments: {
title: [],
},
},
allDays: {
title: 'recommendations.timestamp.common.title',
description: 'recommendations.timestamp.allDays.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: [],
},
},
firstCommit: {
title: '',
description: 'recommendations.timestamp.firstCommit.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
description: [],
},
},
lastCommit: {
title: '',
description: 'recommendations.timestamp.lastCommit.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
description: [],
},
},
regularWeekendWord: {
title: 'recommendations.timestamp.regularWeekendWord.title',
description: 'recommendations.timestamp.weekendWord.description',
type: RECOMMENDATION_TYPES.ALERT,
},
sometimeWeekendWord:{
title: 'recommendations.timestamp.sometimeWeekendWord.title',
description: 'recommendations.timestamp.weekendWord.description',
type: RECOMMENDATION_TYPES.ALERT,
},
neverWeekendWord: {
title: 'recommendations.timestamp.neverWeekendWord.title',
description: 'recommendations.timestamp.neverWeekendWord.description',
type: RECOMMENDATION_TYPES.FACT,
},
},
week: {
lazyDaysDown: {
title: 'recommendations.week.lazyDays.down.title',
description: 'recommendations.week.lazyDays.down.description',
type: RECOMMENDATION_TYPES.FACT,
},
lazyDaysUp: {
title: 'recommendations.week.lazyDays.up.title',
description: 'recommendations.week.lazyDays.up.description',
type: RECOMMENDATION_TYPES.ALERT,
},
notWork: {
title: 'recommendations.week.notWork.title',
description: 'recommendations.week.notWork.description',
type: RECOMMENDATION_TYPES.ALERT,
},
upWork: {
title: 'recommendations.week.upWork.title',
description: 'recommendations.week.upWork.description',
type: RECOMMENDATION_TYPES.ALERT,
},
taskUp: {
title: 'recommendations.week.task.up.title',
description: 'recommendations.week.task.up.description',
type: RECOMMENDATION_TYPES.FACT,
},
taskDown: {
title: 'recommendations.week.task.down.title',
description: 'recommendations.week.task.down.description',
type: RECOMMENDATION_TYPES.ALERT,
},
taskLazyMaintainer: {
description: 'recommendations.week.task.lazyMaintainer.description',
type: RECOMMENDATION_TYPES.ALERT,
},
},
type: {
fewTypes: {
title: 'recommendations.type.fewTypes.title',
description: 'recommendations.type.fewTypes.description',
type: RECOMMENDATION_TYPES.FACT,
},
diff: {
title: 'recommendations.type.diff.title',
description: 'recommendations.type.diff.description',
type: RECOMMENDATION_TYPES.INFO,
},
buddy: {
title: 'recommendations.type.buddy.title',
description: 'recommendations.type.buddy.description',
type: RECOMMENDATION_TYPES.INFO,
},
everyHasOne: {
title: 'recommendations.type.everyHasOne.title',
description: [
'recommendations.type.everyHasOne.description',
'recommendations.type.common',
],
type: RECOMMENDATION_TYPES.WARNING,
},
oneMaintainer: {
title: 'recommendations.type.oneMaintainer.title',
description: [
'recommendations.type.oneMaintainer.description',
'recommendations.type.common',
],
type: RECOMMENDATION_TYPES.ALERT,
arguments: {
description: [],
},
},
},
scope: {
money: {
description: 'recommendations.scope.money',
type: RECOMMENDATION_TYPES.FACT,
},
plan: {
title: 'recommendations.scope.plan.title',
description: 'recommendations.scope.plan.description',
type: RECOMMENDATION_TYPES.INFO,
},
cost: {
title: 'recommendations.scope.cost.title',
description: 'recommendations.scope.cost.description',
type: RECOMMENDATION_TYPES.INFO,
},
parallelismNot: {
title: 'recommendations.scope.parallelism.not.title',
description: 'recommendations.scope.parallelism.not.description',
type: RECOMMENDATION_TYPES.FACT,
},
parallelismHas: {
title: 'recommendations.scope.parallelism.has.title',
description: 'recommendations.scope.parallelism.has.description',
type: RECOMMENDATION_TYPES.FACT,
},
parallelismEvery: {
title: 'recommendations.scope.parallelism.every.title',
description: 'recommendations.scope.parallelism.every.description',
type: RECOMMENDATION_TYPES.FACT,
},
busEveryHasOne: {
title: 'recommendations.scope.bus.everyHasOne.title',
description: 'recommendations.scope.bus.everyHasOne.description',
type: RECOMMENDATION_TYPES.WARNING,
},
busOneMaintainer: {
description: 'recommendations.scope.bus.oneMaintainer',
type: RECOMMENDATION_TYPES.ALERT,
},
typesProcess: {
title: 'recommendations.scope.types.process.title',
description: [
'recommendations.scope.types.process.description',
'recommendations.scope.types.common',
],
type: RECOMMENDATION_TYPES.WARNING,
},
typesOne: {
description: [
'recommendations.scope.types.one',
'recommendations.scope.types.common',
],
type: RECOMMENDATION_TYPES.WARNING,
},
},
hour: {
onlyWork: {
title: 'recommendations.hour.onlyWork.title',
description: 'recommendations.hour.onlyWork.description',
type: RECOMMENDATION_TYPES.ALERT,
},
weekends: {
title: 'recommendations.hour.weekends.title',
description: 'recommendations.hour.weekends.description',
type: RECOMMENDATION_TYPES.ALERT,
},
easy: {
title: 'recommendations.hour.easy.title',
description: 'recommendations.hour.easy.description',
type: RECOMMENDATION_TYPES.WARNING,
},
},
author: {
lotOfLazy: {
title: 'recommendations.author.lotOfLazy.title',
description: 'recommendations.author.lotOfLazy.description',
type: RECOMMENDATION_TYPES.ALERT,
arguments: {
title: '',
description: '',
},
},
manyLazy: {
title: 'recommendations.author.manyLazy.title',
description: 'recommendations.author.manyLazy.description',
type: RECOMMENDATION_TYPES.WARNING,
arguments: {
title: '',
description: '',
},
},
oneTypeMans: {
description: 'recommendations.author.oneTypeMans',
type: RECOMMENDATION_TYPES.WARNING,
},
workToday: {
title: 'recommendations.author.workToday.title',
description: 'recommendations.author.workToday.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: '',
description: '',
},
},
dismissed: {
title: 'recommendations.author.dismissed.title',
description: 'recommendations.author.dismissed.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: '',
description: '',
},
},
staff: {
title: 'recommendations.author.staff.title',
description: 'recommendations.author.staff.description',
type: RECOMMENDATION_TYPES.FACT,
arguments: {
title: '',
description: '',
},
},
manager: {
title: 'recommendations.author.manager.title',
description: 'recommendations.author.manager.description',
type: RECOMMENDATION_TYPES.INFO,
},
shorTalk: {
title: 'recommendations.author.shorTalk.title',
description: 'recommendations.author.shorTalk.description',
type: RECOMMENDATION_TYPES.INFO,
},
ipr: {
title: 'recommendations.author.ipr.title',
description: 'recommendations.author.ipr.description',
type: RECOMMENDATION_TYPES.INFO,
},
oneToOne: {
title: 'recommendations.author.oneToOne.title',
description: 'recommendations.author.oneToOne.description',
type: RECOMMENDATION_TYPES.INFO,
},
club: {
title: 'recommendations.author.club.title',
description: 'recommendations.author.club.description',
type: RECOMMENDATION_TYPES.INFO,
},
projectTypeOpenSource: {
title: 'recommendations.author.projectType.openSource.title',
description: 'recommendations.author.projectType.openSource.description',
type: RECOMMENDATION_TYPES.FACT,
},
projectTypeEasy: {
title: 'recommendations.author.projectType.easy.title',
description: 'recommendations.author.projectType.easy.description',
type: RECOMMENDATION_TYPES.ALERT,
},
},
};

View file

@ -0,0 +1,58 @@
import { RECOMMENDATIONS_BY_VIEW } from './contstants';
export function getBuilder(type: string) {
function getItem(id: string) {
return RECOMMENDATIONS_BY_VIEW[type][id];
}
function getTitle(id: string, title: any) {
return { ...getItem(id), title };
}
function getArgTitle(id: string, title?: any) {
return {
...getItem(id),
arguments: {
title,
},
};
}
function getArgDescription(id: string, description?: any) {
return {
...getItem(id),
arguments: {
description,
},
};
}
function getTitleArgDescription(id: string, title: string, description?: any) {
return {
...getTitle(id, title),
arguments: {
description,
},
};
}
function getArgTitleDescription(id: string, title: any, description?: any) {
return {
...getItem(id),
arguments: {
title,
description,
},
};
}
return {
getItem,
getTitle,
getArgTitle,
getArgDescription,
getTitleArgDescription,
getArgTitleDescription,
};
}

View file

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import dataGripStore from 'ts/store/DataGrip'; import dataGripStore from 'ts/store/DataGrip';
import { getDate, getDateByTimestamp } from 'ts/helpers/formatter'; import { getDate, getDateByTimestamp } from 'ts/helpers/formatter';
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants'; import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
import Recommendations from 'ts/components/Recommendations'; import Recommendations from 'ts/components/Recommendations';
import NothingFound from 'ts/components/NothingFound'; import NothingFound from 'ts/components/NothingFound';

View file

@ -9,7 +9,7 @@ import PageWrapper from 'ts/components/Page/wrapper';
import BarChart from 'ts/components/BarChart'; import BarChart from 'ts/components/BarChart';
import DayInfo from 'ts/components/DayInfo'; import DayInfo from 'ts/components/DayInfo';
import Title from 'ts/components/Title'; import Title from 'ts/components/Title';
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants'; import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
import localization from 'ts/helpers/Localization'; import localization from 'ts/helpers/Localization';
interface ICommitsProps { interface ICommitsProps {

View file

@ -5,7 +5,7 @@ import NothingFound from 'ts/components/NothingFound';
import PageWrapper from 'ts/components/Page/wrapper'; import PageWrapper from 'ts/components/Page/wrapper';
import CandyChart from 'ts/components/CandyChart'; import CandyChart from 'ts/components/CandyChart';
import Title from 'ts/components/Title'; import Title from 'ts/components/Title';
import RECOMMENDATION_TYPES from 'ts/helpers/Recommendations/contstants'; import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
interface IPopularWordsProps { interface IPopularWordsProps {
statistic: any[]; statistic: any[];

View file

@ -142,6 +142,12 @@ export const TEAM = [
title: 'sidebar.team.words', title: 'sidebar.team.words',
icon: './assets/menu/team_words.svg', icon: './assets/menu/team_words.svg',
}, },
{
id: 'recommendations',
link: '/team/recommendations',
title: 'sidebar.team.recommendations',
icon: './assets/menu/building.svg',
},
{ {
id: 'building', id: 'building',
link: '/team/building', link: '/team/building',

View file

@ -0,0 +1,85 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
import CardForPrint from 'ts/components/Recommendations/components/CardForPrint';
import NothingFound from 'ts/components/NothingFound';
import Title from 'ts/components/Title';
import IHashMap from 'ts/interfaces/HashMap';
import dataGripStore from 'ts/store/DataGrip';
import { RECOMMENDATION_TYPES } from 'ts/helpers/Recommendations/helpers/contstants';
import style from '../styles/recommendations.module.scss';
function getAll(recommendations: IHashMap<any>) {
return Object.values(recommendations)
.flat(1)
.filter((item: any) => item);
}
function getGroups(recommendations: any[]) {
return recommendations.reduce((acc: IHashMap<any>, item: any) => {
if (!acc[item.type]) {
acc[item.type] = [];
}
acc[item.type].push(item);
return acc;
}, {});
}
interface BlockProps {
title: string;
recommendations: any[];
}
function Block({
title,
recommendations,
}: BlockProps): React.ReactElement | null {
const cards = recommendations.map((recommendation: any) => (
<CardForPrint
key={recommendation.description}
recommendation={recommendation}
/>
));
if (!cards.length) return null;
return (
<>
<Title title={title}/>
<div className={style.recommendations_page}>
{cards}
</div>
</>
);
}
const RecommendationsPage = observer((): React.ReactElement => {
const all = getAll(dataGripStore.dataGrip.recommendations.team);
if (!all?.length) return (<NothingFound/>);
const groups = getGroups(all);
return (
<>
<Block
title="page.team.recommendations.alert"
recommendations={groups[RECOMMENDATION_TYPES.ALERT]}
/>
<Block
title="page.team.recommendations.warning"
recommendations={groups[RECOMMENDATION_TYPES.WARNING]}
/>
<Block
title="page.team.recommendations.fact"
recommendations={groups[RECOMMENDATION_TYPES.FACT]}
/>
<Block
title="page.team.recommendations.info"
recommendations={groups[RECOMMENDATION_TYPES.INFO]}
/>
</>
);
});
export default RecommendationsPage;

View file

@ -28,6 +28,7 @@ import Print from './components/Print';
import Release from './components/Release'; import Release from './components/Release';
import Refactor from './components/Refactor'; import Refactor from './components/Refactor';
import Department from './components/Department'; import Department from './components/Department';
import RecommendationsPage from './components/Recommendations';
interface ViewProps { interface ViewProps {
page?: string; page?: string;
@ -61,6 +62,7 @@ const View = observer(({ page }: ViewProps): React.ReactElement => {
if (page === 'tasks') return <Tasks/>; if (page === 'tasks') return <Tasks/>;
if (page === 'refactor') return <Refactor/>; if (page === 'refactor') return <Refactor/>;
if (page === 'department') return <Department/>; if (page === 'department') return <Department/>;
if (page === 'recommendations') return <RecommendationsPage/>;
return <Total/>; return <Total/>;
}); });

View file

@ -0,0 +1,18 @@
@import 'src/styles/variables';
.recommendations_page {
column-count: 3;
margin: 0 0 var(--space-xxl);
}
@media (max-width: 1500px) {
.recommendations_page {
column-count: 2;
}
}
@media (max-width: 800px) {
.recommendations_page {
column-count: 1;
}
}

View file

@ -36,6 +36,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: Die Einstellungen § sidebar.team.settings: Die Einstellungen
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: Allgemeine Informationen § sidebar.person.total: Allgemeine Informationen
§ sidebar.person.money: Arbeitskosten § sidebar.person.money: Arbeitskosten
§ sidebar.person.speed: Geschwindigkeit § sidebar.person.speed: Geschwindigkeit

View file

@ -267,6 +267,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: Photo § page.person.print.photo.title: Photo
§ page.person.print.photo.description: space for a photo § page.person.print.photo.description: space for a photo
§ page.person.total.title: Main characteristics § page.person.total.title: Main characteristics

View file

@ -34,6 +34,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: Settings § sidebar.team.settings: Settings
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: Common info § sidebar.person.total: Common info
§ sidebar.person.money: Work cost § sidebar.person.money: Work cost
§ sidebar.person.speed: Speed § sidebar.person.speed: Speed

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: Photo § page.person.print.photo.title: Photo
§ page.person.print.photo.description: space for a photo § page.person.print.photo.description: space for a photo
§ page.person.total.title: Main characteristics § page.person.total.title: Main characteristics

View file

@ -36,6 +36,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: Ajustes § sidebar.team.settings: Ajustes
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: Información general § sidebar.person.total: Información general
§ sidebar.person.money: Costo del trabajo § sidebar.person.money: Costo del trabajo
§ sidebar.person.speed: Velocidad § sidebar.person.speed: Velocidad

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: Photo § page.person.print.photo.title: Photo
§ page.person.print.photo.description: a place for a photo § page.person.print.photo.description: a place for a photo
§ page.person.total.title: Main Features § page.person.total.title: Main Features

View file

@ -34,6 +34,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: Réglages § sidebar.team.settings: Réglages
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: Informations générales § sidebar.person.total: Informations générales
§ sidebar.person.money: Coût des travaux § sidebar.person.money: Coût des travaux
§ sidebar.person.speed: Vitesse § sidebar.person.speed: Vitesse

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: Photo § page.person.print.photo.title: Photo
§ page.person.print.photo.description: place à la photographie § page.person.print.photo.description: place à la photographie
§ page.person.total.title: Caractéristiques de base § page.person.total.title: Caractéristiques de base

View file

@ -35,6 +35,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: 設定 § sidebar.team.settings: 設定
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: 一般的な情報 § sidebar.person.total: 一般的な情報
§ sidebar.person.money: 仕事のコスト § sidebar.person.money: 仕事のコスト
§ sidebar.person.speed: スピード § sidebar.person.speed: スピード

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: Photo § page.person.print.photo.title: Photo
§ page.person.print.photo.description: space for a photo § page.person.print.photo.description: space for a photo
§ page.person.total.title: Main characteristics § page.person.total.title: Main characteristics

View file

@ -34,6 +34,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: 위치 § sidebar.team.country: 위치
§ sidebar.team.settings: 설정 § sidebar.team.settings: 설정
§ sidebar.team.recommendations: 권장
§ sidebar.team.building: Games
§ sidebar.person.total: 일반 § sidebar.person.total: 일반
§ sidebar.person.money: 작업 § sidebar.person.money: 작업
§ sidebar.person.speed: 속도 § sidebar.person.speed: 속도

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: 사진 § page.person.print.photo.title: 사진
§ page.person.print.photo.description: 사진 § page.person.print.photo.description: 사진
§ page.person.total.title: 주요 § page.person.total.title: 주요

View file

@ -35,6 +35,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: Sintonização § sidebar.team.settings: Sintonização
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: Informação geral § sidebar.person.total: Informação geral
§ sidebar.person.money: Custo do trabalho § sidebar.person.money: Custo do trabalho
§ sidebar.person.speed: Velocidade § sidebar.person.speed: Velocidade

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: Photo § page.person.print.photo.title: Photo
§ page.person.print.photo.description: space for a photo § page.person.print.photo.description: space for a photo
§ page.person.total.title: Main characteristics § page.person.total.title: Main characteristics

View file

@ -34,6 +34,7 @@ export default `
§ sidebar.team.department: Отделы § sidebar.team.department: Отделы
§ sidebar.team.country: Местоположение § sidebar.team.country: Местоположение
§ sidebar.team.settings: Настройки § sidebar.team.settings: Настройки
§ sidebar.team.recommendations: Рекомендации и факты
§ sidebar.team.building: Мини игры § sidebar.team.building: Мини игры
§ sidebar.person.total: Общая информация § sidebar.person.total: Общая информация
§ sidebar.person.money: Стоимость работы § sidebar.person.money: Стоимость работы

View file

@ -269,6 +269,10 @@ export default `
§ page.team.building.quiz.result2.description: Правильных ответов от 40% до 70%. Вы имеете хорошее представление о вашей команде, но можете узнать её лучше. Ознакомьтесь с данными в соседних разделах и попробуйте снова! § page.team.building.quiz.result2.description: Правильных ответов от 40% до 70%. Вы имеете хорошее представление о вашей команде, но можете узнать её лучше. Ознакомьтесь с данными в соседних разделах и попробуйте снова!
§ page.team.building.quiz.result3.title: Отлично § page.team.building.quiz.result3.title: Отлично
§ page.team.building.quiz.result3.description: Правильных ответов больше 70%. Вы отлично знаете статистику по вашей команде! § page.team.building.quiz.result3.description: Правильных ответов больше 70%. Вы отлично знаете статистику по вашей команде!
§ page.team.recommendations.alert: Проблемы
§ page.team.recommendations.warning: Обратить внимание
§ page.team.recommendations.fact: Факты о проекте
§ page.team.recommendations.info: Общие советы
§ page.person.print.photo.title: Фотография § page.person.print.photo.title: Фотография
§ page.person.print.photo.description: место для фотографии § page.person.print.photo.description: место для фотографии
§ page.person.total.title: Основные характеристики § page.person.total.title: Основные характеристики

View file

@ -35,6 +35,8 @@ export default `
§ sidebar.team.department: Departments § sidebar.team.department: Departments
§ sidebar.team.country: Locations § sidebar.team.country: Locations
§ sidebar.team.settings: 设置 § sidebar.team.settings: 设置
§ sidebar.team.recommendations: Recommendations and facts
§ sidebar.team.building: Games
§ sidebar.person.total: 般资料 § sidebar.person.total: 般资料
§ sidebar.person.money: 工作的成本 § sidebar.person.money: 工作的成本
§ sidebar.person.speed: 速度 § sidebar.person.speed: 速度

View file

@ -264,6 +264,10 @@ export default `
§ page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again! § page.team.building.quiz.result2.description: The correct answers range from 40% to 70%. You have a good idea of your team, but you can get to know it better. Check out the data in the adjacent sections and try again!
§ page.team.building.quiz.result3.title: Great § page.team.building.quiz.result3.title: Great
§ page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well! § page.team.building.quiz.result3.description: There are more than 70% correct answers. You know the statistics on your team perfectly well!
§ page.team.recommendations.alert: Warning
§ page.team.recommendations.warning: Pay attention
§ page.team.recommendations.fact: Facts about the project
§ page.team.recommendations.info: General tips
§ page.person.print.photo.title: 照片 § page.person.print.photo.title: 照片
§ page.person.print.photo.description: 拍照的地方 § page.person.print.photo.description: 拍照的地方
§ page.person.total.title: 主要特点 § page.person.total.title: 主要特点