JIRA-1234 feat(lang): test test test
|
@ -1,17 +1,17 @@
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.css": "./static/css/main.48701252.css",
|
"main.css": "./static/css/main.f032b99c.css",
|
||||||
"main.js": "./static/js/main.7da5e350.js",
|
"main.js": "./static/js/main.9af297c4.js",
|
||||||
"static/media/car.png": "./static/media/car.b8dd8738e37fe866285f.png",
|
"static/media/car.png": "./static/media/car.b8dd8738e37fe866285f.png",
|
||||||
"index.html": "./index.html",
|
"index.html": "./index.html",
|
||||||
"static/media/warning.svg": "./static/media/warning.e39a87773603f3ab157f.svg",
|
"static/media/warning.svg": "./static/media/warning.e39a87773603f3ab157f.svg",
|
||||||
"static/media/info.svg": "./static/media/info.954631f6b19e3fe9c495.svg",
|
"static/media/info.svg": "./static/media/info.954631f6b19e3fe9c495.svg",
|
||||||
"static/media/alert.svg": "./static/media/alert.41e2b99c481139c13074.svg",
|
"static/media/alert.svg": "./static/media/alert.41e2b99c481139c13074.svg",
|
||||||
"main.48701252.css.map": "./static/css/main.48701252.css.map",
|
"main.f032b99c.css.map": "./static/css/main.f032b99c.css.map",
|
||||||
"main.7da5e350.js.map": "./static/js/main.7da5e350.js.map"
|
"main.9af297c4.js.map": "./static/js/main.9af297c4.js.map"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/css/main.48701252.css",
|
"static/css/main.f032b99c.css",
|
||||||
"static/js/main.7da5e350.js"
|
"static/js/main.9af297c4.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
BIN
build/assets/cards/print.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
build/assets/character/halo/1.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
build/assets/character/weapon/1.png
Normal file
After Width: | Height: | Size: 291 KiB |
BIN
build/assets/character/weapon/2.png
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
build/assets/character/weapon/3.png
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
build/assets/character/weapon/4.png
Normal file
After Width: | Height: | Size: 355 KiB |
BIN
build/assets/character/weapon/5.png
Normal file
After Width: | Height: | Size: 385 KiB |
BIN
build/assets/character/weapon/6.png
Normal file
After Width: | Height: | Size: 392 KiB |
BIN
build/assets/character/weapon/7.png
Normal file
After Width: | Height: | Size: 422 KiB |
BIN
build/assets/character/weapon/8.png
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
build/assets/character/weapon/9.png
Normal file
After Width: | Height: | Size: 474 KiB |
BIN
build/assets/character/wings/1.png
Normal file
After Width: | Height: | Size: 291 KiB |
BIN
build/assets/character/wings/2.png
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
build/assets/character/wings/3.png
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
build/assets/character/wings/4.png
Normal file
After Width: | Height: | Size: 355 KiB |
BIN
build/assets/character/wings/5.png
Normal file
After Width: | Height: | Size: 385 KiB |
BIN
build/assets/character/wings/6.png
Normal file
After Width: | Height: | Size: 392 KiB |
BIN
build/assets/character/wings/7.png
Normal file
After Width: | Height: | Size: 422 KiB |
BIN
build/assets/character/wings/8.png
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
build/assets/character/wings/9.png
Normal file
After Width: | Height: | Size: 474 KiB |
2
build/assets/close.svg
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 201 B |
3212
build/assets/log.txt
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M658-648v-132H302v132h-60v-192h476v192h-60Zm-518 60h680-680Zm599 95q12 0 21-9t9-21q0-12-9-21t-21-9q-12 0-21 9t-9 21q0 12 9 21t21 9Zm-81 313v-192H302v192h356Zm60 60H242v-176H80v-246q0-45.05 30.5-75.525Q141-648 186-648h588q45.05 0 75.525 30.475Q880-587.05 880-542v246H718v176Zm102-236v-186.215Q820-562 806.775-575 793.55-588 774-588H186q-19.55 0-32.775 13.225Q140-561.55 140-542v186h102v-76h476v76h102Z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48" fill="#84858D"><path d="M658-648v-132H302v132h-60v-192h476v192h-60Zm-518 60h680-680Zm599 95q12 0 21-9t9-21q0-12-9-21t-21-9q-12 0-21 9t-9 21q0 12 9 21t21 9Zm-81 313v-192H302v192h356Zm60 60H242v-176H80v-246q0-45.05 30.5-75.525Q141-648 186-648h588q45.05 0 75.525 30.475Q880-587.05 880-542v246H718v176Zm102-236v-186.215Q820-562 806.775-575 793.55-588 774-588H186q-19.55 0-32.775 13.225Q140-561.55 140-542v186h102v-76h476v76h102Z"/></svg>
|
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 521 B |
87642
build/assets/nexign.txt
|
@ -1 +1 @@
|
||||||
<!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.7da5e350.js"></script><link href="./static/css/main.48701252.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script type="text/javascript">!function(e,t,c,n,r,a,s){e[r]=e[r]||function(){(e[r].a=e[r].a||[]).push(arguments)},e[r].l=1*new Date;for(var i=0;i<document.scripts.length;i++)if(document.scripts[i].src===n)return;a=t.createElement(c),s=t.getElementsByTagName(c)[0],a.async=1,a.src=n,s.parentNode.insertBefore(a,s)}(window,document,"script","https://mc.yandex.ru/metrika/tag.js","ym"),ym(94903985,"init",{clickmap:!0,trackLinks:!0,accurateTrackBounce:!0,webvisor:!0})</script><noscript><div><img src="https://mc.yandex.ru/watch/94903985" style="position:absolute;left:-9999px" alt=""/></div></noscript></body></html>
|
<!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>
|
2
build/static/css/main.f032b99c.css
Normal file
1
build/static/css/main.f032b99c.css.map
Normal file
3
build/static/js/main.9af297c4.js
Normal file
1
build/static/js/main.9af297c4.js.map
Normal file
BIN
public/assets/cards/print.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
public/assets/character/halo/1.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
public/assets/character/weapon/1.png
Normal file
After Width: | Height: | Size: 291 KiB |
BIN
public/assets/character/weapon/2.png
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
public/assets/character/weapon/3.png
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
public/assets/character/weapon/4.png
Normal file
After Width: | Height: | Size: 355 KiB |
BIN
public/assets/character/weapon/5.png
Normal file
After Width: | Height: | Size: 385 KiB |
BIN
public/assets/character/weapon/6.png
Normal file
After Width: | Height: | Size: 392 KiB |
BIN
public/assets/character/weapon/7.png
Normal file
After Width: | Height: | Size: 422 KiB |
BIN
public/assets/character/weapon/8.png
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
public/assets/character/weapon/9.png
Normal file
After Width: | Height: | Size: 474 KiB |
BIN
public/assets/character/wings/1.png
Normal file
After Width: | Height: | Size: 291 KiB |
BIN
public/assets/character/wings/2.png
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
public/assets/character/wings/3.png
Normal file
After Width: | Height: | Size: 324 KiB |
BIN
public/assets/character/wings/4.png
Normal file
After Width: | Height: | Size: 355 KiB |
BIN
public/assets/character/wings/5.png
Normal file
After Width: | Height: | Size: 385 KiB |
BIN
public/assets/character/wings/6.png
Normal file
After Width: | Height: | Size: 392 KiB |
BIN
public/assets/character/wings/7.png
Normal file
After Width: | Height: | Size: 422 KiB |
BIN
public/assets/character/wings/8.png
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
public/assets/character/wings/9.png
Normal file
After Width: | Height: | Size: 474 KiB |
2
public/assets/close.svg
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 201 B |
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M658-648v-132H302v132h-60v-192h476v192h-60Zm-518 60h680-680Zm599 95q12 0 21-9t9-21q0-12-9-21t-21-9q-12 0-21 9t-9 21q0 12 9 21t21 9Zm-81 313v-192H302v192h356Zm60 60H242v-176H80v-246q0-45.05 30.5-75.525Q141-648 186-648h588q45.05 0 75.525 30.475Q880-587.05 880-542v246H718v176Zm102-236v-186.215Q820-562 806.775-575 793.55-588 774-588H186q-19.55 0-32.775 13.225Q140-561.55 140-542v186h102v-76h476v76h102Z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48" fill="#84858D"><path d="M658-648v-132H302v132h-60v-192h476v192h-60Zm-518 60h680-680Zm599 95q12 0 21-9t9-21q0-12-9-21t-21-9q-12 0-21 9t-9 21q0 12 9 21t21 9Zm-81 313v-192H302v192h356Zm60 60H242v-176H80v-246q0-45.05 30.5-75.525Q141-648 186-648h588q45.05 0 75.525 30.475Q880-587.05 880-542v246H718v176Zm102-236v-186.215Q820-562 806.775-575 793.55-588 774-588H186q-19.55 0-32.775 13.225Q140-561.55 140-542v186h102v-76h476v76h102Z"/></svg>
|
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 521 B |
87642
public/assets/nexign.txt
|
@ -64,7 +64,7 @@
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
||||||
<!-- Yandex.Metrika counter -->
|
<!-- Yandex.Metrika counter
|
||||||
<script type="text/javascript" >
|
<script type="text/javascript" >
|
||||||
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||||
m[i].l=1*new Date();
|
m[i].l=1*new Date();
|
||||||
|
@ -80,6 +80,6 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<noscript><div><img src="https://mc.yandex.ru/watch/94903985" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
<noscript><div><img src="https://mc.yandex.ru/watch/94903985" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
||||||
<!-- /Yandex.Metrika counter -->
|
/Yandex.Metrika counter -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
BIN
src/assets/cards/print.png
Normal file
After Width: | Height: | Size: 16 KiB |
2
src/assets/close.svg
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#84858D"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 201 B |
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M658-648v-132H302v132h-60v-192h476v192h-60Zm-518 60h680-680Zm599 95q12 0 21-9t9-21q0-12-9-21t-21-9q-12 0-21 9t-9 21q0 12 9 21t21 9Zm-81 313v-192H302v192h356Zm60 60H242v-176H80v-246q0-45.05 30.5-75.525Q141-648 186-648h588q45.05 0 75.525 30.475Q880-587.05 880-542v246H718v176Zm102-236v-186.215Q820-562 806.775-575 793.55-588 774-588H186q-19.55 0-32.775 13.225Q140-561.55 140-542v186h102v-76h476v76h102Z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48" fill="#84858D"><path d="M658-648v-132H302v132h-60v-192h476v192h-60Zm-518 60h680-680Zm599 95q12 0 21-9t9-21q0-12-9-21t-21-9q-12 0-21 9t-9 21q0 12 9 21t21 9Zm-81 313v-192H302v192h356Zm60 60H242v-176H80v-246q0-45.05 30.5-75.525Q141-648 186-648h588q45.05 0 75.525 30.475Q880-587.05 880-542v246H718v176Zm102-236v-186.215Q820-562 806.775-575 793.55-588 774-588H186q-19.55 0-32.775 13.225Q140-561.55 140-542v186h102v-76h476v76h102Z"/></svg>
|
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 521 B |
|
@ -26,8 +26,9 @@
|
||||||
--color-black: #12131B;
|
--color-black: #12131B;
|
||||||
--color-grey: #CBCBCD;
|
--color-grey: #CBCBCD;
|
||||||
--color-border: #E2E9F0;
|
--color-border: #E2E9F0;
|
||||||
--color-button: #0D69F2;
|
--color-button: #1A73E8;
|
||||||
--color-button-2: #0B59CC;
|
--color-button-2: #3081EA;
|
||||||
|
--color-button-3: #0B59CC;
|
||||||
|
|
||||||
--color-11: #7F9BE0;
|
--color-11: #7F9BE0;
|
||||||
--color-12: #E9A5A1;
|
--color-12: #E9A5A1;
|
||||||
|
|
27
src/ts/components/Character/components/Halo.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import IHashMap from 'ts/interfaces/HashMap';
|
||||||
|
|
||||||
|
import style from '../styles/index.module.scss';
|
||||||
|
|
||||||
|
interface IWeaponProps {
|
||||||
|
tasksTypes?: IHashMap<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Weapon({ tasksTypes }: IWeaponProps) {
|
||||||
|
if (!tasksTypes) return null;
|
||||||
|
|
||||||
|
console.log(tasksTypes);
|
||||||
|
// if (tasksNumber > 750) level = 1;
|
||||||
|
// if (tasksNumber > 1000) level = 1;
|
||||||
|
// if (tasksNumber > 1500) level = 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={style.character_halo}
|
||||||
|
style={{ backgroundImage: 'url("./assets/character/halo/1.png")' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Weapon;
|
26
src/ts/components/Character/components/Layers.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import style from '../styles/index.module.scss';
|
||||||
|
|
||||||
|
interface ILayersProps {
|
||||||
|
type: string;
|
||||||
|
level?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Layers({ type, level }: ILayersProps) {
|
||||||
|
const content = [];
|
||||||
|
|
||||||
|
for (let layer = level || 0; layer > 0; layer--) {
|
||||||
|
content.push((
|
||||||
|
<img
|
||||||
|
key={`${type}_${layer}`}
|
||||||
|
className={style.character_layer}
|
||||||
|
src={`./assets/character/${type}/${layer}.png`}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>{content}</>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layers;
|
19
src/ts/components/Character/helpers/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export function getWingsLevel(workedDays: number) {
|
||||||
|
const month = Math.floor(workedDays / 30);
|
||||||
|
return month < 36
|
||||||
|
? [
|
||||||
|
0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, // 1 year
|
||||||
|
4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, // 2 year
|
||||||
|
8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, // 3 year
|
||||||
|
][month] : 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWeaponLevel(tasksNumber: number) {
|
||||||
|
if (tasksNumber > 500) return 6;
|
||||||
|
if (tasksNumber > 300) return 5;
|
||||||
|
if (tasksNumber > 200) return 4;
|
||||||
|
if (tasksNumber > 100) return 3;
|
||||||
|
if (tasksNumber > 50) return 2;
|
||||||
|
if (tasksNumber > 25) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
33
src/ts/components/Character/index.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Halo from './components/Halo';
|
||||||
|
import {
|
||||||
|
getWeaponLevel,
|
||||||
|
getWingsLevel,
|
||||||
|
} from './helpers';
|
||||||
|
import Layers from './components/Layers';
|
||||||
|
import style from './styles/index.module.scss';
|
||||||
|
|
||||||
|
interface ICharacterProps {
|
||||||
|
user: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Character({ user }: ICharacterProps) {
|
||||||
|
if (!user) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={style.character}>
|
||||||
|
<Halo tasksTypes={user?.types} />
|
||||||
|
<Layers
|
||||||
|
type="weapon"
|
||||||
|
level={getWingsLevel(user?.allDaysInProject)}
|
||||||
|
/>
|
||||||
|
<Layers
|
||||||
|
type="weapon"
|
||||||
|
level={getWeaponLevel(user?.tasks?.length)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Character;
|
46
src/ts/components/Character/styles/index.module.scss
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
@import '../../../../styles/variables';
|
||||||
|
|
||||||
|
.character {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 500px;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&_layer {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_halo {
|
||||||
|
--temp-halo: 70px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 7%;
|
||||||
|
left: 45%;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
width: var(--temp-halo);
|
||||||
|
height: var(--temp-halo);
|
||||||
|
|
||||||
|
box-shadow: -5px 0 15px red;
|
||||||
|
border-radius: var(--temp-halo);
|
||||||
|
background-size: 100% 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
animation: 9s linear 1s infinite both running slidein;
|
||||||
|
animation-name: character_halo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes character_halo {
|
||||||
|
from {
|
||||||
|
transform: rotateZ(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotateZ(360deg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import localization from 'ts/helpers/Localization';
|
||||||
|
|
||||||
interface ILineProps {
|
interface ILineProps {
|
||||||
value?: number;
|
value?: number;
|
||||||
width?: number;
|
width?: number;
|
||||||
|
@ -23,12 +25,15 @@ function Line({
|
||||||
}: ILineProps): React.ReactElement | null {
|
}: ILineProps): React.ReactElement | null {
|
||||||
if (!width || width <= 0) return null;
|
if (!width || width <= 0) return null;
|
||||||
|
|
||||||
const formattedTitle = title || '';
|
const formattedTitle = localization.get(title || '');
|
||||||
|
const localizationDescription = localization.get(description || '');
|
||||||
|
const fullDescription = localizationDescription || formattedTitle;
|
||||||
|
|
||||||
const formattedValue = formatter?.(value);
|
const formattedValue = formatter?.(value);
|
||||||
const formattedSuffix = suffix ? ` ${suffix}` : '';
|
const formattedSuffix = suffix ? ` ${localization.get(suffix || '')}` : '';
|
||||||
const formattedDescription = value
|
const formattedDescription = value
|
||||||
? `${width}% (${formattedValue}${formattedSuffix}) ${description || formattedTitle}`
|
? `${width}% (${formattedValue}${formattedSuffix}) ${fullDescription}`
|
||||||
: `${width}% ${description || formattedTitle}`;
|
: `${width}% ${fullDescription}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -24,6 +24,7 @@ const Header = observer(({
|
||||||
{onClose ? (
|
{onClose ? (
|
||||||
<img
|
<img
|
||||||
id={`${id}-close`}
|
id={`${id}-close`}
|
||||||
|
src="./assets/close.svg"
|
||||||
className={`${style.modal_window_close} ${className || ''}`}
|
className={`${style.modal_window_close} ${className || ''}`}
|
||||||
onClick={(event: any) => {
|
onClick={(event: any) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import localization from 'ts/helpers/Localization';
|
||||||
|
|
||||||
import style from './index.module.scss';
|
import style from './index.module.scss';
|
||||||
|
|
||||||
interface ITitleProps {
|
interface ITitleProps {
|
||||||
|
@ -15,7 +17,7 @@ function Title({
|
||||||
}: ITitleProps) {
|
}: ITitleProps) {
|
||||||
return (
|
return (
|
||||||
<h3 className={`${style.title} ${addPadding ? style.title_padding : ''} ${className || ''}`}>
|
<h3 className={`${style.title} ${addPadding ? style.title_padding : ''} ${className || ''}`}>
|
||||||
{title || ''}
|
{localization.get(title || '')}
|
||||||
</h3>
|
</h3>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
--button-color-text: #FFFFFF;
|
--button-color-text: #FFFFFF;
|
||||||
--button-color-border: var(--color-button);
|
--button-color-border: var(--color-button);
|
||||||
--button-color-hover: var(--color-button-2);
|
--button-color-hover: var(--color-button-2);
|
||||||
|
--button-color-active: var(--color-button-3);
|
||||||
|
|
||||||
&_slim,
|
&_slim,
|
||||||
&_second {
|
&_second {
|
||||||
|
@ -77,6 +78,7 @@
|
||||||
--button-color-text: var(--color-black);
|
--button-color-text: var(--color-black);
|
||||||
--button-color-border: var(--color-border);
|
--button-color-border: var(--color-border);
|
||||||
--button-color-hover: var(--color-border);
|
--button-color-hover: var(--color-border);
|
||||||
|
--button-color-active: var(--color-border);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +107,10 @@
|
||||||
background-color: var(--button-color-hover);
|
background-color: var(--button-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--button-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
|
|
@ -103,6 +103,19 @@ localization.parse('ru', `
|
||||||
§ page.team.week.files: Изменения файлов
|
§ page.team.week.files: Изменения файлов
|
||||||
§ page.team.week.days: Дни с коммитами и без
|
§ page.team.week.days: Дни с коммитами и без
|
||||||
§ page.team.week.lossesDetails: Кто не коммитил
|
§ page.team.week.lossesDetails: Кто не коммитил
|
||||||
|
§ page.person.total.title: Основные характеристики
|
||||||
|
§ page.person.total.daysWorked.title: дней работы
|
||||||
|
§ page.person.total.daysWorked.description: Учтены только дни, в которые делались коммиты
|
||||||
|
§ page.person.total.tasks.title: задач
|
||||||
|
§ page.person.total.tasks.description: Если коммиты правильно подписаны
|
||||||
|
§ page.person.character.title: Персонаж
|
||||||
|
§ page.person.achievement.title: Достижения
|
||||||
|
§ page.person.achievement.positive: Позитивные
|
||||||
|
§ page.person.achievement.normal: Нейтральные
|
||||||
|
§ page.person.achievement.negative: Негативные
|
||||||
|
§ page.person.achievement.description: Чем больше сотрудник набрал отрицательных достижений, тем больше вероятность, что ситуация нестандартная. Возможно, стоит изменить режим его работы, задачи или отчётность. Следует поговорить с ним и узнать, какие проблемы мешают его работе.
|
||||||
|
§ page.person.gets.title: Взятые геты:
|
||||||
|
§ page.person.gets.description: «Взять гет» в данном случае означает первым оставить коммит к задаче с «красивым» номером.
|
||||||
§ page.person.business.days.title: дней работы
|
§ page.person.business.days.title: дней работы
|
||||||
§ page.person.business.days.description: Учтены только дни, в которые делались коммиты
|
§ page.person.business.days.description: Учтены только дни, в которые делались коммиты
|
||||||
§ page.person.business.tasks.title: задач
|
§ page.person.business.tasks.title: задач
|
||||||
|
@ -124,18 +137,20 @@ git может показать малое количество изменени
|
||||||
будет отмечен, как скачок «удаленных» и «добавленных» строк.
|
будет отмечен, как скачок «удаленных» и «добавленных» строк.
|
||||||
§ page.person.changes.description: Список коммитов и количество изменений в них за этот день:
|
§ page.person.changes.description: Список коммитов и количество изменений в них за этот день:
|
||||||
§ page.person.commits.title: Список коммитов:
|
§ page.person.commits.title: Список коммитов:
|
||||||
|
§ page.person.money.title.total: За всё время
|
||||||
|
§ page.person.money.title.middle: Средняя стоимость
|
||||||
§ page.person.money.moneyAll.title: получил
|
§ page.person.money.moneyAll.title: получил
|
||||||
§ page.person.money.moneyAll.description: Предполагаемая сумма зп с проекта (см. настройки)
|
§ page.person.money.moneyAll.description: Предполагаемая сумма зп с проекта (см. настройки)
|
||||||
§ page.person.money.moneyWorked.title: отработал
|
§ page.person.money.moneyWorked.title: отработал
|
||||||
§ page.person.money.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
|
§ page.person.money.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
|
||||||
§ page.person.money.moneyLosses.title: не делал коммиты
|
§ page.person.money.moneyLosses.title: возможная переплата
|
||||||
§ page.person.money.moneyLosses.description: Дни когда мог работать, но не работал умноженные на среднюю зп
|
§ page.person.money.moneyLosses.description: Дни без коммитов умноженные на среднюю зп
|
||||||
§ page.person.money.tasks.title: задача
|
§ page.person.money.tasks.title: задача
|
||||||
§ page.person.money.tasks.description: Количество закрытых задач к стоимости дня
|
§ page.person.money.tasks.description: Количество закрытых задач к стоимости дня
|
||||||
§ page.person.money.commits.title: коммит
|
§ page.person.money.commits.title: коммит
|
||||||
§ page.person.money.commits.description: Количество коммитов к стоимости рабочего дня
|
§ page.person.money.commits.description: Количество коммитов к стоимости рабочего дня
|
||||||
§ page.person.money.total: За всё время
|
§ page.person.speed.task: Одна задача в среднем это
|
||||||
§ page.person.money.middle: Средняя стоимость
|
§ page.person.speed.max: Максимальная скорость в день
|
||||||
§ page.person.speed.days.title: дней
|
§ page.person.speed.days.title: дней
|
||||||
§ page.person.speed.days.description: Имеются ввиду рабочие дни, если коммиты правильно подписаны
|
§ page.person.speed.days.description: Имеются ввиду рабочие дни, если коммиты правильно подписаны
|
||||||
§ page.person.speed.commits.title: коммитов
|
§ page.person.speed.commits.title: коммитов
|
||||||
|
@ -146,13 +161,11 @@ git может показать малое количество изменени
|
||||||
§ page.person.speed.tasks.description: Задача может быть не доделана, но работа по ней должна быть
|
§ page.person.speed.tasks.description: Задача может быть не доделана, но работа по ней должна быть
|
||||||
§ page.person.speed.maxCommits.title: коммитов
|
§ page.person.speed.maxCommits.title: коммитов
|
||||||
§ page.person.speed.maxCommits.description: Задача может быть не доделана, но работа по ней должна быть
|
§ page.person.speed.maxCommits.description: Задача может быть не доделана, но работа по ней должна быть
|
||||||
§ page.person.speed.task: Одна задача в среднем это
|
§ page.person.hours.title: Распределение коммитов в течении каждого дня недели
|
||||||
§ page.person.speed.max: Максимальная скорость в день
|
|
||||||
§ page.person.week.date: Дата
|
§ page.person.week.date: Дата
|
||||||
§ page.person.week.tasks: Количество задач
|
§ page.person.week.tasks: Количество задач
|
||||||
§ page.person.week.workDays: Рабочие дни
|
§ page.person.week.workDays: Дни с коммитами
|
||||||
§ page.person.week.taskInDay: Задач в день
|
§ page.person.week.taskInDay: Задач в день
|
||||||
§ page.person.week.commits: коммитов
|
|
||||||
§ page.person.week.days: дней
|
§ page.person.week.days: дней
|
||||||
§ page.person.week.workDay: будни
|
§ page.person.week.workDay: будни
|
||||||
§ page.person.week.weekends: выходные
|
§ page.person.week.weekends: выходные
|
||||||
|
@ -453,6 +466,19 @@ Bus factor = 1
|
||||||
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
|
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
|
||||||
- повышается мотивация и вовлеченность сотрудников;
|
- повышается мотивация и вовлеченность сотрудников;
|
||||||
|
|
||||||
|
§ recommendations.author.club.title
|
||||||
|
Ходите в бар
|
||||||
|
|
||||||
|
§ recommendations.author.club.description
|
||||||
|
один раз в месяц или два.
|
||||||
|
|
||||||
|
Это поможет выстроить неформальную коммуникацию в коллективе и сплотить команду, даже если общение будет сжатым.
|
||||||
|
|
||||||
|
# Почему это важно:
|
||||||
|
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
|
||||||
|
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
|
||||||
|
- повышается вовлеченность сотрудников;
|
||||||
|
|
||||||
§ recommendations.hour.onlyWork.title
|
§ recommendations.hour.onlyWork.title
|
||||||
Выходных тут нет
|
Выходных тут нет
|
||||||
|
|
||||||
|
@ -569,6 +595,39 @@ Bus factor = 1
|
||||||
|
|
||||||
# Возможно, это не так
|
# Возможно, это не так
|
||||||
По типам файлов мы можем предположить тип программы (сайт, серверное приложение, DevOps скрипты и т.д.). Для frontend приложения наша гипотеза будет более верной, чем для DevOps-скриптов, которые могут быть лишь микро-модулем инициализации.
|
По типам файлов мы можем предположить тип программы (сайт, серверное приложение, DevOps скрипты и т.д.). Для frontend приложения наша гипотеза будет более верной, чем для DevOps-скриптов, которые могут быть лишь микро-модулем инициализации.
|
||||||
|
|
||||||
|
§ recommendations.type.diff.title
|
||||||
|
Разбейте лидирующий тип на подтипы
|
||||||
|
|
||||||
|
§ recommendations.type.diff.description
|
||||||
|
для детализации ошибок.
|
||||||
|
|
||||||
|
Как правило, тип задач с меткой «исправление ошибок» является лидирующим. Это делает статистику слабо-детализированной.
|
||||||
|
|
||||||
|
*Если у вас произошла такая ситуация*, вы можете разбить этот тип на подтипы (например, по месту обнаружения).
|
||||||
|
|
||||||
|
Рассмотрим несколько вариантов подтипов:
|
||||||
|
- fix_dev (ошибка выявленная в процессе разработки);
|
||||||
|
- fix_test (ошибка выявленная в процессе тестирования);
|
||||||
|
- fix (ошибка выявленная в проде);
|
||||||
|
|
||||||
|
§ recommendations.type.buddy.title
|
||||||
|
Копите мелкие задачи
|
||||||
|
|
||||||
|
§ recommendations.type.buddy.description
|
||||||
|
для новых сотрудников.
|
||||||
|
|
||||||
|
# Если задача:
|
||||||
|
- не важная;
|
||||||
|
- не большая;
|
||||||
|
- не требует сильного погружения в контекст;
|
||||||
|
- больше про рефакторинг, чем про новый код;
|
||||||
|
|
||||||
|
# Положите её в backlog с меткой «для новичков».
|
||||||
|
|
||||||
|
Когда придёт новый сотрудник, вы сможете моментально достать ему пачку небольших и разнообразных по типу задач, для ознакомления с проектом.
|
||||||
|
|
||||||
|
Также, если у вас будет застой в работе, вы сможете доставать по одной такой мелкой задаче из backlog-а.
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -97,6 +97,11 @@ export default class RecommendationsTeamByAuthor {
|
||||||
localization.get('recommendations.author.oneToOne.description'),
|
localization.get('recommendations.author.oneToOne.description'),
|
||||||
'info',
|
'info',
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
localization.get('recommendations.author.club.title'),
|
||||||
|
localization.get('recommendations.author.club.description'),
|
||||||
|
'info',
|
||||||
|
],
|
||||||
].filter(item => item);
|
].filter(item => item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,16 @@ export default class RecommendationsTeamByType {
|
||||||
localization.get('recommendations.type.fewTypes.description'),
|
localization.get('recommendations.type.fewTypes.description'),
|
||||||
'fact',
|
'fact',
|
||||||
] : null),
|
] : null),
|
||||||
|
[
|
||||||
|
localization.get('recommendations.type.diff.title'),
|
||||||
|
localization.get('recommendations.type.diff.description'),
|
||||||
|
'info',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
localization.get('recommendations.type.buddy.title'),
|
||||||
|
localization.get('recommendations.type.buddy.description'),
|
||||||
|
'info',
|
||||||
|
],
|
||||||
].filter(item => item);
|
].filter(item => item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ const Print = observer(() => {
|
||||||
</Header>
|
</Header>
|
||||||
<Body>
|
<Body>
|
||||||
<img
|
<img
|
||||||
src="./assets/cards/commits.png"
|
src="./assets/cards/print.png"
|
||||||
className={style.page_wrapper_print_icon}
|
className={style.page_wrapper_print_icon}
|
||||||
/>
|
/>
|
||||||
<UiKitButton
|
<UiKitButton
|
||||||
|
|
|
@ -6,7 +6,6 @@ import dataGripStore from 'ts/store/DataGrip';
|
||||||
|
|
||||||
import HoursChart from 'ts/components/HoursChart';
|
import HoursChart from 'ts/components/HoursChart';
|
||||||
import Title from 'ts/components/Title';
|
import Title from 'ts/components/Title';
|
||||||
|
|
||||||
import PageWrapper from 'ts/components/Page/wrapper';
|
import PageWrapper from 'ts/components/Page/wrapper';
|
||||||
|
|
||||||
const Hours = observer((): React.ReactElement => {
|
const Hours = observer((): React.ReactElement => {
|
||||||
|
@ -15,7 +14,7 @@ const Hours = observer((): React.ReactElement => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title="Распределение коммитов в течении каждого дня недели"/>
|
<Title title="page.person.hours.title"/>
|
||||||
<PageWrapper template="table">
|
<PageWrapper template="table">
|
||||||
<HoursChart statistic={statistic} />
|
<HoursChart statistic={statistic} />
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { useParams } from 'react-router-dom';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
|
|
||||||
import { getShortMoney } from 'ts/helpers/formatter';
|
import { getShortMoney } from 'ts/helpers/formatter';
|
||||||
import localization from 'ts/helpers/Localization';
|
|
||||||
|
|
||||||
import CardWithIcon from 'ts/components/CardWithIcon';
|
import CardWithIcon from 'ts/components/CardWithIcon';
|
||||||
import NothingFound from 'ts/components/NothingFound';
|
import NothingFound from 'ts/components/NothingFound';
|
||||||
|
@ -31,36 +30,36 @@ const Money = observer((): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('За всё время')}/>
|
<Title title="page.person.money.title.total"/>
|
||||||
<div>
|
<div>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={getShortMoney(statistic.moneyAll)}
|
value={getShortMoney(statistic.moneyAll)}
|
||||||
icon="./assets/cards/money_total.png"
|
icon="./assets/cards/money_total.png"
|
||||||
title="получил"
|
title="page.person.money.moneyAll.title"
|
||||||
description="Предполагаемая сумма зп с проекта (см. настройки)"
|
description="page.person.money.moneyAll.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={getShortMoney(statistic.moneyWorked)}
|
value={getShortMoney(statistic.moneyWorked)}
|
||||||
icon="./assets/cards/money_work.png"
|
icon="./assets/cards/money_work.png"
|
||||||
title="отработал"
|
title="page.person.money.moneyWorked.title"
|
||||||
description="Фактически отработанные дни умноженные на среднюю зп"
|
description="page.person.money.moneyWorked.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={getShortMoney(statistic.moneyLosses)}
|
value={getShortMoney(statistic.moneyLosses)}
|
||||||
icon="./assets/cards/money_lazy.png"
|
icon="./assets/cards/money_lazy.png"
|
||||||
title="возможная переплата"
|
title="page.person.money.moneyLosses.title"
|
||||||
description="Дни без коммитов умноженные на среднюю зп"
|
description="page.person.money.moneyLosses.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={getShortMoney(byTimestamp.weekendPayment)}
|
value={getShortMoney(byTimestamp.weekendPayment)}
|
||||||
icon="./assets/cards/money_holidays.png"
|
icon="./assets/cards/money_holidays.png"
|
||||||
title={localization.get('page.team.total.weekendPayment.title')}
|
title="page.team.total.weekendPayment.title"
|
||||||
description={localization.get('page.team.total.weekendPayment.description')}
|
description="page.team.total.weekendPayment.description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('Средняя стоимость')}/>
|
<Title title="page.person.money.title.middle"/>
|
||||||
{taskNumber === 0 ? (
|
{taskNumber === 0 ? (
|
||||||
<NothingFound />
|
<NothingFound />
|
||||||
) : (
|
) : (
|
||||||
|
@ -71,8 +70,8 @@ const Money = observer((): React.ReactElement => {
|
||||||
? getShortMoney(statistic.moneyWorked / taskNumber, 0)
|
? getShortMoney(statistic.moneyWorked / taskNumber, 0)
|
||||||
: null}
|
: null}
|
||||||
icon="./assets/cards/money_task.png"
|
icon="./assets/cards/money_task.png"
|
||||||
title="задача"
|
title="page.person.money.tasks.title"
|
||||||
description="Количество закрытых задач к стоимости дня"
|
description="page.person.money.tasks.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
long
|
||||||
|
@ -80,8 +79,8 @@ const Money = observer((): React.ReactElement => {
|
||||||
? getShortMoney(statistic.moneyWorked / statistic.commits, 0)
|
? getShortMoney(statistic.moneyWorked / statistic.commits, 0)
|
||||||
: null}
|
: null}
|
||||||
icon="./assets/cards/money_work.png"
|
icon="./assets/cards/money_work.png"
|
||||||
title="коммит"
|
title="page.person.money.commits.title"
|
||||||
description="Количество коммитов к стоимости рабочего дня"
|
description="page.person.money.commits.description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { useParams } from 'react-router-dom';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
|
|
||||||
import { getShortNumber } from 'ts/helpers/formatter';
|
import { getShortNumber } from 'ts/helpers/formatter';
|
||||||
import localization from 'ts/helpers/Localization';
|
|
||||||
|
|
||||||
import CardWithIcon from 'ts/components/CardWithIcon';
|
import CardWithIcon from 'ts/components/CardWithIcon';
|
||||||
import NothingFound from 'ts/components/NothingFound';
|
import NothingFound from 'ts/components/NothingFound';
|
||||||
|
@ -31,7 +30,7 @@ const Speed = observer((): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('Одна задача в среднем это')}/>
|
<Title title="page.person.speed.task"/>
|
||||||
{taskNumber === 0 ? (
|
{taskNumber === 0 ? (
|
||||||
<NothingFound />
|
<NothingFound />
|
||||||
) : (
|
) : (
|
||||||
|
@ -41,42 +40,42 @@ const Speed = observer((): React.ReactElement => {
|
||||||
? getShortNumber(statistic.daysForTask)
|
? getShortNumber(statistic.daysForTask)
|
||||||
: null}
|
: null}
|
||||||
icon="./assets/cards/month.png"
|
icon="./assets/cards/month.png"
|
||||||
title="дней"
|
title="page.person.speed.days.title"
|
||||||
description="Имеются ввиду рабочие дни,<br>если коммиты правильно подписаны"
|
description="page.person.speed.days.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={taskNumber
|
value={taskNumber
|
||||||
? (statistic.commits / taskNumber).toFixed(1)
|
? (statistic.commits / taskNumber).toFixed(1)
|
||||||
: null}
|
: null}
|
||||||
icon="./assets/cards/commits.png"
|
icon="./assets/cards/commits.png"
|
||||||
title="коммитов"
|
title="page.person.speed.commits.title"
|
||||||
description="Отрезаны 10% максимальных и минимальных значений"
|
description="page.person.speed.commits.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={taskNumber ? statistic.changesForTask : null}
|
value={taskNumber ? statistic.changesForTask : null}
|
||||||
icon="./assets/cards/lines.png"
|
icon="./assets/cards/lines.png"
|
||||||
title="строк кода"
|
title="page.person.speed.line.title"
|
||||||
description="Отрезаны 10% максимальных и минимальных значений"
|
description="page.person.speed.line.description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('Максимальная скорость в день')}/>
|
<Title title="page.person.speed.max"/>
|
||||||
<div>
|
<div>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
long
|
||||||
value={byTimestamp.tasksByTimestampCounter.max}
|
value={byTimestamp.tasksByTimestampCounter.max}
|
||||||
icon="./assets/cards/tasks.png"
|
icon="./assets/cards/tasks.png"
|
||||||
title="задач"
|
title="page.person.speed.tasks.title"
|
||||||
description="Задача может быть не доделана, но работа по ней должна быть"
|
description="page.person.speed.tasks.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
long
|
long
|
||||||
value={byTimestamp.commitsByTimestampCounter.max}
|
value={byTimestamp.commitsByTimestampCounter.max}
|
||||||
icon="./assets/cards/commits.png"
|
icon="./assets/cards/commits.png"
|
||||||
title="коммитов"
|
title="page.person.speed.maxCommits.title"
|
||||||
description="Задача может быть не доделана, но работа по ней должна быть"
|
description="page.person.speed.maxCommits.description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { observer } from 'mobx-react-lite';
|
||||||
import { IPagination } from 'ts/interfaces/Pagination';
|
import { IPagination } from 'ts/interfaces/Pagination';
|
||||||
import dataGripStore from 'ts/store/DataGrip';
|
import dataGripStore from 'ts/store/DataGrip';
|
||||||
import { getShortDateRange } from 'ts/helpers/formatter';
|
import { getShortDateRange } from 'ts/helpers/formatter';
|
||||||
import localization from 'ts/helpers/Localization';
|
|
||||||
|
|
||||||
import UiKitButton from 'ts/components/UiKit/components/Button';
|
import UiKitButton from 'ts/components/UiKit/components/Button';
|
||||||
import PageWrapper from 'ts/components/Page/wrapper';
|
import PageWrapper from 'ts/components/Page/wrapper';
|
||||||
|
@ -60,7 +59,7 @@ const Tempo = observer((): React.ReactElement => {
|
||||||
if (!partOfData?.length) return (<NothingFound />);
|
if (!partOfData?.length) return (<NothingFound />);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={localization.get('common.filters')} />
|
<Title title="common.filters" />
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<div className={style.tempo_page_filters}>
|
<div className={style.tempo_page_filters}>
|
||||||
<UiKitButton
|
<UiKitButton
|
||||||
|
@ -95,9 +94,7 @@ const Tempo = observer((): React.ReactElement => {
|
||||||
loader={() => getFakeLoader({ content: partOfData })}
|
loader={() => getFakeLoader({ content: partOfData })}
|
||||||
watch={week}
|
watch={week}
|
||||||
>
|
>
|
||||||
<TempoView
|
<TempoView user={author.author}/>
|
||||||
user={author.author}
|
|
||||||
/>
|
|
||||||
<Pagination />
|
<Pagination />
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import Achievements from 'ts/components/Achievement';
|
||||||
import Description from 'ts/components/Description';
|
import Description from 'ts/components/Description';
|
||||||
import PageWrapper from 'ts/components/Page/wrapper';
|
import PageWrapper from 'ts/components/Page/wrapper';
|
||||||
import PageColumn from 'ts/components/Page/column';
|
import PageColumn from 'ts/components/Page/column';
|
||||||
|
import Character from 'ts/components/Character';
|
||||||
import Title from 'ts/components/Title';
|
import Title from 'ts/components/Title';
|
||||||
import GetList from 'ts/components/GetList';
|
import GetList from 'ts/components/GetList';
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ function AchievementBlock({ title, achievements }: IAchievementBlockProps) {
|
||||||
if (!achievements.length) return null;
|
if (!achievements.length) return null;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Description text={`# ${title}`}/>
|
<Description text={`# ${localization.get(title)}`}/>
|
||||||
<Achievements list={achievements} />
|
<Achievements list={achievements} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -41,19 +42,19 @@ const Total = observer((): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('Основные характеристики')}/>
|
<Title title="page.person.total.title"/>
|
||||||
<div>
|
<div>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={statistic.daysWorked}
|
value={statistic.daysWorked}
|
||||||
icon="./assets/cards/work_days.png"
|
icon="./assets/cards/work_days.png"
|
||||||
title="дней работы"
|
title="page.person.total.daysWorked.title"
|
||||||
description="page.team.total.daysWorked.description"
|
description="page.person.total.daysWorked.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={taskNumber ? taskNumber : null}
|
value={taskNumber ? taskNumber : null}
|
||||||
icon="./assets/cards/tasks.png"
|
icon="./assets/cards/tasks.png"
|
||||||
title="задач"
|
title="page.person.total.tasks.title"
|
||||||
description="Если коммиты правильно подписаны"
|
description="page.person.total.tasks.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={statistic.daysLosses}
|
value={statistic.daysLosses}
|
||||||
|
@ -68,29 +69,35 @@ const Total = observer((): React.ReactElement => {
|
||||||
description="page.team.total.commits.description"
|
description="page.team.total.commits.description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<Title title="page.person.character.title"/>
|
||||||
|
<Character user={statistic} />
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('Достижения')}/>
|
<Title title="page.person.achievement.title"/>
|
||||||
<AchievementBlock
|
<AchievementBlock
|
||||||
title="Позитивные"
|
title="page.person.achievement.positive"
|
||||||
achievements={achievements[ACHIEVEMENT_TYPE.GOOD]}
|
achievements={achievements[ACHIEVEMENT_TYPE.GOOD]}
|
||||||
/>
|
/>
|
||||||
<AchievementBlock
|
<AchievementBlock
|
||||||
title="Нейтральные"
|
title="page.person.achievement.normal"
|
||||||
achievements={achievements[ACHIEVEMENT_TYPE.NORMAL]}
|
achievements={achievements[ACHIEVEMENT_TYPE.NORMAL]}
|
||||||
/>
|
/>
|
||||||
<AchievementBlock
|
<AchievementBlock
|
||||||
title="Негативные"
|
title="page.person.achievement.negative"
|
||||||
achievements={achievements[ACHIEVEMENT_TYPE.BAD]}
|
achievements={achievements[ACHIEVEMENT_TYPE.BAD]}
|
||||||
/>
|
/>
|
||||||
<Description text="Чем больше сотрудник набрал отрицательных достижений, тем больше вероятность, что ситуация нестандартная. Возможно, стоит изменить режим его работы, задачи или отчётность. Следует поговорить с ним и узнать, какие проблемы мешают его работе."/>
|
<Description
|
||||||
|
text={localization.get('page.person.achievement.description')}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{commitsWithGet?.length ? (
|
{commitsWithGet?.length ? (
|
||||||
<>
|
<>
|
||||||
<Title title={localization.get('Взятые геты:')}/>
|
<Title title="page.person.gets.title"/>
|
||||||
<GetList list={commitsWithGet} />
|
<GetList list={commitsWithGet} />
|
||||||
<Description text="«Взять гет» в данном случае означает первым оставить коммит к задаче с «красивым» номером."/>
|
<Description
|
||||||
|
text={localization.get('page.person.gets.description')}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
|
|
|
@ -32,7 +32,10 @@ function WeekView({ response, name }: IWeekViewProps) {
|
||||||
if (!response) return null;
|
if (!response) return null;
|
||||||
|
|
||||||
const typeChart = getOptions({ max: getMax(response, 'authors', name), order: dataGripStore.dataGrip.type.list });
|
const typeChart = getOptions({ max: getMax(response, 'authors', name), order: dataGripStore.dataGrip.type.list });
|
||||||
const workDaysChart = getOptions({ max: 7, order: ['будни', 'выходные'], suffix: 'дней' });
|
const workDaysChart = getOptions({ max: 7, order: [
|
||||||
|
'page.person.week.workDay',
|
||||||
|
'page.person.week.weekends',
|
||||||
|
], suffix: 'page.person.week.days' });
|
||||||
const taskInDayChart = getOptions({ max: getMax(response, 'taskInDay', name) });
|
const taskInDayChart = getOptions({ max: getMax(response, 'taskInDay', name) });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -40,7 +43,7 @@ function WeekView({ response, name }: IWeekViewProps) {
|
||||||
<Column
|
<Column
|
||||||
isFixed
|
isFixed
|
||||||
template={ColumnTypesEnum.STRING}
|
template={ColumnTypesEnum.STRING}
|
||||||
title="Дата"
|
title="page.person.week.date"
|
||||||
properties="timestamp"
|
properties="timestamp"
|
||||||
formatter={getShortDateRange}
|
formatter={getShortDateRange}
|
||||||
width={200}
|
width={200}
|
||||||
|
@ -51,7 +54,7 @@ function WeekView({ response, name }: IWeekViewProps) {
|
||||||
formatter={(authors: IHashMap<number>) => authors[name] || 0}
|
formatter={(authors: IHashMap<number>) => authors[name] || 0}
|
||||||
/>
|
/>
|
||||||
<Column
|
<Column
|
||||||
title="Количество задач"
|
title="page.person.week.tasks"
|
||||||
template={(row: any) => (
|
template={(row: any) => (
|
||||||
<LineChart
|
<LineChart
|
||||||
options={typeChart}
|
options={typeChart}
|
||||||
|
@ -67,12 +70,15 @@ function WeekView({ response, name }: IWeekViewProps) {
|
||||||
formatter={(workDays: IHashMap<number>) => workDays[name] || 0}
|
formatter={(workDays: IHashMap<number>) => workDays[name] || 0}
|
||||||
/>
|
/>
|
||||||
<Column
|
<Column
|
||||||
title="Дни с коммитами"
|
title="page.person.week.workDays"
|
||||||
template={([work, week]: any) => (
|
template={([work, week]: any) => (
|
||||||
<LineChart
|
<LineChart
|
||||||
options={workDaysChart}
|
options={workDaysChart}
|
||||||
value={work + week}
|
value={work + week}
|
||||||
details={{ 'будни': work, 'выходные': week }}
|
details={{
|
||||||
|
'page.person.week.workDay': work,
|
||||||
|
'page.person.week.weekends': week,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
formatter={(row: any) => ( // TODO: не верно, тут сумма, а сб или вс не факт. Он мог прогулять пн, но работать в вс
|
formatter={(row: any) => ( // TODO: не верно, тут сумма, а сб или вс не факт. Он мог прогулять пн, но работать в вс
|
||||||
|
@ -88,7 +94,7 @@ function WeekView({ response, name }: IWeekViewProps) {
|
||||||
formatter={(taskInDay: IHashMap<number>) => getShortNumber(taskInDay[name] || 0)}
|
formatter={(taskInDay: IHashMap<number>) => getShortNumber(taskInDay[name] || 0)}
|
||||||
/>
|
/>
|
||||||
<Column
|
<Column
|
||||||
title="Задач в день"
|
title="page.person.week.taskInDay"
|
||||||
properties="taskInDay"
|
properties="taskInDay"
|
||||||
template={(taskInDay: any) => (
|
template={(taskInDay: any) => (
|
||||||
<LineChart
|
<LineChart
|
||||||
|
|
|
@ -39,32 +39,34 @@ const Total = observer((): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('Достижения')}/>
|
<Title title="page.person.achievement.title"/>
|
||||||
<AchievementBlock
|
<AchievementBlock
|
||||||
title="Позитивные"
|
title="page.person.achievement.positive"
|
||||||
achievements={achievements[ACHIEVEMENT_TYPE.GOOD]}
|
achievements={achievements[ACHIEVEMENT_TYPE.GOOD]}
|
||||||
/>
|
/>
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
<PageColumn>
|
<PageColumn>
|
||||||
<Title title={localization.get('_')}/>
|
<Title title={localization.get('_')}/>
|
||||||
<AchievementBlock
|
<AchievementBlock
|
||||||
title="Нейтральные"
|
title="page.person.achievement.normal"
|
||||||
achievements={achievements[ACHIEVEMENT_TYPE.NORMAL]}
|
achievements={achievements[ACHIEVEMENT_TYPE.NORMAL]}
|
||||||
/>
|
/>
|
||||||
<AchievementBlock
|
<AchievementBlock
|
||||||
title="Негативные"
|
title="page.person.achievement.negative"
|
||||||
achievements={achievements[ACHIEVEMENT_TYPE.BAD]}
|
achievements={achievements[ACHIEVEMENT_TYPE.BAD]}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{commitsWithGet?.length ? (
|
{commitsWithGet?.length ? (
|
||||||
<>
|
<>
|
||||||
<Title title={localization.get('Взятые геты:')}/>
|
<Title title="page.person.gets.title"/>
|
||||||
<GetList
|
<GetList
|
||||||
mode="print"
|
mode="print"
|
||||||
list={commitsWithGet}
|
list={commitsWithGet}
|
||||||
/>
|
/>
|
||||||
<Description text="«Взять гет» в данном случае означает первым оставить коммит к задаче с «красивым» номером."/>
|
<Description
|
||||||
|
text={localization.get('page.person.gets.description')}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</PageColumn>
|
</PageColumn>
|
||||||
|
|
|
@ -21,7 +21,7 @@ const Total = observer((): React.ReactElement => {
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value=""
|
value=""
|
||||||
icon="./assets/cards/work_days.png"
|
icon="./assets/cards/work_days.png"
|
||||||
title="Фотограция"
|
title="Фотография"
|
||||||
/>
|
/>
|
||||||
<div className={style.place_for_photo}>
|
<div className={style.place_for_photo}>
|
||||||
место для фотографии
|
место для фотографии
|
||||||
|
@ -33,14 +33,14 @@ const Total = observer((): React.ReactElement => {
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={statistic.daysWorked}
|
value={statistic.daysWorked}
|
||||||
icon="./assets/cards/work_days.png"
|
icon="./assets/cards/work_days.png"
|
||||||
title="дней работы"
|
title="page.person.total.daysWorked.title"
|
||||||
description="page.team.total.daysWorked.description"
|
description="page.person.total.daysWorked.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={taskNumber ? taskNumber : null}
|
value={taskNumber ? taskNumber : null}
|
||||||
icon="./assets/cards/tasks.png"
|
icon="./assets/cards/tasks.png"
|
||||||
title="задач"
|
title="page.person.total.tasks.title"
|
||||||
description="Если коммиты правильно подписаны"
|
description="page.person.total.tasks.description"
|
||||||
/>
|
/>
|
||||||
<CardWithIcon
|
<CardWithIcon
|
||||||
value={statistic.daysLosses}
|
value={statistic.daysLosses}
|
||||||
|
|