mirror of
https://github.com/bakhirev/assayo.git
synced 2024-11-16 08:11:40 +00:00
update
This commit is contained in:
parent
7b9e41d928
commit
2c4528c941
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -14,6 +14,7 @@
|
|||
&_item {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
min-width: 1px;
|
||||
|
||||
vertical-align: bottom;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,32 +27,45 @@ 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 (
|
||||
<>
|
||||
<PageWrapper>
|
||||
<Title title="page.team.country.byTimezone"/>
|
||||
<TimeZoneMap authors={authors}/>
|
||||
</PageWrapper>
|
||||
<CountryCharts/>
|
||||
<Title title="page.team.country.table.title"/>
|
||||
<DataLoader
|
||||
to="response"
|
||||
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
|
||||
content: countryRows, pagination, sort, mode,
|
||||
})}
|
||||
watch={`${mode}${dataGripStore.hash}`}
|
||||
>
|
||||
<Countries
|
||||
mode={mode}
|
||||
rowsForExcel={countryRows}
|
||||
/>
|
||||
<Pagination/>
|
||||
</DataLoader>
|
||||
{travel.length ? (
|
||||
{!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"
|
||||
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
|
||||
content: countryRows, pagination, sort, mode,
|
||||
})}
|
||||
watch={`${mode}${dataGripStore.hash}`}
|
||||
>
|
||||
<Countries
|
||||
mode={mode}
|
||||
rowsForExcel={countryRows}
|
||||
/>
|
||||
<Pagination/>
|
||||
</DataLoader>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{canShowByTravel ? (
|
||||
<>
|
||||
<Title title="page.team.country.travel.title"/>
|
||||
<DataLoader
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
`;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: По времени последнего коммита
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue