Вывод всех метрик на виджет на дашборде
This commit is contained in:
parent
d8f56b8c34
commit
e4fb067ea9
3 changed files with 449 additions and 8 deletions
|
|
@ -4,6 +4,7 @@ import { observer } from 'mobx-react-lite';
|
||||||
import { DebugInfo } from '../../misc-components/debug-info';
|
import { DebugInfo } from '../../misc-components/debug-info';
|
||||||
import { Instance, onSnapshot, types } from 'mobx-state-tree';
|
import { Instance, onSnapshot, types } from 'mobx-state-tree';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { text2id } from '../../utils/text-to-id';
|
||||||
|
|
||||||
export const DailyEccmV2Data = types.model({
|
export const DailyEccmV2Data = types.model({
|
||||||
id: types.string,
|
id: types.string,
|
||||||
|
|
@ -29,7 +30,7 @@ export const DailyEccmV2Store = types
|
||||||
export type IDailyEccmV2Store = Instance<typeof DailyEccmV2Store>;
|
export type IDailyEccmV2Store = Instance<typeof DailyEccmV2Store>;
|
||||||
|
|
||||||
const SimpleCounterViewComponent = (props: {
|
const SimpleCounterViewComponent = (props: {
|
||||||
key?: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
count: number;
|
count: number;
|
||||||
issueIds?: number[];
|
issueIds?: number[];
|
||||||
|
|
@ -38,41 +39,178 @@ const SimpleCounterViewComponent = (props: {
|
||||||
}): JSX.Element => {
|
}): JSX.Element => {
|
||||||
let detailsHintComponent = <></>;
|
let detailsHintComponent = <></>;
|
||||||
if (props.details) {
|
if (props.details) {
|
||||||
const parentKey = props.key
|
const parentKey = props.id
|
||||||
? props.key
|
? props.id
|
||||||
: `simple-counter-component-${uuidv4()}`;
|
: `simple-counter-component-${uuidv4()}`;
|
||||||
const detailsKey = `${parentKey}-details`;
|
const detailsKey = `${parentKey}-details`;
|
||||||
detailsHintComponent = (
|
detailsHintComponent = (
|
||||||
<DetailsHintViewComponent
|
<DetailsHintViewComponent
|
||||||
key={detailsKey}
|
key={detailsKey}
|
||||||
|
id={detailsKey}
|
||||||
mainLabel={props.detailsLabel ?? 'Details'}
|
mainLabel={props.detailsLabel ?? 'Details'}
|
||||||
details={props.details}
|
details={props.details}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<span key={props.key}>
|
<span key={props.id}>
|
||||||
{props.label}: {props.count} {detailsHintComponent}
|
{props.label}: {props.count} {detailsHintComponent}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DetailsHintViewComponent = (props: {
|
const DetailsHintViewComponent = (props: {
|
||||||
key?: string;
|
id: string;
|
||||||
mainLabel: string;
|
mainLabel: string;
|
||||||
details: Record<string, number>;
|
details: Record<string, number>;
|
||||||
}): JSX.Element => {
|
}): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<span key={props.key} style={{ marginLeft: '10px', color: 'lightgray' }}>
|
<span key={props.id} style={{ marginLeft: '10px', color: 'lightgray' }}>
|
||||||
({props.mainLabel}: {JSON.stringify(props.details)})
|
({props.mainLabel}: {JSON.stringify(props.details)})
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ChangesCounterTotalViewComponent = (props: {
|
||||||
|
id: string;
|
||||||
|
data: Record<string, any>;
|
||||||
|
}): JSX.Element => {
|
||||||
|
if (!props.id) return <></>;
|
||||||
|
const titles: Record<string, string> = {
|
||||||
|
byIssue: 'По задачам',
|
||||||
|
byStatus: 'По статусам',
|
||||||
|
byVersion: 'По версиям',
|
||||||
|
byUserName: 'По работникам',
|
||||||
|
};
|
||||||
|
const groups = Object.keys(titles);
|
||||||
|
const details: JSX.Element[] = [];
|
||||||
|
groups.forEach((groupName) => {
|
||||||
|
const groupKey = `${props.id}-details-${groupName}`;
|
||||||
|
const groupTitle = titles[groupName];
|
||||||
|
const groupData = props.data[groupName];
|
||||||
|
const cmp = (
|
||||||
|
<ChangesCounterListViewComponent
|
||||||
|
key={groupKey}
|
||||||
|
id={groupKey}
|
||||||
|
title={groupTitle}
|
||||||
|
data={groupData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
details.push(cmp);
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
<li>Итого изменений: {props.data?.totalChanges ?? 0}</li>
|
||||||
|
<li>Итого комментариев: {props.data?.totalComments ?? 0}</li>
|
||||||
|
{details}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChangesCounterListViewComponent = (props: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
data?: Record<string, { changes: number; comments: number }>;
|
||||||
|
}): JSX.Element => {
|
||||||
|
if (!props.data || !props.id) return <></>;
|
||||||
|
const dataKeys = Object.keys(props.data ?? {});
|
||||||
|
if (!dataKeys || dataKeys.length <= 0) return <></>;
|
||||||
|
|
||||||
|
const res: JSX.Element[] = [];
|
||||||
|
|
||||||
|
dataKeys.forEach((itemKey) => {
|
||||||
|
const itemData = props.data && props.data[itemKey];
|
||||||
|
if (!itemData) return;
|
||||||
|
const key = `${props.id}-${text2id(props.title)}-${text2id(itemKey)}`;
|
||||||
|
res.push(
|
||||||
|
<li key={`${key}-li`}>
|
||||||
|
<ChangesCounterItemViewComponent
|
||||||
|
key={key}
|
||||||
|
id={key}
|
||||||
|
label={itemKey}
|
||||||
|
type={itemKey === 'byIssue' ? 'issue' : 'other'}
|
||||||
|
changes={itemData.changes}
|
||||||
|
comments={itemData.comments}
|
||||||
|
/>
|
||||||
|
</li>,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{props.title}:<ul>{res}</ul>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChangesCounterItemViewComponent = (props: {
|
||||||
|
id: string;
|
||||||
|
type: 'issue' | 'other';
|
||||||
|
label: string;
|
||||||
|
changes: number;
|
||||||
|
comments: number;
|
||||||
|
}): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<span key={props.id}>
|
||||||
|
<span>
|
||||||
|
{props.type == 'issue' ? '#' : ''}
|
||||||
|
{props.label}:
|
||||||
|
</span>
|
||||||
|
<span>все изменения - {props.changes}</span>,
|
||||||
|
<span>комментарии - {props.comments}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const VerySimpleCounterViewComponent = (props: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
value: number | string;
|
||||||
|
details?: any;
|
||||||
|
}): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{props.title}:
|
||||||
|
<span style={{ marginLeft: '10px' }}> {props.value}</span>
|
||||||
|
<span style={{ marginLeft: '20px', color: 'lightgray' }}>
|
||||||
|
{props.details ? JSON.stringify(props.details) : ''}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const VerySimpleCounterListViewComponent = (props: {
|
||||||
|
id: string;
|
||||||
|
data: { title: string; value: number | string; details?: any }[];
|
||||||
|
}): JSX.Element => {
|
||||||
|
const items: JSX.Element[] = [];
|
||||||
|
props.data.forEach((item) => {
|
||||||
|
const itemId = `${props.id}-${text2id(item.title)}`;
|
||||||
|
items.push(
|
||||||
|
<VerySimpleCounterViewComponent
|
||||||
|
key={itemId}
|
||||||
|
id={itemId}
|
||||||
|
title={item.title}
|
||||||
|
value={item.value}
|
||||||
|
details={item.details}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<ul key={props.id}>
|
||||||
|
{items.map((item) => (
|
||||||
|
<li key={item.props.id + '-li'}>{item}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const DailyEccmV2 = observer(
|
export const DailyEccmV2 = observer(
|
||||||
(props: { store: IDailyEccmV2Store }): JSX.Element => {
|
(props: { store: IDailyEccmV2Store }): JSX.Element => {
|
||||||
const dashboardId = props.store?.data?.dashboardId;
|
const dashboardId = props.store?.data?.dashboardId;
|
||||||
const widgetId = props.store?.data?.widgetId;
|
const widgetId = props.store?.data?.widgetId;
|
||||||
|
if (!dashboardId || !widgetId) return <></>;
|
||||||
|
|
||||||
const keyPrefix = `dashboard-${dashboardId}-widget-${widgetId}`;
|
const keyPrefix = `dashboard-${dashboardId}-widget-${widgetId}`;
|
||||||
|
|
||||||
const issuesByStatusCount: Record<string, any> =
|
const issuesByStatusCount: Record<string, any> =
|
||||||
|
|
@ -81,6 +219,233 @@ export const DailyEccmV2 = observer(
|
||||||
props.store?.data?.issuesMetrics?.issuesByVersionsCount ?? {};
|
props.store?.data?.issuesMetrics?.issuesByVersionsCount ?? {};
|
||||||
const issuesByUsername: Record<string, any> =
|
const issuesByUsername: Record<string, any> =
|
||||||
props.store?.data?.issuesMetrics?.issuesByUsername ?? {};
|
props.store?.data?.issuesMetrics?.issuesByUsername ?? {};
|
||||||
|
const changesCount: Record<string, any> =
|
||||||
|
props.store?.data?.issuesMetrics?.changesCount ?? {};
|
||||||
|
|
||||||
|
const otherData: {
|
||||||
|
title: string;
|
||||||
|
value: number | string;
|
||||||
|
details?: any;
|
||||||
|
}[] = [];
|
||||||
|
|
||||||
|
// ШАГ 1. Количество задач по статусам
|
||||||
|
const issuesByStatusCount2 =
|
||||||
|
props.store?.data?.issuesMetrics?.issuesByStatusCount ?? {};
|
||||||
|
const issuesByStatusCount2Prefix = `Счётчики с количеством задач по статусам`;
|
||||||
|
Object.keys(issuesByStatusCount2).forEach((statusName) => {
|
||||||
|
const statusData = issuesByStatusCount2[statusName];
|
||||||
|
if (statusData) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${issuesByStatusCount2Prefix} / ${statusName} / Количество задач`,
|
||||||
|
value: statusData.count,
|
||||||
|
details: {
|
||||||
|
issueIds: statusData.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const byVersions = statusData.byVersion;
|
||||||
|
const byVersionsPrefix = `${issuesByStatusCount2Prefix} / ${statusName} / По версиям`;
|
||||||
|
if (byVersions) {
|
||||||
|
Object.keys(byVersions).forEach((versionName) => {
|
||||||
|
otherData.push({
|
||||||
|
title: `${byVersionsPrefix} / ${versionName} / Количество задач`,
|
||||||
|
value: byVersions[versionName].count,
|
||||||
|
details: {
|
||||||
|
issueIds: byVersions[versionName].issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ШАГ 2. Количество задач по версиям
|
||||||
|
const issuesByVersionCount2 =
|
||||||
|
props.store?.data?.issuesMetrics?.issuesByVersionsCount ?? {};
|
||||||
|
const issuesByVersionCount2Prefix = 'Счётчики по версиям';
|
||||||
|
Object.keys(issuesByVersionCount2).forEach((versionName) => {
|
||||||
|
const versionData = issuesByVersionCount2[versionName];
|
||||||
|
if (versionData) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${issuesByVersionCount2Prefix} / ${versionName} / Количество задач`,
|
||||||
|
value: versionData.count,
|
||||||
|
details: {
|
||||||
|
issueIds: versionData.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const byStatuses = versionData.byStatus;
|
||||||
|
const byStatusesPrefix = `${issuesByVersionCount2Prefix} / ${versionName} / По статусам`;
|
||||||
|
if (byStatuses) {
|
||||||
|
Object.keys(byStatuses).forEach((statusName) => {
|
||||||
|
otherData.push({
|
||||||
|
title: `${byStatusesPrefix} / ${statusName} / Количество задач`,
|
||||||
|
value: byStatuses[statusName].count,
|
||||||
|
details: {
|
||||||
|
issueIds: byStatuses[statusName].issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ШАГ 3. Количество задач по работникам
|
||||||
|
const issuesByUsername2 =
|
||||||
|
props.store?.data?.issuesMetrics?.issuesByUsername ?? {};
|
||||||
|
const issuesByUsername2Prefix = 'Счётчики по работникам';
|
||||||
|
Object.keys(issuesByUsername2).forEach((username) => {
|
||||||
|
const userData = issuesByUsername2[username];
|
||||||
|
if (userData) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${issuesByUsername2Prefix} / ${username} / Количество задач`,
|
||||||
|
value: userData.count,
|
||||||
|
details: {
|
||||||
|
issueIds: userData.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ШАГ 4. Количество внутренних изменений
|
||||||
|
const changesCount2 = props.store?.data?.issuesMetrics?.changesCount ?? {};
|
||||||
|
const changesCount2Prefix = 'Счётчики изменений';
|
||||||
|
otherData.push({
|
||||||
|
title: `${changesCount2Prefix} / Всего изменений`,
|
||||||
|
value: changesCount2.totalChanges || 0,
|
||||||
|
});
|
||||||
|
otherData.push({
|
||||||
|
title: `${changesCount2Prefix} / Всего комментариев`,
|
||||||
|
value: changesCount2.totalComments || 0,
|
||||||
|
});
|
||||||
|
const sections: Record<string, string> = {
|
||||||
|
byIssue: 'По задачам',
|
||||||
|
byStatus: 'По статусам',
|
||||||
|
byVersion: 'По версиям',
|
||||||
|
byUserName: 'По работникам',
|
||||||
|
};
|
||||||
|
Object.keys(sections).forEach((sectionName) => {
|
||||||
|
const sectionData = changesCount2[sectionName];
|
||||||
|
if (!sectionData) return;
|
||||||
|
const sectionPrefix = `${changesCount2Prefix} / ${sections[sectionName]}`;
|
||||||
|
Object.keys(sectionData).forEach((itemKey) => {
|
||||||
|
const itemData = sectionData[itemKey];
|
||||||
|
otherData.push({
|
||||||
|
title: `${sectionPrefix} / ${itemKey} / Изменения`,
|
||||||
|
value: itemData.changes || 0,
|
||||||
|
});
|
||||||
|
otherData.push({
|
||||||
|
title: `${sectionPrefix} / ${itemKey} / Комментарии`,
|
||||||
|
value: itemData.comments || 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ШАГ 5. Количество задач с оценками трудозатрат
|
||||||
|
const issuesWithEstimatesAndSpenthoursCount =
|
||||||
|
props.store?.data?.issuesMetrics?.issuesWithEstimatesAndSpenthoursCount ??
|
||||||
|
{};
|
||||||
|
|
||||||
|
const estimatesPrefix =
|
||||||
|
'Счётчики с оценкой трудозатрат и потраченных часов';
|
||||||
|
|
||||||
|
if (issuesWithEstimatesAndSpenthoursCount.withEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefix} / С оценкой трудозатрат`,
|
||||||
|
value: issuesWithEstimatesAndSpenthoursCount.withEstimates.count,
|
||||||
|
details: {
|
||||||
|
issueIds:
|
||||||
|
issuesWithEstimatesAndSpenthoursCount.withEstimates.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (issuesWithEstimatesAndSpenthoursCount.withoutEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefix} / Без оценки трудозатрат`,
|
||||||
|
value: issuesWithEstimatesAndSpenthoursCount.withoutEstimates.count,
|
||||||
|
details: {
|
||||||
|
issueIds:
|
||||||
|
issuesWithEstimatesAndSpenthoursCount.withoutEstimates.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (issuesWithEstimatesAndSpenthoursCount.withSpentHoursOverEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefix} / С потраченными часами больше, чем оценка трудозатрат`,
|
||||||
|
value:
|
||||||
|
issuesWithEstimatesAndSpenthoursCount.withSpentHoursOverEstimates
|
||||||
|
.count,
|
||||||
|
details: {
|
||||||
|
issueIds:
|
||||||
|
issuesWithEstimatesAndSpenthoursCount.withSpentHoursOverEstimates
|
||||||
|
.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (issuesWithEstimatesAndSpenthoursCount.byVersion) {
|
||||||
|
const estimatesPrefixVersions = `${estimatesPrefix} / По версиям`;
|
||||||
|
Object.keys(issuesWithEstimatesAndSpenthoursCount.byVersion).forEach(
|
||||||
|
(versionName) => {
|
||||||
|
const estimatesPrefixVersion = `${estimatesPrefixVersions} / ${versionName}`;
|
||||||
|
const versionData =
|
||||||
|
issuesWithEstimatesAndSpenthoursCount.byVersion[versionName];
|
||||||
|
if (versionData.withEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefixVersion} / С оценкой трудозатрат`,
|
||||||
|
value: versionData.withEstimates.count,
|
||||||
|
details: { issueIds: versionData.withEstimates.issueIds },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (versionData.withoutEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefixVersion} / Без оценки трудозатрат`,
|
||||||
|
value: versionData.withoutEstimates.count,
|
||||||
|
details: { issueIds: versionData.withoutEstimates.issueIds },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (versionData.withSpentHoursOverEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefixVersion} / С потраченными часами больше, чем оценка трудозатрат`,
|
||||||
|
value: versionData.withSpentHoursOverEstimates.count,
|
||||||
|
details: {
|
||||||
|
issueIds: versionData.withSpentHoursOverEstimates.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (issuesWithEstimatesAndSpenthoursCount.byStatus) {
|
||||||
|
const estimatesPrefixStatuses = `${estimatesPrefix} / По статусам`;
|
||||||
|
Object.keys(issuesWithEstimatesAndSpenthoursCount.byStatus).forEach(
|
||||||
|
(statusName) => {
|
||||||
|
const estimatesPrefixStatus = `${estimatesPrefixStatuses} / ${statusName}`;
|
||||||
|
const statusData =
|
||||||
|
issuesWithEstimatesAndSpenthoursCount.byStatus[statusName];
|
||||||
|
if (statusData.withEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefixStatus} / С оценкой трудозатрат`,
|
||||||
|
value: statusData.withEstimates.count,
|
||||||
|
details: { issueIds: statusData.withEstimates.issueIds },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (statusData.withoutEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefixStatus} / Без оценки трудозатрат`,
|
||||||
|
value: statusData.withoutEstimates.count,
|
||||||
|
details: { issueIds: statusData.withoutEstimates.issueIds },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (statusData.withSpentHoursOverEstimates) {
|
||||||
|
otherData.push({
|
||||||
|
title: `${estimatesPrefixStatus} / С потраченными часами больше, чем оценка трудозатрат`,
|
||||||
|
value: statusData.withSpentHoursOverEstimates.count,
|
||||||
|
details: {
|
||||||
|
issueIds: statusData.withSpentHoursOverEstimates.issueIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const byStatusLi: JSX.Element[] = [];
|
const byStatusLi: JSX.Element[] = [];
|
||||||
|
|
||||||
|
|
@ -90,7 +455,8 @@ export const DailyEccmV2 = observer(
|
||||||
byStatusLi.push(
|
byStatusLi.push(
|
||||||
<li key={`${keyPrefixForCurrentStatusBlock}-li`}>
|
<li key={`${keyPrefixForCurrentStatusBlock}-li`}>
|
||||||
<SimpleCounterViewComponent
|
<SimpleCounterViewComponent
|
||||||
key={`${keyPrefixForCurrentStatusBlock}`}
|
key={keyPrefixForCurrentStatusBlock}
|
||||||
|
id={keyPrefixForCurrentStatusBlock}
|
||||||
label={statusName}
|
label={statusName}
|
||||||
count={byStatusData.count}
|
count={byStatusData.count}
|
||||||
issueIds={byStatusData.issueIds}
|
issueIds={byStatusData.issueIds}
|
||||||
|
|
@ -110,6 +476,7 @@ export const DailyEccmV2 = observer(
|
||||||
<li key={`${keyPrefixForCurrentVersionBlock}-li`}>
|
<li key={`${keyPrefixForCurrentVersionBlock}-li`}>
|
||||||
<SimpleCounterViewComponent
|
<SimpleCounterViewComponent
|
||||||
key={keyPrefixForCurrentVersionBlock}
|
key={keyPrefixForCurrentVersionBlock}
|
||||||
|
id={keyPrefixForCurrentVersionBlock}
|
||||||
label={versionName}
|
label={versionName}
|
||||||
count={byVersionData.count}
|
count={byVersionData.count}
|
||||||
issueIds={byVersionData.issueIds}
|
issueIds={byVersionData.issueIds}
|
||||||
|
|
@ -129,6 +496,7 @@ export const DailyEccmV2 = observer(
|
||||||
<li key={`${keyPrefixForCurrentUserBlock}-li`}>
|
<li key={`${keyPrefixForCurrentUserBlock}-li`}>
|
||||||
<SimpleCounterViewComponent
|
<SimpleCounterViewComponent
|
||||||
key={keyPrefixForCurrentUserBlock}
|
key={keyPrefixForCurrentUserBlock}
|
||||||
|
id={keyPrefixForCurrentUserBlock}
|
||||||
label={username}
|
label={username}
|
||||||
count={byUserNameData.count}
|
count={byUserNameData.count}
|
||||||
issueIds={byUserNameData.issueIds}
|
issueIds={byUserNameData.issueIds}
|
||||||
|
|
@ -160,6 +528,22 @@ export const DailyEccmV2 = observer(
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
По изменениям в задачах за период:
|
||||||
|
<ChangesCounterTotalViewComponent
|
||||||
|
key={`${keyPrefix}-changesCounterTotal`}
|
||||||
|
id={`${keyPrefix}-changesCounterTotal`}
|
||||||
|
data={changesCount}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Другие счётчики:
|
||||||
|
<VerySimpleCounterListViewComponent
|
||||||
|
key={`${keyPrefix}-verySimpleCounterListViewComponent`}
|
||||||
|
id={`${keyPrefix}-verySimpleCounterListViewComponent`}
|
||||||
|
data={otherData || []}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<DebugInfo value={JSON.stringify(props.store?.data, null, 2)} />
|
<DebugInfo value={JSON.stringify(props.store?.data, null, 2)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
55
frontend/src/utils/text-to-id.ts
Normal file
55
frontend/src/utils/text-to-id.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
export function transformUtf8ToTransliteAscii(inputText: string): string {
|
||||||
|
// Define a mapping of Russian characters to their translite ASCII equivalents
|
||||||
|
const transliterationMap: { [key: string]: string } = {
|
||||||
|
а: 'a',
|
||||||
|
б: 'b',
|
||||||
|
в: 'v',
|
||||||
|
г: 'g',
|
||||||
|
д: 'd',
|
||||||
|
е: 'e',
|
||||||
|
ё: 'e',
|
||||||
|
ж: 'zh',
|
||||||
|
з: 'z',
|
||||||
|
и: 'i',
|
||||||
|
й: 'y',
|
||||||
|
к: 'k',
|
||||||
|
л: 'l',
|
||||||
|
м: 'm',
|
||||||
|
н: 'n',
|
||||||
|
о: 'o',
|
||||||
|
п: 'p',
|
||||||
|
р: 'r',
|
||||||
|
с: 's',
|
||||||
|
т: 't',
|
||||||
|
у: 'u',
|
||||||
|
ф: 'f',
|
||||||
|
х: 'kh',
|
||||||
|
ц: 'ts',
|
||||||
|
ч: 'ch',
|
||||||
|
ш: 'sh',
|
||||||
|
щ: 'sch',
|
||||||
|
ъ: '',
|
||||||
|
ы: 'y',
|
||||||
|
ь: '',
|
||||||
|
э: 'e',
|
||||||
|
ю: 'yu',
|
||||||
|
я: 'ya',
|
||||||
|
// Add more mappings as needed...
|
||||||
|
' ': '-',
|
||||||
|
'/': 'then',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transform the input text to translite ASCII without spaces
|
||||||
|
let transformedText = '';
|
||||||
|
for (const char of inputText.toLowerCase()) {
|
||||||
|
if (transliterationMap[char]) {
|
||||||
|
transformedText += transliterationMap[char];
|
||||||
|
} else {
|
||||||
|
transformedText += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const text2id = transformUtf8ToTransliteAscii;
|
||||||
|
|
@ -314,7 +314,9 @@ export class DailyEccmV2ReportTaskRunnerService {
|
||||||
comments: 0,
|
comments: 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if (changes && (changes.changes > 0 || changes.comments > 0)) {
|
||||||
changesCount.byIssue[issue.id] = changes;
|
changesCount.byIssue[issue.id] = changes;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue