This commit is contained in:
bakhirev 2024-10-21 16:12:21 +03:00
parent 7b9e41d928
commit 2c4528c941
25 changed files with 155 additions and 84 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

@ -14,6 +14,7 @@
&_item {
display: inline-block;
width: 10px;
min-width: 1px;
vertical-align: bottom;
cursor: pointer;

View file

@ -6,13 +6,12 @@ function getWidth(value: number, max: number) {
return Math.round(value * (100 / max));
}
function getFormattedOther(other: any[], options: any): ISubLine {
let width = 0;
function getFormattedOther(other: any[], normalWidth: number, options: any): ISubLine {
let value = 0;
const width = 100 - normalWidth;
const titles: string[] = [];
other.forEach((field: any) => {
width += field.width;
value += field.value;
if (field.title) titles.push(field.title);
});
@ -36,6 +35,7 @@ export default function getSubLines(
const normal: ISubLine[] = [];
const other: ISubLine[] = [];
let normalWidth = 0;
list.forEach(([title, value]: any) => {
const width = getWidth(value || 0, currentMax);
const field: ISubLine = { title, value, width };
@ -43,6 +43,7 @@ export default function getSubLines(
allItems.push(field);
if (width >= options.limit) {
normal.push(field);
normalWidth += width;
} else {
other.push(field);
}
@ -50,6 +51,6 @@ export default function getSubLines(
if (other.length === 0) return normal;
if (other.length === 1) return allItems;
return [...normal, getFormattedOther(other, options)]
return [...normal, getFormattedOther(other, normalWidth, options)]
.filter((item: any) => item.width > 1);
}

View file

@ -68,7 +68,7 @@
&_item {
display: block;
width: 100%;
margin: 0 0 24px 0;
margin: 0;
}
&_white {
display: block;
@ -76,7 +76,7 @@
}
.main_wrapper_item + .main_wrapper_item {
display: block;
margin: 0 0 24px 0;
margin: 0;
}
}

View file

@ -1,4 +1,5 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { IOptions, ISubLine } from 'ts/components/LineChart/interfaces';
import { getSegmentPath } from './helpers';
@ -17,16 +18,23 @@ function PieSVG({
parts,
center,
}: IPieSVGProps): React.ReactElement | null {
const { t } = useTranslation();
const centerRadius = 49 * ((center || 72) / 100);
const suffix = options.suffix ? t(options.suffix) : '';
let prev = 0;
const paths = parts.map((item: ISubLine) => {
const fill = options.color.get(item.title).first;
const angle = 360 * item.width / 100;
const next = Math.min(prev + angle, 360);
const formattedAngle = angle === 360 ? 359.9 : angle;
const next = Math.min(prev + formattedAngle, 360);
const d = getSegmentPath(50, 50, centerRadius, 50, prev + ROTATE, next + ROTATE);
prev += angle;
const formattedValue = item.value && suffix
? ` (${item.value || ''} ${suffix})`
: '';
return (
<path
key={item.title}
@ -35,7 +43,7 @@ function PieSVG({
className={style.pie_svg_sector}
>
<title>
{`${item.title} ${item.description || ''}`}
{`${t(item.title)}${formattedValue}`}
</title>
</path>
);

View file

@ -195,7 +195,8 @@ export default class DataGripByAuthor {
const daysWorkedLosses = workDays + (lazyDays > 0 ? lazyDays : 0);
const percentWork = workDays * 100 / daysWorkedLosses;
const isStaff = daysWorkedLosses < 20 || (percentWork < 15);
const isBot = (/[^a-z]bot[^a-z]/gim).test(dot.author);
const isStaff = daysWorkedLosses < 20 || (percentWork < 15) || isBot;
const authorInfo = {
...dot,

View file

@ -21,7 +21,7 @@ export default class DataGripByPR {
if (!commit.prId) return;
const statistic = this.pr.get(commit.prId);
if (statistic) {
console.log('PR error');
console.log('Parsing error. PR already exist.');
} else {
this.#addCommitByPR(commit);
}

View file

@ -3,7 +3,7 @@ import IHashMap from 'ts/interfaces/HashMap';
import { getTypeAndScope, getTask, getTaskNumber } from './getTypeAndScope';
import getInfoFromNameAndEmail from './getCompany';
import { getGithubPrInfo } from './getMergeInfo';
import { getGithubPrInfo, getGitlabPrInfo } from './getMergeInfo';
import getCountryByTimeZone from './getCountryByTimeZone';
const MASTER_BRANCH = {
@ -148,13 +148,12 @@ export default function getCommitInfo(
} else if (isGitlabPR) {
commitType = COMMIT_TYPE.PR_GITLAB;
[, branch, toBranch ] = message
.replace(/'/gim, '')
.replace(/(Merge\sbranch\s)|(\sinto\s)/gim, ',')
.split(',');
[branch, toBranch] = getGitlabPrInfo(message);
if (toBranch && MASTER_BRANCH[toBranch]) {
task = getTask(branch) || `#${getTaskNumber(branch)}`;
prId = task;
task = getTask(branch);
taskNumber = getTaskNumber(branch);
prId = `#${taskNumber}-${Math.random()}`;
if (!task && taskNumber) task = `#${taskNumber}`;
}
}
taskNumber = getTaskNumber(task);

View file

@ -1,9 +1,10 @@
// "Merge pull request #3 in repository from TASK-123-add-profile to master"
// "Merge pull request #3 from facebook/compiler into master"
// "Merge pull request #3 from facebook/compiler"
/* "Merge pull request #3 in repository from TASK-123-add-profile to master"
* "Merge pull request #3 from facebook/compiler into master"
* "Merge pull request #3 from facebook/compiler"
*/
export function getGithubPrInfo(text: string) {
const json = (text || '')
.replace(/"/gim, '')
.replace(/["']+/gim, '')
.replace('#', '#": "')
.replace(' in ', '", "in": "')
.replace(' from ', '", "from": "')
@ -12,3 +13,12 @@ export function getGithubPrInfo(text: string) {
const data = JSON.parse(`{"${json}"}`);
return [data['Merge pull request #'], data.in, data.from, data.to];
}
/* "Merge branch 'J123456' into 'develop'" */
export function getGitlabPrInfo(text: string) {
const prefix = text.substring(14, text.length - 1);
const index = prefix.indexOf("'");
const branch = prefix.substring(0, index);
const toBranch = prefix.substring(index + 8);
return [branch, toBranch];
}

View file

@ -16,6 +16,7 @@ interface IChangesProps {
}
function Changes({ statistic }: IChangesProps) {
const files = dataGripStore.fileGrip.files.list;
const maxData = statistic.changesByTimestampCounter.maxData;
const [selected, setSelected] = useState<any>(maxData);
@ -26,7 +27,8 @@ function Changes({ statistic }: IChangesProps) {
value: dot.addedAndChanges,
meta: dot,
}));
if (!dots?.length) return (<NothingFound />);
if (!dots?.length || !files?.length) return (<NothingFound />);
const [fullDay, shortDay] = getDateByTimestamp(maxData.timestamp);
const recommendations = [

View file

@ -32,6 +32,7 @@ function Countries({ response, updateSort, rowsForExcel, mode }: CompaniesProps)
updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
fullScreenMode="countries"
>
<Column
isFixed

View file

@ -31,6 +31,7 @@ function Travel({ response, updateSort, rowsForExcel, mode }: TravelProps) {
updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
fullScreenMode="travel"
>
<Column
isFixed

View file

@ -15,6 +15,7 @@ import Countries from './components/Countries';
import CountryCharts from './components/Charts';
import TimeZoneMap from 'ts/components/TimeZoneMap';
import PageWrapper from 'ts/components/Page/Box';
import fullScreen from 'ts/store/FullScreen';
import Travel from './components/Travel';
@ -26,17 +27,27 @@ const Country = observer(({
const travel = authors.filter((dot: any) => dot?.country?.length)
.sort((a: any, b: any) => b?.country?.length - a?.country?.length);
const canShowByCountries = (!fullScreen.isOpen || fullScreen.mode === 'countries');
const canShowByTravel = (!fullScreen.isOpen || fullScreen.mode === 'travel') && travel.length;
if (!countryRows?.length) {
return mode !== 'print' ? (<NothingFound/>) : null;
}
return (
<>
{!fullScreen.isOpen && (
<>
<PageWrapper>
<Title title="page.team.country.byTimezone"/>
<TimeZoneMap authors={authors}/>
</PageWrapper>
<CountryCharts/>
</>
)}
{canShowByCountries ? (
<>
<Title title="page.team.country.table.title"/>
<DataLoader
to="response"
@ -51,7 +62,10 @@ const Country = observer(({
/>
<Pagination/>
</DataLoader>
{travel.length ? (
</>
) : null}
{canShowByTravel ? (
<>
<Title title="page.team.country.travel.title"/>
<DataLoader

View file

@ -57,7 +57,6 @@ function View({ response, updateSort, rowsForExcel, mode }: CompaniesProps) {
.reverse()
.map((taskId: any) => dataGripStore.dataGrip.tasks.statisticByName.get(taskId))
.filter(v => v);
console.log(content);
return (
<Tasks // @ts-ignore
response={{ content }}

View file

@ -16,11 +16,45 @@ import PageWrapper from 'ts/components/Page/wrapper';
import Filters from './Filters';
import View from './View';
interface IFilters {
user: number;
company: number;
}
function getContentByFilters(content: any, filters: IFilters) {
if (filters.user) {
const author = dataGripStore.dataGrip.author.statistic?.[filters.user]?.author;
return author
? content.filter((task: any) => {
return task.author === author || task.authors?.[author];
})
: content;
}
if (filters.company) {
const employments = dataGripStore.dataGrip.company.statistic?.[filters.company].employments;
const employmentInCompany = new Map(employments.map((key: string) => [key, true]));
return employments?.length
? content.filter((task: any) => employmentInCompany.has(task.author))
: content;
}
return content;
}
const Tasks = observer(({
mode,
}: ICommonPageProps): React.ReactElement | null => {
const rows = dataGripStore.dataGrip.tasks.statistic;
const [filters, setFilters] = useState<any>({ user: 0, company: 0 });
const content = getContentByFilters(rows, filters);
const hash = [
mode,
dataGripStore.hash,
filters.user,
filters.company,
content.length,
].join('.');
if (!rows?.length) return mode !== 'print' ? (<NothingFound />) : null;
@ -36,9 +70,9 @@ const Tasks = observer(({
<DataLoader
to="response"
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
content: rows, pagination, sort, mode,
content, pagination, sort, mode,
})}
watch={`${mode}${dataGripStore.hash}`}
watch={hash}
>
<View
mode={mode}

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit

View file

@ -1,28 +1,28 @@
export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Hide personal data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR
§ page.settings.user.title: Individual settings
§ page.settings.user.notFound: No individual settings. Data for all employees are calculated based on common parameters.
§ page.settings.user.subTitle: Addendum to employment contract $1
§ page.settings.user.from: Start date
§ page.settings.mailmap: .mailmap example
§ page.settings.common.title: General salary data
§ page.settings.common.type.title: Project work type
§ page.settings.common.type.full: Full-time employment
§ page.settings.common.type.part: Project work
§ page.settings.common.salary: Monthly salary in USD (US dollar, $)
§ page.settings.common.currency: Currency for view
§ page.settings.common.workDaysInYear: Number of working days in a year
§ page.settings.common.vacationDaysInYear: Number of vacation days in a year
§ page.settings.common.workDaysInWeek: Workdays
§ page.settings.form.save: Save
§ page.settings.form.cancel: Cancel
§ page.settings.form.remove: Remove
§ page.settings.form.addEmployee: Add an employee
§ page.settings.form.addContract: Add an employment contract
§ page.settings.document.title: Anzeigeeinstellungen
§ page.settings.document.name: Seitentitel
§ page.settings.document.language: Sprache der benutzeroberfläche
§ page.settings.document.depersonalize: Persönliche daten verstecken
§ page.settings.links.title: Link-Präfixe
§ page.settings.links.task: Für Aufgabennummern
§ page.settings.links.pr: Für PR
§ page.settings.user.title: Individuelle einstellungen
§ page.settings.user.notFound: Keine individuellen Einstellungen. Daten für alle Mitarbeiter werden anhand allgemeiner Parameter berechnet.
§ page.settings.user.subTitle: Zusatz zum arbeitsvertrag . $1
§ page.settings.user.from: Startdatum
§ page.settings.mailmap: Beispiel .mailmap
§ page.settings.common.title: Allgemeine Gehaltsdaten
§ page.settings.common.type.title: Art der projektarbeit
§ page.settings.common.type.full: Vollzeitbeschäftigung
§ page.settings.common.type.part: Projektarbeit
§ page.settings.common.salary: Monatliches gehalt in USD (US-Dollar, $)
§ page.settings.common.currency: Währung zur ansicht
§ page.settings.common.workDaysInYear: Anzahl der arbeitstage im Jahr
§ page.settings.common.vacationDaysInYear: Anzahl der urlaubstage im Jahr
§ page.settings.common.workDaysInWeek: Arbeitstage
§ page.settings.form.save: Speichern
§ page.settings.form.cancel: Abbrechen
§ page.settings.form.remove: Entfernen
§ page.settings.form.addEmployee: Mitarbeiter hinzufügen
§ page.settings.form.addContract: Arbeitsvertrag hinzufügen
`;

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit

View file

@ -126,7 +126,7 @@ export default `
§ page.team.company.employments.title: По количеству сотрудников
§ page.team.company.employments.item: сотрудников
§ page.team.company.daysChart.title: По длительности контракта
§ page.team.company.daysChart.item: дней
§ page.team.company.daysChart.item: компаний
§ page.team.company.active.yes: активна
§ page.team.company.active.no: контракт истёк
§ page.team.country.byTimezone: По времени последнего коммита

View file

@ -121,7 +121,7 @@ export default `
§ page.team.company.employments.title: By number of employees
§ page.team.company.employments.item: employments
§ page.team.company.daysChart.title: By duration of the contract
§ page.team.company.daysChart.item: days
§ page.team.company.daysChart.item: companies
§ page.team.company.active.yes: active
§ page.team.company.active.no: contract has expired
§ page.team.country.byTimezone: By the time of the last commit