mirror of
https://github.com/bakhirev/assayo.git
synced 2024-11-16 16:21:41 +00:00
TEST-0000 feat(doc): some text for save
This commit is contained in:
parent
9657773717
commit
2964b8b5e1
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.f032b99c.css",
|
||||
"main.js": "./static/js/main.9af297c4.js",
|
||||
"static/media/car.png": "./static/media/car.b8dd8738e37fe866285f.png",
|
||||
"index.html": "./index.html",
|
||||
"static/media/warning.svg": "./static/media/warning.e39a87773603f3ab157f.svg",
|
||||
"static/media/info.svg": "./static/media/info.954631f6b19e3fe9c495.svg",
|
||||
"static/media/alert.svg": "./static/media/alert.41e2b99c481139c13074.svg",
|
||||
"main.f032b99c.css.map": "./static/css/main.f032b99c.css.map",
|
||||
"main.9af297c4.js.map": "./static/js/main.9af297c4.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.f032b99c.css",
|
||||
"static/js/main.9af297c4.js"
|
||||
]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<!doctype html><html lang="ru"><head><meta name="viewport" content="width=device-width,height=device-height,initial-scale=1,user-scalable=no,maximum-scale=1"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Cache-Control" content="no-cache"><meta http-equiv="cleartype" content="on"><meta name="HandheldFriendly" content="True"><meta name="format-detection" content="telephone=no"><meta name="format-detection" content="address=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><script type="text/javascript">var report=[]</script><script src="/log.txt"></script><script src="./log.txt"></script><script src="../log.txt"></script><script src="./log-0.txt"></script><script src="./log-1.txt"></script><script src="./log-2.txt"></script><script src="./log-3.txt"></script><script src="./log-4.txt"></script><script src="./log-5.txt"></script><script src="./log-6.txt"></script><script src="./report/log-0.txt"></script><script src="./report/log-1.txt"></script><script src="./report/log-2.txt"></script><script src="./report/log-3.txt"></script><script src="./report/log-4.txt"></script><script src="./report/log-5.txt"></script><script src="./report/log-6.txt"></script><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>Git статистика</title><meta name="description" content="Простой и быстрый отчёт по истории коммитов в git."><meta name="keywords" content="git, статистика, аудит, история, log, мониторинг, контроль сотрудников"><meta name="author" content="Bakhirev Aleksei"><meta name="copyright" content="(c) Bakhirev Aleksei"><meta http-equiv="Reply-to" content="alexey-bakhirev@yandex.ru"><meta name="application-name" content="GIT Статистика"><meta name="msapplication-tooltip" content="Простой и быстрый отчёт по истории коммитов в git."><meta property="og:title" content="GIT Статистика"><meta property="og:description" content="Простой и быстрый отчёт по истории коммитов в git."><meta property="og:image" content="http://assayo.jp/assets/seo/custom_icon_256.png"><meta property="og:site_name" content="Assayo"><meta property="og:url" content="http://assayo.jp/"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="GIT Статистика"><meta name="twitter:description" content="Простой и быстрый отчёт по истории коммитов в git."><meta name="twitter:creator" content="Bakhirev Aleksei"><meta name="twitter:image:src" content="http://assayo.jp/assets/seo/custom_icon_256.png"><meta name="twitter:domain" content="assayo.jp"><meta name="twitter:site" content="assayo.jp"><meta itemprop="name" content="GIT Статистика"><meta itemprop="description" content="Простой и быстрый отчёт по истории коммитов в git."><meta itemprop="image" content="http://assayo.jp/assets/seo/custom_icon_256.png"><script defer="defer" src="./static/js/main.9af297c4.js"></script><link href="./static/css/main.f032b99c.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,74 +0,0 @@
|
|||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.3.1
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.8.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.8.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#E29893"><path d="M2 42 24 4l22 38Zm5.2-3h33.6L24 10Zm17-2.85q.65 0 1.075-.425.425-.425.425-1.075 0-.65-.425-1.075-.425-.425-1.075-.425-.65 0-1.075.425Q22.7 34 22.7 34.65q0 .65.425 1.075.425.425 1.075.425Zm-1.5-5.55h3V19.4h-3Zm1.3-6.1Z"/></svg>
|
Before Width: | Height: | Size: 313 B |
Binary file not shown.
Before Width: | Height: | Size: 9.9 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#0386D4"><path d="M22.65 34h3V22h-3ZM24 18.3q.7 0 1.175-.45.475-.45.475-1.15t-.475-1.2Q24.7 15 24 15q-.7 0-1.175.5-.475.5-.475 1.2t.475 1.15q.475.45 1.175.45ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 23.95q0-4.1 1.575-7.75 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24.05 4q4.1 0 7.75 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm.05-3q7.05 0 12-4.975T41 23.95q0-7.05-4.95-12T24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24.05 41ZM24 24Z"/></svg>
|
Before Width: | Height: | Size: 660 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#FB9A1F"><path d="M31.3 21.35q1.15 0 1.925-.8.775-.8.775-1.9 0-1.15-.775-1.925-.775-.775-1.925-.775-1.1 0-1.9.775-.8.775-.8 1.925 0 1.1.8 1.9.8.8 1.9.8Zm-14.6 0q1.15 0 1.925-.8.775-.8.775-1.9 0-1.15-.775-1.925-.775-.775-1.925-.775-1.1 0-1.9.775-.8.775-.8 1.925 0 1.1.8 1.9.8.8 1.9.8Zm7.3 5.8q-3.35 0-6.075 1.875T13.9 34h2.65q1.1-2.1 3.1-3.25t4.4-1.15q2.35 0 4.325 1.175T31.5 34h2.6q-1.25-3.15-4-5T24 27.15ZM24 44q-4.15 0-7.8-1.575-3.65-1.575-6.35-4.275-2.7-2.7-4.275-6.35Q4 28.15 4 24t1.575-7.8Q7.15 12.55 9.85 9.85q2.7-2.7 6.35-4.275Q19.85 4 24 4t7.8 1.575q3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24t-1.575 7.8q-1.575 3.65-4.275 6.35-2.7 2.7-6.35 4.275Q28.15 44 24 44Zm0-20Zm0 17q7.1 0 12.05-4.95Q41 31.1 41 24q0-7.1-4.95-12.05Q31.1 7 24 7q-7.1 0-12.05 4.95Q7 16.9 7 24q0 7.1 4.95 12.05Q16.9 41 24 41Z"/></svg>
|
Before Width: | Height: | Size: 893 B |
|
@ -2,6 +2,9 @@ import React, { ReactNode } from 'react';
|
|||
|
||||
import Button from 'ts/components/UiKit/components/Button';
|
||||
import notificationsStore from 'ts/components/Notifications/store';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from './index.module.scss';
|
||||
|
||||
function copyInBuffer(value?: string) {
|
||||
if (!value) return;
|
||||
|
@ -16,8 +19,6 @@ function copyInBuffer(value?: string) {
|
|||
document.body.removeChild(copyTextarea);
|
||||
}
|
||||
|
||||
import style from './index.module.scss';
|
||||
|
||||
interface IConsoleProps {
|
||||
textForCopy?: string;
|
||||
className?: string;
|
||||
|
@ -43,7 +44,7 @@ function Console({ className, textForCopy, children }: IConsoleProps) {
|
|||
notificationsStore.show('Текст скопирован');
|
||||
}}
|
||||
>
|
||||
Копировать
|
||||
{localization.get('uiKit.console')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ import type { IPagination, IPaginationRequest } from 'ts/interfaces/Pagination';
|
|||
import UiKitInputString from 'ts/components/UiKit/components/InputString';
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import Loading from 'ts/components/Loading';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import { DataLoaderState, IDataLoaderStore } from '../store';
|
||||
import ErrorDescription from '../ErrorDescription';
|
||||
|
@ -59,7 +60,7 @@ function SimplePagination({
|
|||
return (
|
||||
<nav className={style.paginator}>
|
||||
<p className={style.paginator_text}>
|
||||
Страница
|
||||
{localization.get('uiKit.dataLoader.page')}
|
||||
</p>
|
||||
<UiKitButton
|
||||
type="second"
|
||||
|
@ -94,7 +95,7 @@ function SimplePagination({
|
|||
»
|
||||
</UiKitButton>
|
||||
<p className={style.paginator_text}>
|
||||
из
|
||||
{localization.get('uiKit.dataLoader.from')}
|
||||
</p>
|
||||
<UiKitButton
|
||||
type="second"
|
||||
|
@ -105,7 +106,7 @@ function SimplePagination({
|
|||
{totalPages}
|
||||
</UiKitButton>
|
||||
<p className={style.paginator_text}>
|
||||
Отображается по
|
||||
{localization.get('uiKit.dataLoader.size')}
|
||||
</p>
|
||||
<UiKitInputString
|
||||
value={pageSize}
|
||||
|
@ -131,7 +132,7 @@ function SimplePagination({
|
|||
if (store) store.showAll();
|
||||
}}
|
||||
>
|
||||
Показать все
|
||||
{localization.get('uiKit.dataLoader.all')}
|
||||
</UiKitButton>
|
||||
)}
|
||||
</nav>
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
import type { IPagination } from 'ts/interfaces/Pagination';
|
||||
import Loading from 'ts/components/Loading';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import { IDataLoaderStore, DataLoaderState } from '../store';
|
||||
import ErrorDescription from '../ErrorDescription';
|
||||
|
@ -48,7 +49,7 @@ function ShowAll({
|
|||
className={`${style.show_all} ${className || ''}`}
|
||||
onClick={() => { if (store) store.showAll(); }}
|
||||
>
|
||||
Показать все
|
||||
{localization.get('uiKit.dataLoader.all')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import cssStyle from './index.module.scss';
|
||||
|
||||
|
@ -7,12 +8,30 @@ interface ICommonProps {
|
|||
style: any;
|
||||
}
|
||||
|
||||
function getTextWithLink(text: string) {
|
||||
const parts = (text || '')
|
||||
.split(/(\[[^\]]+\])/gim)
|
||||
.map((value: string) => {
|
||||
if (value?.[0] !== '[') return value;
|
||||
const [ title, link ] = value.replace(/\[|\]/gim, '').split('|');
|
||||
return (
|
||||
<Link
|
||||
key={value}
|
||||
target="_blank"
|
||||
to={link}>
|
||||
{title}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
return (<>{parts}</>) ;
|
||||
}
|
||||
|
||||
function getTextWithStyle(text: string) {
|
||||
const parts = (text || '')
|
||||
.split('*')
|
||||
.map((value: string, index: number) => (index % 2
|
||||
? (<b key={value}>{value}</b>)
|
||||
: (<span key={value}>{value}</span>)
|
||||
.map((value: string, index: number) => (index % 2
|
||||
? (<b key={value}>{getTextWithLink(value)}</b>)
|
||||
: (<span key={value}>{getTextWithLink(value)}</span>)
|
||||
));
|
||||
return (<>{parts}</>) ;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import React from 'react';
|
||||
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from '../styles/legend.module.scss';
|
||||
|
||||
function Legend(): React.ReactElement | null {
|
||||
|
@ -8,13 +10,13 @@ function Legend(): React.ReactElement | null {
|
|||
<div className={style.legend_item}>
|
||||
<div className={style.legend_work}></div>
|
||||
<div className={style.legend_title}>
|
||||
стандартное рабочее время (будни, с 07:00 до 20:00)
|
||||
{localization.get('uiKit.hoursChart.work')}
|
||||
</div>
|
||||
</div>
|
||||
<div className={style.legend_item}>
|
||||
<div className={style.legend_weekend}></div>
|
||||
<div className={style.legend_title}>
|
||||
выходные дни или время до/после рабочего дня
|
||||
{localization.get('uiKit.hoursChart.weekend')}
|
||||
</div>
|
||||
</div>
|
||||
<div className={style.legend_item}>
|
||||
|
@ -22,7 +24,7 @@ function Legend(): React.ReactElement | null {
|
|||
42
|
||||
</div>
|
||||
<div className={style.legend_title}>
|
||||
суммарное количество коммитов за все время в конкретный день и час
|
||||
{localization.get('uiKit.hoursChart.days')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from '../index.module.scss';
|
||||
|
||||
function CommitFormat() {
|
||||
return (
|
||||
<>
|
||||
<p className={style.nothing_found_title}>
|
||||
Нет или недостаточно данных для отображения
|
||||
{localization.get('uiKit.nothingFound.common.title')}
|
||||
</p>
|
||||
<p className={style.nothing_found_text}>
|
||||
Система обработает больше данных, если коммиты будут подписаны в формате "
|
||||
|
@ -21,10 +23,10 @@ function CommitFormat() {
|
|||
". Шаблон:
|
||||
</p>
|
||||
<p className={style.nothing_found_console}>
|
||||
Номер_задачи тип(фича): пояснение
|
||||
{localization.get('uiKit.nothingFound.common.console')}
|
||||
</p>
|
||||
<p className={style.nothing_found_text}>
|
||||
Например:
|
||||
{localization.get('uiKit.nothingFound.common.example')}
|
||||
</p>
|
||||
<p className={style.nothing_found_console}>
|
||||
JIRA-0001 feat(profile): add user avatar<br/>
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import React from 'react';
|
||||
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from '../index.module.scss';
|
||||
|
||||
function IsStaff() {
|
||||
return (
|
||||
<>
|
||||
<p className={style.nothing_found_title}>
|
||||
Нет данных для этого сотрудника
|
||||
{localization.get('uiKit.nothingFound.staff.title')}
|
||||
</p>
|
||||
<p className={style.nothing_found_text}>
|
||||
Он вносил правки не каждый рабочий день и получил статус Помошник.
|
||||
Работой сотрудников с таким статусом по данному проекту можно пренебречь, т.к. его влад на общем фоне незначителен.
|
||||
{localization.get('uiKit.nothingFound.staff.description1')}
|
||||
</p>
|
||||
<p className={style.nothing_found_text}>
|
||||
Поэтому система не рассчитывает для него ряд показателей.
|
||||
Если это ошибка и данного сотрудника надо рассчитать как обычного, перейдите в раздел Настройки и измените его тип.
|
||||
{localization.get('uiKit.nothingFound.staff.description2')}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import CommitFormat from './components/CommitFormat';
|
||||
import style from './index.module.scss';
|
||||
|
||||
|
@ -17,6 +19,7 @@ function NothingFound({
|
|||
children,
|
||||
className,
|
||||
}: INothingFoundProps) {
|
||||
const formattedMessage = localization.get(message || '');
|
||||
return (
|
||||
<div className={`${style.nothing_found_wrapper} ${className}`}>
|
||||
<div className={style.nothing_found}>
|
||||
|
@ -26,7 +29,7 @@ function NothingFound({
|
|||
/>
|
||||
{!children && message && (
|
||||
<p className={style.nothing_found_title}>
|
||||
{message}
|
||||
{formattedMessage}
|
||||
</p>
|
||||
)}
|
||||
{!children && !message && (<CommitFormat />)}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { makeObservable, observable, action } from 'mobx';
|
||||
|
||||
import localization from 'ts/helpers/Localization';
|
||||
import IMessage from '../interfaces/Message';
|
||||
import localization from "../../../helpers/Localization";
|
||||
|
||||
interface INotificationsStore {
|
||||
timer: any;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from './index.module.scss';
|
||||
|
||||
interface IPageColumnProps {
|
||||
|
@ -22,7 +24,7 @@ function PageBox({
|
|||
type="second"
|
||||
onClick={() => onRemove()}
|
||||
>
|
||||
Удалить
|
||||
{localization.get('uiKit.page.remove')}
|
||||
</UiKitButton>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import Track from './Track';
|
||||
import style from './index.module.scss';
|
||||
|
@ -46,7 +47,7 @@ function Races({
|
|||
setShowAnimation(true);
|
||||
}}
|
||||
>
|
||||
Поехали
|
||||
{localization.get('uiKit.races.go')}
|
||||
</UiKitButton>
|
||||
)}
|
||||
{lines}
|
||||
|
|
|
@ -1,6 +1,29 @@
|
|||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
localization.parse('ru', `
|
||||
§ uiKit.console: Копировать
|
||||
§ uiKit.dataLoader.page: Страница
|
||||
§ uiKit.dataLoader.size: Отображается по
|
||||
§ uiKit.dataLoader.from: из
|
||||
§ uiKit.dataLoader.all: Показать все
|
||||
§ uiKit.hoursChart.work: стандартное рабочее время (будни, с 07:00 до 20:00)
|
||||
§ uiKit.hoursChart.weekend: выходные дни или время до/после рабочего дня
|
||||
§ uiKit.hoursChart.days: суммарное количество коммитов за все время в конкретный день и час
|
||||
§ uiKit.page.remove: Удалить
|
||||
§ uiKit.races.go: Поехали
|
||||
§ uiKit.nothingFound.common.title: Нет или недостаточно данных для отображения
|
||||
§ uiKit.nothingFound.common.description: Система обработает больше данных, если коммиты будут подписаны в формате [Git commit message convention|https://www.conventionalcommits.org/en/v1.0.0/]. Шаблон:
|
||||
§ uiKit.nothingFound.common.console: Номер_задачи тип(фича): пояснение
|
||||
§ uiKit.nothingFound.common.example: Например:
|
||||
§ uiKit.nothingFound.staff.title: Нет данных для этого сотрудника
|
||||
§ uiKit.nothingFound.staff.description1:
|
||||
Он вносил правки не каждый рабочий день и получил статус «Помошник».
|
||||
Работой сотрудников с таким статусом по данному проекту можно пренебречь, т.к. его влад на общем фоне незначителен.
|
||||
|
||||
§ uiKit.nothingFound.staff.description2:
|
||||
Поэтому система не рассчитывает для него ряд показателей.
|
||||
Если это ошибка и данного сотрудника нужно рассчитать как обычного, перейдите в раздел «Настройки» и измените его тип.
|
||||
|
||||
§ common.filters: Фильтры
|
||||
§ common.notifications.save: Изменения сохранены
|
||||
§ common.notifications.setting: Настройки сохранены
|
||||
|
@ -42,10 +65,46 @@ localization.parse('ru', `
|
|||
§ page.welcome.step1: Выполните команду в корне вашего проекта
|
||||
§ page.welcome.step2: Перетащите файл log.txt на эту страницу
|
||||
§ page.welcome.description1: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл
|
||||
§ page.welcome.description2: в корне проекта, чтобы обьединить статистику по сотрудникам.
|
||||
§ page.welcome.description2: [.mailmap|https://git-scm.com/docs/gitmailmap] в корне проекта, чтобы обьединить статистику по сотрудникам.
|
||||
§ page.welcome.description: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл [.mailmap|https://git-scm.com/docs/gitmailmap] в корне проекта, чтобы обьединить статистику по сотрудникам.
|
||||
§ page.welcome.warning1: Сервис *НЕ ХРАНИТ* и *НЕ ПЕРЕДАЁТ* ваши данные. Все расчёты выполняются локально в вашем браузере прямо на вашей машине.
|
||||
§ page.welcome.warning2: Сервис *НЕ СОБИРАЕТ СТАТИСТИКУ* по проектам. Вы можете отключить интернет, проверить трафик и даже собрать локальный билд из [исходников|https://github.com/bakhirev/assayo].
|
||||
§ page.common.words.title: Статистика по словам
|
||||
§ page.common.words.description: самое популярное слово. Встречается $1 раза.
|
||||
§ page.common.commits.title: Количество коммитов по дням
|
||||
§ page.common.commits.description: ($1) самый продуктивный день по числу коммитов.
|
||||
§ page.common.commits.title2: $1 сделано коммитов: $2
|
||||
§ page.common.filter.allUsers: Не имеет значения
|
||||
§ page.settings.document.title: Настройки отображения
|
||||
§ page.settings.document.name: Заголовок страницы
|
||||
§ page.settings.document.language: Язык интерфейса
|
||||
§ page.settings.links.title: Префиксы ссылок
|
||||
§ page.settings.links.task: Для номеров задач
|
||||
§ page.settings.links.pr: Для PR
|
||||
§ page.settings.user.title: Индивидуальные настройки
|
||||
§ page.settings.user.notFound: Индивидуальных настроек нет. Данные по всем сотрудникам вычисляются по общим параметрам.
|
||||
§ page.settings.user.subTitle: Дополнение к трудовому договору №$1
|
||||
§ page.settings.user.from: Дата начала действия
|
||||
§ page.settings.mailmap: Настройки .mailmap
|
||||
§ page.settings.common.title: Общие данные по зарплате
|
||||
§ page.settings.common.type.title: Тип работы над проектом
|
||||
§ page.settings.common.type.full: Полная занятость
|
||||
§ page.settings.common.type.part: Проектная работа
|
||||
§ page.settings.common.salary: Зарплата в месяц
|
||||
§ page.settings.common.currency: Валюта
|
||||
§ page.settings.common.workDaysInYear: Количество рабочих дней в году
|
||||
§ page.settings.common.vacationDaysInYear: Количество дней отпуска в год
|
||||
§ page.settings.common.workDaysInWeek: Рабочие дни
|
||||
§ page.settings.form.save: Сохранить
|
||||
§ page.settings.form.cancel: Отмена
|
||||
§ page.settings.form.remove: Удалить
|
||||
§ page.settings.form.addEmployee: Добавить сотрудника
|
||||
§ page.settings.form.addContract: Добавить трудовой договор
|
||||
§ page.print.title: Что распечатываем?
|
||||
§ page.print.page: Текущую страницу
|
||||
§ page.print.type: Текущий раздел
|
||||
§ page.print.all: Всю статистику
|
||||
§ page.print.cancel: Отмена
|
||||
§ page.team.author.title: Статистика по сотрудникам
|
||||
§ page.team.author.description1: *Часть статитики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помошник» не считается*, т.к. это эпизодическая роль в проекте. Предпологаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы.
|
||||
§ page.team.author.description2: *Сортировка по умолчанию* — это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники).
|
||||
|
@ -136,6 +195,26 @@ localization.parse('ru', `
|
|||
§ page.team.week.hasNotCommits: небыло коммитов
|
||||
§ page.team.week.days: дней
|
||||
§ page.team.week.tasks: задач
|
||||
§ page.team.pr.task: Задача
|
||||
§ page.team.pr.tasks: задач
|
||||
§ page.team.pr.firstCommitTime: Первый коммит
|
||||
§ page.team.pr.lastCommitTime: Последний
|
||||
§ page.team.pr.workDays: Дней разработки
|
||||
§ page.team.pr.delayDays: Дней ожидания влития
|
||||
§ page.team.pr.commits: Коммиты
|
||||
§ page.team.pr.date: Дата влития
|
||||
§ page.team.pr.mergeAuthor: Влил
|
||||
§ page.team.pr.author: Сотрудник
|
||||
§ page.team.pr.middleTimeRelease: Среднее время поставки (дни)
|
||||
§ page.team.pr.work: разработка
|
||||
§ page.team.pr.delay: ожидание
|
||||
§ page.team.pr.days: дней
|
||||
§ page.team.pr.oneTaskDays: Время потраченное на одну задачу
|
||||
§ page.team.pr.description1: *Время разработки* это разница времени от первого до последнего коммита по задаче. Не важно были перерывы в несколько дней между коммитами или нет. Сам факт какого-либо коммита увеличивает время.
|
||||
§ page.team.pr.description2: *Время ожидания* это время между последним коммитом и влитием кода. Оно показывает фактический простой в ожидании чего-либо.
|
||||
§ page.team.pr.description3: *Зачем отображать время разработки* без разбивки на кодинг и код-ревью? Затем, чтобы показать бизнесу фактическое время поставки кода. Ожидание тестирования, замечания на ревью, проблемы DevOps и прочие несовершенства процесса, как раз уже заложены в этот срок.
|
||||
§ page.team.pr.statByAuthors: Статистика по сотрудникам
|
||||
§ page.team.pr.longDelay: Длительное ожидание влития
|
||||
§ page.person.print.photo.title: Фотография
|
||||
§ page.person.print.photo.description: место для фотографии
|
||||
§ page.person.total.title: Основные характеристики
|
||||
|
|
|
@ -22,14 +22,29 @@ export default class DataGripByExtension {
|
|||
|
||||
updateTotalInfo(fileList: any[], byAuthor: any) {
|
||||
const byExtension = {};
|
||||
console.dir(fileList);
|
||||
|
||||
fileList.forEach((file: any) => {
|
||||
if (!file.extension
|
||||
|| IGNORE_LIST.includes(file.name)) return;
|
||||
if (!byExtension[file.extension]) {
|
||||
byExtension[file.extension] = {
|
||||
extension: file.extension, authors: {}, more: {}, total: { added: 0, changes: 0, removed: 0, total: 0 },
|
||||
extension: file.extension,
|
||||
authors: {},
|
||||
files: { [file.firstName]: 1 },
|
||||
more: {},
|
||||
total: {
|
||||
added: 0,
|
||||
changes: 0,
|
||||
removed: 0,
|
||||
total: 0,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
const numberNames = byExtension[file.extension].files[file.firstName];
|
||||
byExtension[file.extension].files[file.firstName] = numberNames
|
||||
? (numberNames + 1)
|
||||
: 1;
|
||||
}
|
||||
|
||||
for (let author in file.authors) {
|
||||
|
|
|
@ -3,7 +3,16 @@ class Localization {
|
|||
|
||||
translations: any = {};
|
||||
|
||||
get(key = '') {
|
||||
insertArguments(message: string, args?: any) {
|
||||
if (!args) return message;
|
||||
const list = Array.isArray(args) ? args : [args];
|
||||
list.forEach((text: any, index: number) => {
|
||||
message = message.replace(`$${index}`, text || '_');
|
||||
});
|
||||
return message;
|
||||
}
|
||||
|
||||
get(key = '', args?: any) {
|
||||
const dictionary = this.translations[this.language];
|
||||
if (!dictionary) return key || '';
|
||||
|
||||
|
@ -16,7 +25,8 @@ class Localization {
|
|||
message = message[keys[i]];
|
||||
if (!message) return key || '';
|
||||
}
|
||||
return message;
|
||||
|
||||
return this.insertArguments(message, args);
|
||||
}
|
||||
|
||||
parse(langId: string, text: string) {
|
||||
|
|
|
@ -20,9 +20,12 @@ export function getNewFileInfo(
|
|||
addedLines: number,
|
||||
commit?: ICommit | null,
|
||||
) {
|
||||
const nameParts = name?.split('/')?.pop()?.split('.') || [];
|
||||
return {
|
||||
name,
|
||||
extension: name?.split('.')?.pop(),
|
||||
extension: nameParts.pop(),
|
||||
firstName: nameParts.shift(),
|
||||
suffixes: nameParts,
|
||||
lines: addedLines,
|
||||
created: commit,
|
||||
authors: {
|
||||
|
|
|
@ -9,6 +9,7 @@ import PageWrapper from 'ts/components/Page/wrapper';
|
|||
import BarChart from 'ts/components/BarChart';
|
||||
import DayInfo from 'ts/components/DayInfo';
|
||||
import Title from 'ts/components/Title';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
interface ICommitsProps {
|
||||
statistic: any;
|
||||
|
@ -30,13 +31,17 @@ function Commits({ statistic }: ICommitsProps) {
|
|||
|
||||
const [fullDay, shortDay] = getDateByTimestamp(maxData.timestamp);
|
||||
const recommendations = [
|
||||
[fullDay, `(${shortDay}) самый продуктивный день по числу коммитов.`, 'fact'],
|
||||
[
|
||||
fullDay,
|
||||
localization.get('page.common.commits.description', shortDay),
|
||||
'fact',
|
||||
],
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<RecommendationsWrapper recommendations={recommendations} />
|
||||
<Title title="Количество коммитов по дням"/>
|
||||
<Title title="page.common.commits.title"/>
|
||||
<PageWrapper template="box">
|
||||
<BarChart
|
||||
dots={dots}
|
||||
|
@ -49,7 +54,10 @@ function Commits({ statistic }: ICommitsProps) {
|
|||
<br/>
|
||||
<br/>
|
||||
{}
|
||||
<Title title={`${getDate(selected?.timestamp)} сделано коммитов: ${selected?.commits || '_'}`}/>
|
||||
<Title title={localization.get('page.common.commits.title2', [
|
||||
getDate(selected?.timestamp),
|
||||
selected?.commits,
|
||||
])} />
|
||||
<PageWrapper template="box">
|
||||
<DayInfo
|
||||
day={selected}
|
||||
|
|
|
@ -5,6 +5,7 @@ import NothingFound from 'ts/components/NothingFound';
|
|||
import PageWrapper from 'ts/components/Page/wrapper';
|
||||
import CandyChart from 'ts/components/CandyChart';
|
||||
import Title from 'ts/components/Title';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
interface IPopularWordsProps {
|
||||
statistic: any[];
|
||||
|
@ -24,7 +25,10 @@ function PopularWords({ statistic, mode }: IPopularWordsProps) {
|
|||
|
||||
// dots[0].color = COLOR.FIRST;
|
||||
const recommendations = [
|
||||
[dots[0].title, `самое популярное слово. Встречается ${dots[0].value} раза.`, 'fact'],
|
||||
[dots[0].title,
|
||||
localization.get('page.common.words.description', dots[0].value),
|
||||
'fact',
|
||||
],
|
||||
];
|
||||
|
||||
return (
|
||||
|
@ -32,7 +36,7 @@ function PopularWords({ statistic, mode }: IPopularWordsProps) {
|
|||
{mode !== 'print' && (
|
||||
<RecommendationsWrapper recommendations={recommendations} />
|
||||
)}
|
||||
<Title title="Статистика по словам"/>
|
||||
<Title title="page.common.words.title"/>
|
||||
<PageWrapper template="table">
|
||||
<CandyChart
|
||||
dots={dots}
|
||||
|
|
|
@ -6,6 +6,7 @@ import UiKitSelect from 'ts/components/UiKit/components/Select';
|
|||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
|
||||
import style from '../styles/user.module.scss';
|
||||
import localization from "../../../helpers/Localization";
|
||||
|
||||
interface IUserSelectProps {
|
||||
required?: boolean;
|
||||
|
@ -17,7 +18,7 @@ const UserSelect = observer(({ required, userId, onChange }: IUserSelectProps):
|
|||
const authors = dataGripStore.dataGrip.author.list;
|
||||
const options = authors.map((title: string, id: number) => ({ id, title }));
|
||||
if (!required) {
|
||||
options.unshift({ id: '', title: 'Не имеет значения' });
|
||||
options.unshift({ id: '', title: localization.get('page.common.filter.allUsers') });
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -3,6 +3,7 @@ import { observer } from 'mobx-react-lite';
|
|||
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import { Modal, Header, Body } from 'ts/components/ModalWindow';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from '../styles/print.module.scss';
|
||||
import printStore from '../store/Print';
|
||||
|
@ -16,7 +17,7 @@ const Print = observer(() => {
|
|||
}}>
|
||||
<Header>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
Что распечатываем?
|
||||
{localization.get('page.print.title')}
|
||||
</div>
|
||||
</Header>
|
||||
<Body>
|
||||
|
@ -30,7 +31,7 @@ const Print = observer(() => {
|
|||
printStore.printPage();
|
||||
}}
|
||||
>
|
||||
Текущую страницу
|
||||
{localization.get('page.print.page')}
|
||||
</UiKitButton>
|
||||
<UiKitButton
|
||||
className={style.page_wrapper_print_button}
|
||||
|
@ -38,7 +39,7 @@ const Print = observer(() => {
|
|||
printStore.printSection();
|
||||
}}
|
||||
>
|
||||
Текущий раздел
|
||||
{localization.get('page.print.type')}
|
||||
</UiKitButton>
|
||||
{false && (
|
||||
<UiKitButton
|
||||
|
@ -47,7 +48,7 @@ const Print = observer(() => {
|
|||
printStore.printAllPages();
|
||||
}}
|
||||
>
|
||||
Всю статистику
|
||||
{localization.get('page.print.all')}
|
||||
</UiKitButton>
|
||||
)}
|
||||
<UiKitButton
|
||||
|
@ -57,7 +58,7 @@ const Print = observer(() => {
|
|||
printStore.close();
|
||||
}}
|
||||
>
|
||||
Отмена
|
||||
{localization.get('page.print.cancel')}
|
||||
</UiKitButton>
|
||||
</Body>
|
||||
</Modal>
|
||||
|
|
|
@ -4,12 +4,13 @@ import { observer } from 'mobx-react-lite';
|
|||
|
||||
import Buttons from 'ts/pages/Settings/components/Buttons';
|
||||
import settingsForm from 'ts/pages/Settings/store/Form';
|
||||
import style from '../../styles/header.module.scss';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
|
||||
import Title from './Title';
|
||||
import Filters from './Filters';
|
||||
import printStore from '../../store/Print';
|
||||
import localization from "../../../../helpers/Localization";
|
||||
import style from '../../styles/header.module.scss';
|
||||
|
||||
const Header = observer((): React.ReactElement | null => {
|
||||
const navigate = useNavigate();
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import formStore from '../store/Form';
|
||||
import style from '../styles/index.module.scss';
|
||||
|
@ -17,14 +18,14 @@ const Buttons = observer((): React.ReactElement | null => {
|
|||
formStore.setInitState(formStore.initState);
|
||||
}}
|
||||
>
|
||||
Отмена
|
||||
{localization.get('page.settings.form.cancel')}
|
||||
</UiKitButton>
|
||||
<UiKitButton
|
||||
onClick={() => {
|
||||
formStore.save(formStore.state);
|
||||
}}
|
||||
>
|
||||
Сохранить
|
||||
{localization.get('page.settings.form.save')}
|
||||
</UiKitButton>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,30 +2,33 @@ import React from 'react';
|
|||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import InputString from 'ts/components/UiKit/components/InputString';
|
||||
import Select from 'ts/components/UiKit/components/Select';
|
||||
import PageBox from 'ts/components/Page/Box';
|
||||
import Title from 'ts/components/Title';
|
||||
|
||||
import formStore from '../store/Form';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
const Common = observer((): React.ReactElement | null => {
|
||||
return (
|
||||
<>
|
||||
<Title title="Префиксы ссылок"/>
|
||||
<Title title="page.settings.document.title"/>
|
||||
<PageBox>
|
||||
<InputString
|
||||
title="Для номеров задач"
|
||||
value={formStore.state?.linksPrefix?.task}
|
||||
placeholder="https://jira.com/secure/RapidBoard.jspa?task="
|
||||
title="page.settings.document.name"
|
||||
value={document.title}
|
||||
placeholder="Git статистика"
|
||||
onChange={(value: string) => {
|
||||
formStore.updateState('linksPrefix.task', value);
|
||||
document.title = value || 'Git статистика';
|
||||
}}
|
||||
/>
|
||||
<InputString
|
||||
title="Для PR"
|
||||
value={formStore.state.linksPrefix.pr}
|
||||
placeholder="https://bitbucket.com/projects/assayo/repos/frontend/pull-requests/"
|
||||
<Select
|
||||
title="page.settings.document.language"
|
||||
value={localization.language}
|
||||
options={[
|
||||
{ id: 'ru', title: 'Русский' },
|
||||
{ id: 'en', title: 'English' },
|
||||
]}
|
||||
onChange={(value: string) => {
|
||||
formStore.updateState('linksPrefix.pr', value);
|
||||
localization.language = value;
|
||||
}}
|
||||
/>
|
||||
</PageBox>
|
||||
|
|
|
@ -9,10 +9,12 @@ import NothingFound from 'ts/components/NothingFound';
|
|||
import Title from 'ts/components/Title';
|
||||
|
||||
import dataGripStore from 'ts/store/DataGrip';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import UserSetting from './User';
|
||||
import Salary from './Salary';
|
||||
import Common from './Common';
|
||||
import Prefixes from './Prefixes';
|
||||
|
||||
import { getNewEmployeesSettings } from '../helpers/getEmptySettings';
|
||||
import MailMap from './MailMap';
|
||||
|
@ -49,16 +51,15 @@ const SettingForm = observer((response: any): React.ReactElement | null => {
|
|||
<PageWrapper>
|
||||
<PageColumn>
|
||||
<Common />
|
||||
<Prefixes />
|
||||
<Salary />
|
||||
</PageColumn>
|
||||
<PageColumn>
|
||||
<Title title="Индивидуальные настройки"/>
|
||||
<Title title="page.settings.user.title"/>
|
||||
{employees.length > 0 ? (
|
||||
users
|
||||
) : (
|
||||
<NothingFound
|
||||
message="Индивидуальных настроек нет. Данные по всем сотрудникам вычисляются по общим параметрам."
|
||||
/>
|
||||
<NothingFound message="page.settings.user.notFound" />
|
||||
)}
|
||||
{authors.length && (
|
||||
<div className={style.buttons_footer}>
|
||||
|
@ -71,14 +72,14 @@ const SettingForm = observer((response: any): React.ReactElement | null => {
|
|||
]);
|
||||
}}
|
||||
>
|
||||
Добавить сотрудника
|
||||
{localization.get('page.settings.form.addEmployee')}
|
||||
</UiKitButtonMenu>
|
||||
</div>
|
||||
)}
|
||||
</PageColumn>
|
||||
</PageWrapper>
|
||||
<PageWrapper>
|
||||
<Title title="Настройки .mailmap"/>
|
||||
<Title title="page.settings.mailmap"/>
|
||||
<MailMap />
|
||||
</PageWrapper>
|
||||
</>
|
||||
|
|
|
@ -7,6 +7,8 @@ import UiKitSwitch from 'ts/components/UiKit/components/Switch';
|
|||
import PageBox from 'ts/components/Page/Box';
|
||||
import Title from 'ts/components/Title';
|
||||
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import formStore from '../store/Form';
|
||||
|
||||
const Common = observer((): React.ReactElement | null => {
|
||||
|
@ -15,14 +17,14 @@ const Common = observer((): React.ReactElement | null => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Title title="Общие данные по зарплате"/>
|
||||
<Title title="page.settings.common.title"/>
|
||||
<PageBox>
|
||||
<UiKitSwitch
|
||||
title="Тип работы над проектом"
|
||||
title="page.settings.common.type.title"
|
||||
value={defaultSalary.type}
|
||||
options={[
|
||||
{ id: 'full', title: 'Полная занятость' },
|
||||
{ id: 'part', title: 'Проектная работа' },
|
||||
{ id: 'full', title: localization.get('page.settings.common.type.full') },
|
||||
{ id: 'part', title: localization.get('page.settings.common.type.part') },
|
||||
]}
|
||||
onChange={(type: any) => {
|
||||
formStore.updateState('defaultSalary.type', type?.id);
|
||||
|
@ -30,14 +32,14 @@ const Common = observer((): React.ReactElement | null => {
|
|||
/>
|
||||
<UiKitColumns>
|
||||
<UiKitInputNumber
|
||||
title="Зарплата в месяц"
|
||||
title="page.settings.common.salary"
|
||||
value={defaultSalary.value}
|
||||
onChange={(value: number) => {
|
||||
formStore.updateState('defaultSalary.value', value);
|
||||
}}
|
||||
/>
|
||||
<UiKitSwitch
|
||||
title="Валюта"
|
||||
title="page.settings.common.currency"
|
||||
value={defaultSalary.currency}
|
||||
options={['RUB', 'USD', 'EUR']}
|
||||
onChange={(currency: string) => {
|
||||
|
@ -47,14 +49,14 @@ const Common = observer((): React.ReactElement | null => {
|
|||
</UiKitColumns>
|
||||
<UiKitColumns>
|
||||
<UiKitInputNumber
|
||||
title="Количество рабочих дней в году"
|
||||
title="page.settings.common.workDaysInYear"
|
||||
value={defaultSalary.workDaysInYear}
|
||||
onChange={(workDaysInYear: number) => {
|
||||
formStore.updateState('defaultSalary.workDaysInYear', workDaysInYear);
|
||||
}}
|
||||
/>
|
||||
<UiKitInputNumber
|
||||
title="Количество дней отпуска в год"
|
||||
title="page.settings.common.vacationDaysInYear"
|
||||
value={defaultSalary.vacationDaysInYear}
|
||||
onChange={(vacationDaysInYear: number) => {
|
||||
formStore.updateState('defaultSalary.vacationDaysInYear', vacationDaysInYear);
|
||||
|
@ -62,7 +64,7 @@ const Common = observer((): React.ReactElement | null => {
|
|||
/>
|
||||
</UiKitColumns>
|
||||
<UiKitSwitch
|
||||
title="Количество рабочих дней в неделю"
|
||||
title="page.settings.common.workDaysInWeek"
|
||||
value={defaultSalary.workDaysInWeek}
|
||||
options={[1, 2, 3, 4, 5, 6, 7]}
|
||||
onChange={(workDaysInWeek: number) => {
|
||||
|
@ -70,7 +72,7 @@ const Common = observer((): React.ReactElement | null => {
|
|||
}}
|
||||
/>
|
||||
<UiKitSwitch
|
||||
title="Рабочие дни"
|
||||
title="page.settings.common.workDaysInWeek"
|
||||
value={defaultSalary.workDaysInWeek.map((v: number, i: number) => v ? (i + 1) : null)}
|
||||
options={[
|
||||
{ id: 1, title: 'Пн' },
|
||||
|
|
|
@ -5,6 +5,7 @@ import UiKitButton from 'ts/components/UiKit/components/Button';
|
|||
import confirm from 'ts/components/ModalWindow/store/Confirm';
|
||||
import PageBox from 'ts/components/Page/Box';
|
||||
import Title from 'ts/components/Title';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import { getNewEmploymentContract } from '../helpers/getEmptySettings';
|
||||
import UserSalary from './UserSalary';
|
||||
|
@ -65,7 +66,7 @@ function UserSetting({
|
|||
});
|
||||
}}
|
||||
>
|
||||
Добавить трудовой договор
|
||||
{localization.get('page.settings.form.addContract')}
|
||||
</UiKitButton>
|
||||
</div>
|
||||
</PageBox>
|
||||
|
|
|
@ -8,6 +8,7 @@ import UiKitButton from 'ts/components/UiKit/components/Button';
|
|||
import UiKitDate from 'ts/components/UiKit/components/Date';
|
||||
import confirm from 'ts/components/ModalWindow/store/Confirm';
|
||||
import Title from 'ts/components/Title';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import style from '../styles/index.module.scss';
|
||||
|
||||
|
@ -28,7 +29,7 @@ function UserSalary({
|
|||
return (
|
||||
<div className={style.salary}>
|
||||
<Title
|
||||
title={`Дополнение к трудовому договору №${index}`}
|
||||
title={localization.get('page.settings.user.subTitle', index)}
|
||||
className={isOpen ? '' : style.salary_title}
|
||||
/>
|
||||
<div className={style.salary_icons}>
|
||||
|
@ -42,14 +43,14 @@ function UserSalary({
|
|||
<>
|
||||
<UiKitColumns>
|
||||
<UiKitDate
|
||||
title="Дата начала действия"
|
||||
title="page.settings.user.from"
|
||||
value={salary?.from}
|
||||
onChange={(from: string) => {
|
||||
onChange({ ...salary, from });
|
||||
}}
|
||||
/>
|
||||
<UiKitSwitch
|
||||
title="Количество рабочих дней в неделю"
|
||||
title="page.settings.common.workDaysInWeek"
|
||||
value={salary.workDaysInWeek}
|
||||
options={[1, 2, 3, 4, 5, 6, 7]}
|
||||
onChange={(workDaysInWeek: number) => {
|
||||
|
@ -59,14 +60,14 @@ function UserSalary({
|
|||
</UiKitColumns>
|
||||
<UiKitColumns>
|
||||
<UiKitInputNumber
|
||||
title="Зарплата в месяц"
|
||||
title="page.settings.common.salary"
|
||||
value={salary?.value}
|
||||
onChange={(value: number) => {
|
||||
onChange({ ...salary, value });
|
||||
}}
|
||||
/>
|
||||
<UiKitSwitch
|
||||
title="Валюта"
|
||||
title="page.settings.common.currency"
|
||||
value={salary?.currency}
|
||||
options={['RUB', 'USD', 'EUR']}
|
||||
onChange={(currency: string) => {
|
||||
|
@ -76,14 +77,14 @@ function UserSalary({
|
|||
</UiKitColumns>
|
||||
<UiKitColumns>
|
||||
<UiKitInputNumber
|
||||
title="Количество рабочих дней в году"
|
||||
title="page.settings.common.workDaysInYear"
|
||||
value={salary?.workDaysInYear}
|
||||
onChange={(workDaysInYear: number) => {
|
||||
onChange({ ...salary, workDaysInYear });
|
||||
}}
|
||||
/>
|
||||
<UiKitInputNumber
|
||||
title="Количество дней отпуска в год"
|
||||
title="page.settings.common.vacationDaysInYear"
|
||||
value={salary?.vacationDaysInYear}
|
||||
onChange={(vacationDaysInYear: number) => {
|
||||
onChange({ ...salary, vacationDaysInYear });
|
||||
|
@ -95,7 +96,7 @@ function UserSalary({
|
|||
type="second"
|
||||
onClick={() => confirm.open().then(() => onRemove())}
|
||||
>
|
||||
Удалить
|
||||
{localization.get('page.settings.form.remove')}
|
||||
</UiKitButton>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -43,7 +43,7 @@ function AllPR({
|
|||
{mode === 'print' ? (
|
||||
<Column
|
||||
isSortable
|
||||
title="Задача"
|
||||
title="page.team.pr.task"
|
||||
properties="task"
|
||||
width={120}
|
||||
/>
|
||||
|
@ -64,7 +64,7 @@ function AllPR({
|
|||
</>
|
||||
);
|
||||
}}
|
||||
title="Задача"
|
||||
title="page.team.pr.task"
|
||||
properties="task"
|
||||
width={120}
|
||||
/>
|
||||
|
@ -72,7 +72,7 @@ function AllPR({
|
|||
<Column
|
||||
isSortable
|
||||
template={ColumnTypesEnum.STRING}
|
||||
title="Первый коммит"
|
||||
title="page.team.pr.firstCommitTime"
|
||||
properties="beginTaskTime"
|
||||
formatter={getDate}
|
||||
width={130}
|
||||
|
@ -80,7 +80,7 @@ function AllPR({
|
|||
<Column
|
||||
isSortable
|
||||
template={ColumnTypesEnum.STRING}
|
||||
title="Последний"
|
||||
title="page.team.pr.lastCommitTime"
|
||||
properties="endTaskTime"
|
||||
formatter={getDate}
|
||||
width={130}
|
||||
|
@ -92,7 +92,7 @@ function AllPR({
|
|||
/>
|
||||
<Column
|
||||
isSortable
|
||||
title="Дней в работе"
|
||||
title="page.team.pr.workDays"
|
||||
properties="workDays"
|
||||
minWidth={100}
|
||||
template={(value: any) => (
|
||||
|
@ -109,7 +109,7 @@ function AllPR({
|
|||
/>
|
||||
<Column
|
||||
isSortable
|
||||
title="Коммиты"
|
||||
title="page.team.pr.commits"
|
||||
properties="commitsByAuthors"
|
||||
minWidth={100}
|
||||
template={(details: any) => (
|
||||
|
@ -126,7 +126,7 @@ function AllPR({
|
|||
/>
|
||||
<Column
|
||||
isSortable
|
||||
title="Дней ожидания влития"
|
||||
title="page.team.pr.delayDays"
|
||||
properties="delayDays"
|
||||
minWidth={200}
|
||||
template={(value: any) => (
|
||||
|
@ -139,7 +139,7 @@ function AllPR({
|
|||
<Column
|
||||
isSortable
|
||||
template={ColumnTypesEnum.STRING}
|
||||
title="Дата влития"
|
||||
title="page.team.pr.date"
|
||||
properties="milliseconds"
|
||||
formatter={getDate}
|
||||
width={130}
|
||||
|
@ -147,7 +147,7 @@ function AllPR({
|
|||
<Column
|
||||
isSortable
|
||||
template={ColumnTypesEnum.STRING}
|
||||
title="Влил"
|
||||
title="page.team.pr.mergeAuthor"
|
||||
properties="author"
|
||||
width={250}
|
||||
/>
|
||||
|
|
|
@ -30,8 +30,11 @@ function Authors({ response, updateSort }: IAuthorsProps) {
|
|||
const timeChart = getOptions({ order, limit: 3 });
|
||||
const weightedAverageChart = getOptions({
|
||||
max: getMax(response, 'weightedAverage'),
|
||||
order: ['разработка', 'ожидание'],
|
||||
suffix: 'дней',
|
||||
order: [
|
||||
'page.team.pr.work',
|
||||
'page.team.pr.delay',
|
||||
],
|
||||
suffix: 'page.team.pr.days',
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -43,12 +46,12 @@ function Authors({ response, updateSort }: IAuthorsProps) {
|
|||
<Column
|
||||
isSortable
|
||||
template={ColumnTypesEnum.STRING}
|
||||
title="Сотрудник"
|
||||
title="page.team.pr.author"
|
||||
properties="author"
|
||||
width={250}
|
||||
/>
|
||||
<Column
|
||||
title="Время разработки"
|
||||
title="page.team.pr.workDays"
|
||||
properties="workDays"
|
||||
template={(details: any) => (
|
||||
<LineChart
|
||||
|
@ -58,7 +61,7 @@ function Authors({ response, updateSort }: IAuthorsProps) {
|
|||
)}
|
||||
/>
|
||||
<Column
|
||||
title="Время ожидания влития"
|
||||
title="page.team.pr.delayDays"
|
||||
properties="delayDays"
|
||||
template={(details: any) => (
|
||||
<LineChart
|
||||
|
@ -72,7 +75,7 @@ function Authors({ response, updateSort }: IAuthorsProps) {
|
|||
template={ColumnTypesEnum.SHORT_NUMBER}
|
||||
/>
|
||||
<Column
|
||||
title="Среднее время поставки (дни)"
|
||||
title="page.team.pr.middleTimeRelease"
|
||||
properties="weightedAverageDetails"
|
||||
width={300}
|
||||
template={(item: any, row: any) => (
|
||||
|
@ -80,8 +83,8 @@ function Authors({ response, updateSort }: IAuthorsProps) {
|
|||
options={weightedAverageChart}
|
||||
value={row.weightedAverage}
|
||||
details={{
|
||||
'разработка': item.workDays,
|
||||
'ожидание': item.delayDays,
|
||||
'page.team.pr.work': item.workDays,
|
||||
'page.team.pr.delay': item.delayDays,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -13,7 +13,7 @@ function Total() {
|
|||
const allPR = dataGripStore.dataGrip.pr.statistic;
|
||||
|
||||
const workChart = DataGripByPR.getPRByGroups(allPR, 'workDays');
|
||||
const workChartOptions = getOptions({ order: workChart.order, limit: 3, suffix: 'задачь' });
|
||||
const workChartOptions = getOptions({ order: workChart.order, limit: 3, suffix: 'page.team.pr.tasks' });
|
||||
|
||||
const delayChart = DataGripByPR.getPRByGroups(allPR, 'delayDays');
|
||||
const delayChartOptions = getOptions({ order: delayChart.order, limit: 3, suffix: 'PR' });
|
||||
|
@ -23,8 +23,8 @@ function Total() {
|
|||
const weightedAverage = workDaysWeightedAverage + delayDaysWeightedAverage;
|
||||
|
||||
const weightedAverageChart = getOptions({ // @ts-ignore
|
||||
order: ['разработка', 'ожидание'],
|
||||
suffix: 'дней',
|
||||
order: ['page.team.pr.word', 'page.team.pr.delay'],
|
||||
suffix: 'page.team.pr.days',
|
||||
});
|
||||
|
||||
const rows = [
|
||||
|
@ -42,7 +42,7 @@ function Total() {
|
|||
return (
|
||||
<Table rows={rows}>
|
||||
<Column
|
||||
title="Время разработки"
|
||||
title="page.team.pr.workDays"
|
||||
properties="workDays"
|
||||
template={(details: any) => (
|
||||
<LineChart
|
||||
|
@ -52,7 +52,7 @@ function Total() {
|
|||
)}
|
||||
/>
|
||||
<Column
|
||||
title="Время ожидания влития"
|
||||
title="page.team.pr.delayDays"
|
||||
properties="delayDays"
|
||||
template={(details: any) => (
|
||||
<LineChart
|
||||
|
@ -66,15 +66,15 @@ function Total() {
|
|||
template={ColumnTypesEnum.SHORT_NUMBER}
|
||||
/>
|
||||
<Column
|
||||
title="Среднее время поставки (дни)"
|
||||
title="page.team.pr.middleTimeRelease"
|
||||
properties="weightedAverageDetails"
|
||||
width={300}
|
||||
template={(item: any) => (
|
||||
<LineChart
|
||||
options={weightedAverageChart}
|
||||
details={{
|
||||
'разработка': item.workDays,
|
||||
'ожидание': item.delayDays,
|
||||
'page.team.pr.work': item.workDays,
|
||||
'page.team.pr.delay': item.delayDays,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -15,6 +15,7 @@ import getFakeLoader from 'ts/components/DataLoader/helpers/formatter';
|
|||
import NothingFound from 'ts/components/NothingFound';
|
||||
import Title from 'ts/components/Title';
|
||||
import PageBreak from 'ts/pages/Common/components/PageBreak';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
|
||||
import Total from './Total';
|
||||
import Authors from './Authors';
|
||||
|
@ -32,7 +33,7 @@ const PR = observer(({
|
|||
|
||||
return (
|
||||
<>
|
||||
<Title title="Время потраченное на одну задачу"/>
|
||||
<Title title="page.team.pr.oneTaskDays"/>
|
||||
<PageWrapper template="table">
|
||||
<Total/>
|
||||
</PageWrapper>
|
||||
|
@ -40,22 +41,22 @@ const PR = observer(({
|
|||
<PageWrapper>
|
||||
<PageColumn>
|
||||
<Description
|
||||
text="*Время разработки* это разница времени от первого до последнего коммита по задаче. Не важно были перерывы в несколько дней между коммитами или нет. Сам факт какого-либо коммита увеличивает время."
|
||||
text={localization.get('page.team.pr.description1')}
|
||||
/>
|
||||
<Description
|
||||
text="*Время ожидания* это время между последним коммитом и влитием кода. Оно показывает фактический простой в ожидании чего-либо."
|
||||
text={localization.get('page.team.pr.description2')}
|
||||
/>
|
||||
</PageColumn>
|
||||
<PageColumn>
|
||||
<Description
|
||||
text="*Зачем отображать время разработки* без разбивки на кодинг и код-ревью? Затем, чтобы показать бизнесу фактическое время поставки кода. Ожидание тестирования, замечания на ревью, проблемы DevOps и прочие несовершенства процесса, как раз уже заложены в этот срок."
|
||||
text={localization.get('page.team.pr.description3')}
|
||||
/>
|
||||
</PageColumn>
|
||||
</PageWrapper>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<Title title="Статистика по сотрудникам"/>
|
||||
<Title title="page.team.pr.statByAuthors"/>
|
||||
<PageWrapper template="table">
|
||||
<DataLoader
|
||||
to="response"
|
||||
|
@ -69,7 +70,7 @@ const PR = observer(({
|
|||
</PageWrapper>
|
||||
|
||||
<PageBreak/>
|
||||
<Title title="Длительное ожидание влития"/>
|
||||
<Title title="page.team.pr.longDelay"/>
|
||||
<PageWrapper template="table">
|
||||
<DataLoader
|
||||
to="response"
|
||||
|
|
|
@ -64,7 +64,6 @@ function TreeView({ response }: ITreeViewProps) {
|
|||
}}
|
||||
/>
|
||||
<Column
|
||||
title="Процент перезаписи строк"
|
||||
properties="file"
|
||||
minWidth={250}
|
||||
template={(file: any) => (
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
import Console from 'ts/components/Console';
|
||||
import localization from 'ts/helpers/Localization';
|
||||
import Description from 'ts/components/Description';
|
||||
|
||||
import style from './styles/index.module.scss';
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import getFileTreeWithStatistic from 'ts/helpers/DataGrip/helpers/tree';
|
|||
import Parser from 'ts/helpers/Parser';
|
||||
import ParserTelegramm from 'ts/helpers/ParserTelegramm';
|
||||
import { setDefaultValues } from 'ts/pages/Settings/helpers/getEmptySettings';
|
||||
import getTitle from 'ts/helpers/Title';
|
||||
|
||||
import settingsStore from './Settings';
|
||||
|
||||
|
@ -71,7 +72,9 @@ class DataGripStore implements IDataGripStore {
|
|||
|
||||
this.dataGrip = null;
|
||||
this.dataGrip = dataGrip;
|
||||
console.dir(dataGrip);
|
||||
|
||||
console.dir(this.dataGrip);
|
||||
document.title = getTitle(this.dataGrip, this.commits);
|
||||
}
|
||||
|
||||
setTelegrammMessages(dump?: any[]) {
|
||||
|
|
Loading…
Reference in a new issue