JIRA-1234 fix(doc): some some

This commit is contained in:
bakhirev 2023-11-27 15:45:54 +03:00
parent 127d978b31
commit c456f5c43e
69 changed files with 2611 additions and 2017 deletions

View file

@ -82,6 +82,16 @@ Git создаст файл `log.txt`.
- См. «Как посмотреть отчёт онлайн?». На последнем шаге перетащить сразу все файлы в окно браузера. - См. «Как посмотреть отчёт онлайн?». На последнем шаге перетащить сразу все файлы в окно браузера.
- См. «Как посмотреть отчёт офлайн?». На втором шаге перетащить все файлы микросервисов (`log-1.txt`, `log-2.txt`, `log-3.txt` и т.д.) в папку отчета (`/build`). - См. «Как посмотреть отчёт офлайн?». На втором шаге перетащить все файлы микросервисов (`log-1.txt`, `log-2.txt`, `log-3.txt` и т.д.) в папку отчета (`/build`).
### Как брендировать интерфейс?
Вы можете написать свою тему для интерфейса. Можно менять:
- **Заголовок**. Вы можете указать его в URL-параметре ```title```. Например: ```?title=You Company```
- **Визуальную тему**. Для этого нужно подготовить CSS файл с новыми стилями и указать его адрес в URL-параметре ```theme```. Например: ```?theme=//company.com/some.css```. Вы можете использовать имена классов в качестве селекторов. Большинство из них не меняется в при выходе новой версий.
- **Язык**. Вы можете указать его в URL-параметре ```lang```. Например: ```?lang=es```
### Как добавить или отредактировать перевод?
Вы можете добавить новый перевод или поправить текущий в разделе ```ts/translations/``` и создать Pull Request.
### Как подписывать коммиты? ### Как подписывать коммиты?
Следуйте практике [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/). Например: Следуйте практике [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/). Например:
@ -93,7 +103,7 @@ JIRA-1234 feat(profile): Added avatar for user
- фича `(profile - раздел сайта, страница или новый функционал, одним словом)` - фича `(profile - раздел сайта, страница или новый функционал, одним словом)`
- какую проблему решали `(Added avatar for user)` - какую проблему решали `(Added avatar for user)`
### Как автоматизировать сбор данных ### Как автоматизировать сбор данных?
#### Без бекенда #### Без бекенда
- создайте клон нужного вам репозитория; - создайте клон нужного вам репозитория;
@ -122,6 +132,7 @@ assayo_url - URL адресс контейнера assayo, он слушает 8
you_url - URL адресс вашего контейнера с логами git; you_url - URL адресс вашего контейнера с логами git;
``` ```
По умолчанию образ запустится по адресу ```http://127.0.0.1:80/```. Если не получилось проверьте свободен ли у вас 80 порт.
#### Обновление Docker-образа #### Обновление Docker-образа
- удилить метрику, аллерты, старые билды; - удилить метрику, аллерты, старые билды;
@ -136,11 +147,12 @@ you_url - URL адресс вашего контейнера с логами
- больше советов и достижений; - больше советов и достижений;
- итоги года / месяца, печать отчётов; - итоги года / месяца, печать отчётов;
- локализация и интернационализация; - локализация и интернационализация;
- анализ файлов;
- разные роли для статистики (скрытие финансов); - разные роли для статистики (скрытие финансов);
- разработка бекенда, интеграции с другими системами; - разработка бекенда, интеграции с другими системами;
### Пожелания, предложения, замечания ### Пожелания, предложения, замечания
- telegramm [@bakhirev](https://t.me/bakhirev) (приоритетный способ связи)
- [alexey-bakhirev@yandex.ru](mailto:alexey-bakhirev@yandex.ru) - [alexey-bakhirev@yandex.ru](mailto:alexey-bakhirev@yandex.ru)
- telegramm [@bakhirev](https://t.me/bakhirev)
- сайт [https://assayo.jp/](https://assayo.jp/) - сайт [https://assayo.jp/](https://assayo.jp/)

View file

@ -1,17 +1,17 @@
{ {
"files": { "files": {
"main.css": "./static/css/main.bd89a1c5.css", "main.css": "./static/css/main.3c6bf65a.css",
"main.js": "./static/js/main.b114e843.js", "main.js": "./static/js/main.7746635d.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.bd89a1c5.css.map": "./static/css/main.bd89a1c5.css.map", "main.3c6bf65a.css.map": "./static/css/main.3c6bf65a.css.map",
"main.b114e843.js.map": "./static/js/main.b114e843.js.map" "main.7746635d.js.map": "./static/js/main.7746635d.js.map"
}, },
"entrypoints": [ "entrypoints": [
"static/css/main.bd89a1c5.css", "static/css/main.3c6bf65a.css",
"static/js/main.b114e843.js" "static/js/main.7746635d.js"
] ]
} }

View file

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg">
<path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"></path> <path d="M19 5v2h-4V5h4M9 5v6H5V5h4m10 8v6h-4v-6h4M9 17v2H5v-2h4M21 3h-8v6h8V3zM11 3H3v10h8V3zm10 8h-8v10h8V11zm-10 4H3v6h8v-6z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 225 B

View file

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg">
<path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 221 B

View file

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg">
<path d="M20 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 2v3H5V5h15zm-5 14h-5v-9h5v9zM5 10h3v9H5v-9zm12 9v-9h3v9h-3z"></path> <path d="M20 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 2v3H5V5h15zm-5 14h-5v-9h5v9zM5 10h3v9H5v-9zm12 9v-9h3v9h-3z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 245 B

16
build/assets/vds.css Normal file
View file

@ -0,0 +1,16 @@
body {
--vds-color--main: #00AFD0;
}
.title,
.header_title,
.card_with_icon_value,
.card_with_icon_title,
.welcome_first_title,
.welcome_last_title {
/*color: var(--vds-color--main);*/
}
.sidebar {
background-color: transparent;
}

View file

@ -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.b114e843.js"></script><link href="./static/css/main.bd89a1c5.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></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.7746635d.js"></script><link href="./static/css/main.3c6bf65a.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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

18
config-overrides.js Normal file
View file

@ -0,0 +1,18 @@
module.exports = {
webpack: (config) => {
const oneOfs = config.module.rules.find((rule) => !!rule.oneOf).oneOf;
for (const oneOf of oneOfs) {
oneOf?.use?.forEach((someUse) => {
if (!someUse?.options?.modules?.mode) return;
// someUse.options.modules.localIdentName = '[local]_';
someUse.options.modules.getLocalIdent = (context, localIdentName, localName, options) => {
return localName;
}
});
}
return config;
}
};

176
package-lock.json generated
View file

@ -1,11 +1,11 @@
{ {
"name": "my", "name": "Assayo",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "my", "name": "Assayo",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
@ -34,6 +34,8 @@
"eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.1", "eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"react-app-rewire-typings-for-css-module": "^4.0.3",
"react-app-rewired": "^2.2.1",
"react-testing-library": "^8.0.1", "react-testing-library": "^8.0.1",
"stylelint": "^14.16.1", "stylelint": "^14.16.1",
"stylelint-group-selectors": "^1.0.9", "stylelint-group-selectors": "^1.0.9",
@ -6304,6 +6306,45 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/css-modules-typescript-loader": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/css-modules-typescript-loader/-/css-modules-typescript-loader-4.0.1.tgz",
"integrity": "sha512-vXrUAwPGcRaopnGdg7I5oqv/NSSKQRN5L80m3f49uSGinenU5DTNsMFHS+2roh5tXqpY5+yAAKAl7A2HDvumzg==",
"dev": true,
"peer": true,
"dependencies": {
"line-diff": "^2.0.1",
"loader-utils": "^1.2.3"
}
},
"node_modules/css-modules-typescript-loader/node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"peer": true,
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
}
},
"node_modules/css-modules-typescript-loader/node_modules/loader-utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
"dev": true,
"peer": true,
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/css-prefers-color-scheme": { "node_modules/css-prefers-color-scheme": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz",
@ -12031,6 +12072,13 @@
"language-subtag-registry": "~0.3.2" "language-subtag-registry": "~0.3.2"
} }
}, },
"node_modules/levdist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/levdist/-/levdist-1.0.0.tgz",
"integrity": "sha512-YguwC2spb0pqpJM3a5OsBhih/GG2ZHoaSHnmBqhEI7997a36buhqcRTegEjozHxyxByIwLpZHZTVYMThq+Zd3g==",
"dev": true,
"peer": true
},
"node_modules/leven": { "node_modules/leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@ -12059,6 +12107,16 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/line-diff": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/line-diff/-/line-diff-2.1.1.tgz",
"integrity": "sha512-vswdynAI5AMPJacOo2o+JJ4caDJbnY2NEqms4MhMW0NJbjh3skP/brpVTAgBxrg55NRZ2Vtw88ef18hnagIpYQ==",
"dev": true,
"peer": true,
"dependencies": {
"levdist": "^1.0.0"
}
},
"node_modules/lines-and-columns": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@ -14688,6 +14746,42 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/react-app-rewire-typings-for-css-module": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-app-rewire-typings-for-css-module/-/react-app-rewire-typings-for-css-module-4.0.3.tgz",
"integrity": "sha512-8Y1K07iLGilhRnSraPAKGgIs2PpZj9gjuBDATuIUqJZ8AL1ZXthoMFJXh8TcHzlmrNCqiUnv7kXRvRAgH5pn4w==",
"dev": true,
"dependencies": {
"deepmerge": "^4.2.2"
},
"peerDependencies": {
"css-modules-typescript-loader": "^4.0.1"
}
},
"node_modules/react-app-rewired": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz",
"integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==",
"dev": true,
"dependencies": {
"semver": "^5.6.0"
},
"bin": {
"react-app-rewired": "bin/index.js"
},
"peerDependencies": {
"react-scripts": ">=2.1.3"
}
},
"node_modules/react-app-rewired/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/react-dev-utils": { "node_modules/react-dev-utils": {
"version": "12.0.1", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@ -22624,6 +22718,41 @@
} }
} }
}, },
"css-modules-typescript-loader": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/css-modules-typescript-loader/-/css-modules-typescript-loader-4.0.1.tgz",
"integrity": "sha512-vXrUAwPGcRaopnGdg7I5oqv/NSSKQRN5L80m3f49uSGinenU5DTNsMFHS+2roh5tXqpY5+yAAKAl7A2HDvumzg==",
"dev": true,
"peer": true,
"requires": {
"line-diff": "^2.0.1",
"loader-utils": "^1.2.3"
},
"dependencies": {
"json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"peer": true,
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
"dev": true,
"peer": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
}
}
},
"css-prefers-color-scheme": { "css-prefers-color-scheme": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz",
@ -26788,6 +26917,13 @@
"language-subtag-registry": "~0.3.2" "language-subtag-registry": "~0.3.2"
} }
}, },
"levdist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/levdist/-/levdist-1.0.0.tgz",
"integrity": "sha512-YguwC2spb0pqpJM3a5OsBhih/GG2ZHoaSHnmBqhEI7997a36buhqcRTegEjozHxyxByIwLpZHZTVYMThq+Zd3g==",
"dev": true,
"peer": true
},
"leven": { "leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@ -26807,6 +26943,16 @@
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz",
"integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==" "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg=="
}, },
"line-diff": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/line-diff/-/line-diff-2.1.1.tgz",
"integrity": "sha512-vswdynAI5AMPJacOo2o+JJ4caDJbnY2NEqms4MhMW0NJbjh3skP/brpVTAgBxrg55NRZ2Vtw88ef18hnagIpYQ==",
"dev": true,
"peer": true,
"requires": {
"levdist": "^1.0.0"
}
},
"lines-and-columns": { "lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@ -28516,6 +28662,32 @@
"whatwg-fetch": "^3.6.2" "whatwg-fetch": "^3.6.2"
} }
}, },
"react-app-rewire-typings-for-css-module": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-app-rewire-typings-for-css-module/-/react-app-rewire-typings-for-css-module-4.0.3.tgz",
"integrity": "sha512-8Y1K07iLGilhRnSraPAKGgIs2PpZj9gjuBDATuIUqJZ8AL1ZXthoMFJXh8TcHzlmrNCqiUnv7kXRvRAgH5pn4w==",
"dev": true,
"requires": {
"deepmerge": "^4.2.2"
}
},
"react-app-rewired": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz",
"integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==",
"dev": true,
"requires": {
"semver": "^5.6.0"
},
"dependencies": {
"semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
}
}
},
"react-dev-utils": { "react-dev-utils": {
"version": "12.0.1", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",

View file

@ -19,7 +19,7 @@
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {
"dev": "set PORT=3006 && react-scripts start", "dev": "set PORT=3006 && react-app-rewired start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject", "eject": "react-scripts eject",
@ -58,6 +58,8 @@
"eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.1", "eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"react-app-rewire-typings-for-css-module": "^4.0.3",
"react-app-rewired": "^2.2.1",
"react-testing-library": "^8.0.1", "react-testing-library": "^8.0.1",
"stylelint": "^14.16.1", "stylelint": "^14.16.1",
"stylelint-group-selectors": "^1.0.9", "stylelint-group-selectors": "^1.0.9",

View file

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="#84858D" xmlns="http://www.w3.org/2000/svg">
<path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 221 B

16
public/assets/vds.css Normal file
View file

@ -0,0 +1,16 @@
body {
--vds-color--main: #00AFD0;
}
.title,
.header_title,
.card_with_icon_value,
.card_with_icon_title,
.welcome_first_title,
.welcome_last_title {
/*color: var(--vds-color--main);*/
}
.sidebar {
background-color: transparent;
}

View file

@ -2,12 +2,14 @@ import React from 'react';
import { HashRouter } from 'react-router-dom'; import { HashRouter } from 'react-router-dom';
import { render } from 'react-dom'; import { render } from 'react-dom';
import ru from 'ts/config/translations/ru'; import localization from 'ts/helpers/Localization';
import en from 'ts/config/translations/en'; import ru from 'ts/translations/ru/index';
import en from 'ts/translations/en/index';
import Authorization from 'ts/pages/Authorization'; import Authorization from 'ts/pages/Authorization';
import userSettings from 'ts/store/UserSettings'; import userSettings from 'ts/store/UserSettings';
import Notifications from 'ts/components/Notifications'; import Notifications from 'ts/components/Notifications';
import printStore from 'ts/pages/PageWrapper/store/Print'; import printStore from 'ts/pages/PageWrapper/store/Print';
import applyUrlCommands from 'ts/helpers/RPC';
import './styles/index.scss'; import './styles/index.scss';
@ -19,15 +21,8 @@ if (module.hot) {
module.hot.accept(); module.hot.accept();
} }
// @ts-ignore localization.parse('ru', ru);
console.dir(ru + en + ''); localization.parse('en', en);
function getParametersFromString(text: string) {
return Object.fromEntries((text || '')
.substring(1, Infinity)
.split('&')
.map((token: string) => token.split('=')));
}
function renderReactApplication() { function renderReactApplication() {
// @ts-ignore // @ts-ignore
@ -46,24 +41,6 @@ function renderReactApplication() {
); );
} }
function loadApplication() {
const parameters = {
...getParametersFromString(location.search),
...getParametersFromString(location.hash),
};
if (!parameters.dump) {
return renderReactApplication();
}
const script = document.createElement('script');
script.src = parameters.dump;
script.async = true;
script.onload = renderReactApplication;
script.onerror = renderReactApplication;
document.body.appendChild(script);
}
userSettings.loadUserSettings().then(() => { userSettings.loadUserSettings().then(() => {
loadApplication(); applyUrlCommands(renderReactApplication);
}); });

View file

@ -101,3 +101,29 @@
} }
} }
} }
@media print {
.card_with_icon,
.card_with_icon_long {
min-height: 220px;
padding: 16px 0;
&_icon {
height: 60px;
}
&_value {
font-size: 22px;
margin: 0;
}
&_title {
font-size: var(--font-s);
margin: 0 0 8px 0;
}
&_description {
display: block;
}
}
}

View file

@ -10,12 +10,14 @@ interface ICardProps {
item: any; item: any;
lines: IColumn[]; lines: IColumn[];
className?: string; className?: string;
customStyle?: any;
} }
function Card({ function Card({
item, item,
lines, lines,
className, className,
customStyle,
}: ICardProps) { }: ICardProps) {
const parts = lines.map((line: IColumn, columnIndex: number) => { const parts = lines.map((line: IColumn, columnIndex: number) => {
const value = line.properties const value = line.properties
@ -54,7 +56,10 @@ function Card({
}); });
return ( return (
<div className={`${style.card} ${className}`}> <div
className={`${style.card} ${className}`}
style={customStyle || {}}
>
{parts} {parts}
</div> </div>
); );

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { useLayoutEffect, useRef, useState } from 'react';
import { IColumn } from 'ts/components/Table/interfaces/Column'; import { IColumn } from 'ts/components/Table/interfaces/Column';
import getDefaultProps from 'ts/components/Table/helpers/getDefaultProps'; import getDefaultProps from 'ts/components/Table/helpers/getDefaultProps';
@ -9,6 +9,7 @@ import style from './styles/index.module.scss';
interface ICardsProps { interface ICardsProps {
items: any[]; items: any[];
columnCount?: number;
className?: string; className?: string;
children: React.ReactNode | React.ReactNode[]; children: React.ReactNode | React.ReactNode[];
} }
@ -16,24 +17,46 @@ interface ICardsProps {
function Cards({ function Cards({
items = [], items = [],
className, className,
columnCount,
children, children,
}: ICardsProps): React.ReactElement | null { }: ICardsProps): React.ReactElement | null {
const [cardNumber, setCardNumber] = useState<number>(columnCount || 4);
const ref = useRef() as React.MutableRefObject<HTMLDivElement>;
if (!items || !items.length) return null; if (!items || !items.length) return null;
const configs = getDefaultProps(children) as IColumn[]; const configs = getDefaultProps(children) as IColumn[];
const lines = getCardConfigs(configs) as IColumn[]; const lines = getCardConfigs(configs) as IColumn[];
useLayoutEffect(() => {
const width = ref?.current?.offsetWidth;
let count = 4;
if (width < 1100) count = 3;
if (width < 850) count = 2;
if (width < 700) count = 1;
setCardNumber(columnCount || count);
}, []);
const cards = items?.map((item: any, index: number) => ( const cards = items?.map((item: any, index: number) => (
<Card <Card
key={index} key={index}
item={item} item={item}
lines={lines} lines={lines}
customStyle={[
{ width: 'calc(100% - 24px)' },
{ width: 'calc(50% - 24px)' },
{ width: 'calc(33.33% - 24px)' },
{ width: 'calc(25% - 24px)' },
][cardNumber - 1]}
className={className} className={className}
/> />
)); ));
return ( return (
<div className={style.card_wrapper}> <div
ref={ref}
className={style.card_wrapper}
>
{cards} {cards}
</div> </div>
); );
@ -42,6 +65,7 @@ function Cards({
Cards.defaultProps = { Cards.defaultProps = {
items: [], items: [],
className: undefined, className: undefined,
columnCount: undefined,
}; };
export default Cards; export default Cards;

View file

@ -4,17 +4,17 @@
display: inline-block; display: inline-block;
width: 100%; width: 100%;
padding: var(--space-s); padding: var(--space-s);
margin: 0 0 var(--space-xxl) 0; margin: 0 var(--space-xxl) var(--space-xxl) 0;
border-radius: var(--border-radius-s); border-radius: var(--border-radius-m);
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
vertical-align: top; page-break-inside: avoid;
box-sizing: border-box; box-sizing: border-box;
box-shadow: 4px 4px 4px #CCCCCC; vertical-align: top;
background-color: white;
&_wrapper { &_wrapper {
margin-top: var(--space-xxl); width: calc(100% + 24px);
column-count: 4; margin: 0;
column-gap: var(--space-xxl);
} }
&_title { &_title {
@ -64,21 +64,3 @@
.card_line + .card_line { .card_line + .card_line {
border-top: 1px solid var(--color-border); border-top: 1px solid var(--color-border);
} }
@media (max-width: 1350px) {
.card_wrapper {
column-count: 3;
}
}
@media (max-width: 1100px) {
.card_wrapper {
column-count: 2;
}
}
@media (max-width: 700px) {
.card_wrapper {
column-count: 1;
}
}

View file

@ -2,7 +2,10 @@
.paginator { .paginator {
display: block; display: block;
margin: 24px auto 0 auto; margin: 0 auto 24px auto;
white-space: normal;
box-sizing: border-box;
vertical-align: top;
} }
.paginator_text { .paginator_text {

View file

@ -1,16 +1,26 @@
@import '../../../styles/variables'; @import '../../../styles/variables';
.data_view { .data_view {
&_icon { &_buttons {
position: absolute; position: absolute;
top: -48px; top: -48px;
right: 24px; right: 24px;
text-align: right;
}
&_icon {
display: inline-block; display: inline-block;
width: var(--space-xxl); width: var(--space-xxl);
height: var(--space-xxl); height: var(--space-xxl);
padding: 0; padding: 0;
margin-left: var(--space-l);
cursor: pointer; cursor: pointer;
} }
} }
@media print {
.data_view_buttons {
display: none;
}
}

View file

@ -1,17 +1,22 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useParams } from 'react-router-dom';
import ISort from 'ts/interfaces/Sort'; import ISort from 'ts/interfaces/Sort';
import Table from 'ts/components/Table'; import Table from 'ts/components/Table';
import Cards from 'ts/components/Cards'; import Cards from 'ts/components/Cards';
import { downloadCsv } from 'ts/helpers/File';
import style from './index.module.scss'; import style from './index.module.scss';
import PageWrapper from '../Page/wrapper';
interface IDataViewProps { interface IDataViewProps {
rows: any[]; rows: any[];
type?: string; type?: string;
sort?: ISort[]; sort?: ISort[];
columnCount?: number,
className?: string, className?: string,
disabledRow?: (row: any) => boolean; disabledRow?: (row: any) => boolean;
converterToCsv?: Function,
updateSort?: Function, updateSort?: Function,
children: React.ReactNode | React.ReactNode[]; children: React.ReactNode | React.ReactNode[];
} }
@ -20,11 +25,13 @@ function DataView({
rows = [], rows = [],
sort = [], sort = [],
type, type,
columnCount,
className, className,
disabledRow, disabledRow,
updateSort, updateSort,
children, children,
}: IDataViewProps): React.ReactElement | null { }: IDataViewProps): React.ReactElement | null {
const urlParams = useParams<any>();
const [localType, setType] = useState<string>(type || 'table'); const [localType, setType] = useState<string>(type || 'table');
if (!rows || !rows.length) return null; if (!rows || !rows.length) return null;
@ -41,29 +48,45 @@ function DataView({
return ( return (
<> <>
<img <div style={{ position: 'relative' }}>
title={title} <div className={style.data_view_buttons}>
src={icon} <img
className={style.data_view_icon} title={'Скачать CSV'}
onClick={() => { src="./assets/icons/Download.svg"
setType(localType === 'table' ? 'cards' : 'table'); className={style.data_view_icon}
}} onClick={() => {
/> const fileName = `${urlParams.type || ''} ${urlParams.page || ''}`;
downloadCsv(rows, children, fileName);
}}
/>
<img
title={title}
src={icon}
className={style.data_view_icon}
onClick={() => {
setType(localType === 'table' ? 'cards' : 'table');
}}
/>
</div>
</div>
{localType === 'table' && ( {localType === 'table' && (
<Table <PageWrapper template="table">
rows={rows} <Table
sort={sort} rows={rows}
disabledRow={disabledRow} sort={sort}
updateSort={updateSort} disabledRow={disabledRow}
> updateSort={updateSort}
{children} >
</Table> {children}
</Table>
</PageWrapper>
)} )}
{localType === 'cards' && ( {localType === 'cards' && (
<Cards <Cards
items={rows} items={rows}
columnCount={columnCount}
className={className} className={className}
> >
{children} {children}
@ -77,6 +100,7 @@ DataView.defaultProps = {
rows: [], rows: [],
sort: [], sort: [],
type: 'table', type: 'table',
columnCount: undefined,
updateSort: () => { updateSort: () => {
}, },
}; };

View file

@ -9,11 +9,11 @@ import style from '../styles/card.module.scss';
function getClassName(recommendation?: any) { function getClassName(recommendation?: any) {
const type = recommendation?.type; const type = recommendation?.type;
return { return {
[RECOMMENDATION_TYPES.INFO]: style.card_info, [RECOMMENDATION_TYPES.INFO]: style.recommendations_card_info,
[RECOMMENDATION_TYPES.FACT]: style.card_fact, [RECOMMENDATION_TYPES.FACT]: style.recommendations_card_fact,
[RECOMMENDATION_TYPES.WARNING]: style.card_warning, [RECOMMENDATION_TYPES.WARNING]: style.recommendations_card_warning,
[RECOMMENDATION_TYPES.ALERT]: style.card_error, [RECOMMENDATION_TYPES.ALERT]: style.recommendations_card_error,
}[type || RECOMMENDATION_TYPES.INFO] ?? style.card_fact; }[type || RECOMMENDATION_TYPES.INFO] ?? style.recommendations_card_fact;
} }
function getDescriptionText(recommendation?: any) { function getDescriptionText(recommendation?: any) {
@ -52,17 +52,17 @@ function Card({
const mainText = parts.join('\n'); const mainText = parts.join('\n');
return ( return (
<div className={`${style.card} ${className}`}> <div className={`${style.recommendations_card} ${className}`}>
<div className={style.card_wrapper}> <div className={style.recommendations_card_wrapper}>
<h5 className={style.card_title}> <h5 className={style.recommendations_card_title}>
<span className={style.card_icon}></span> <span className={style.recommendations_card_icon}></span>
{localization.get(formattedTitle, titleArgs)} {localization.get(formattedTitle, titleArgs)}
</h5> </h5>
<Description <Description
style={{ color: '#12131B' }} style={{ color: '#12131B' }}
text={previewText || ''} text={previewText || ''}
/> />
<div className={style.card_shortcut}> <div className={style.recommendations_card_shortcut}>
<Description <Description
style={{ color: '#12131B' }} style={{ color: '#12131B' }}
text={mainText || ''} text={mainText || ''}

View file

@ -1,26 +0,0 @@
import React, { ReactNode } from 'react';
import style from './index.module.scss';
interface IRecommendationsProps {
children: ReactNode | string | null;
template?: string;
}
function Recommendations({
children,
template,
}: IRecommendationsProps) {
const className = template === 'box'
? `${style.main_wrapper} ${style.main_wrapper_white}`
: `${style.main_wrapper}`;
return (
<div className={className}>
{children}
</div>
);
}
export default Recommendations;

View file

@ -1,26 +0,0 @@
import React, { ReactNode } from 'react';
import style from './index.module.scss';
interface IRecommendationsProps {
children: ReactNode | string | null;
template?: string;
}
function Recommendations({
children,
template,
}: IRecommendationsProps) {
const className = template === 'box'
? `${style.main_wrapper} ${style.main_wrapper_white}`
: `${style.main_wrapper}`;
return (
<div className={className}>
{children}
</div>
);
}
export default Recommendations;

View file

@ -1,73 +1,135 @@
@import '../../../../styles/variables'; @import '../../../../styles/variables';
.recommendations_short, .recommendations {
.recommendations_full { &_short,
position: relative; &_full {
display: block; position: relative;
max-height: 108px; display: block;
margin: 0 0 16px 0; max-height: 108px;
margin: 0 0 16px 0;
}
&_full {
max-height: none;
}
&_more,
&_card {
display: inline-block;
min-height: 100px;
max-height: 100px;
text-align: left;
vertical-align: top;
box-sizing: border-box;
white-space: normal;
border-radius: var(--border-radius-m);
background-color: white;
}
&_more {
position: absolute;
top: 0;
right: 0;
width: 30px;
margin: 0 0 8px 0;
text-align: center;
line-height: 100px;
cursor: pointer;
border: 1px solid var(--color-border);
color: #AAAAAA;
}
&_card {
position: relative;
width: 220px;
margin: 0 12px 16px 0;
border-left: none;
&_wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
display: block;
min-height: 100px;
max-height: 100px;
padding: 16px;
box-sizing: border-box;
overflow: hidden;
border-radius: var(--border-radius-m);
border: 1px solid var(--color-border);
border-left: 8px solid var(--color-border);
background-color: white;
}
&_icon {
position: absolute;
top: 16px;
left: 16px;
display: inline-block;
width: 18px;
height: 18px;
background-repeat: no-repeat;
background-position: center center;
background-size: 100% auto;
}
&_info {
--color-temp-border: #97C2A9;
--color-temp-icon: url('/assets/recommendations/info.svg');
--color-temp-bg: #E3F8EC;
--color-temp-title: #58866B;
}
&_fact {
--color-temp-border: var(--color-11);
--color-temp-icon: url('/assets/recommendations/info.svg');
--color-temp-bg: #EFF7FF;
--color-temp-title: var(--color-first);
}
&_warning {
--color-temp-border: var(--color-21);
--color-temp-icon: url('/assets/recommendations/warning.svg');
--color-temp-bg: #FFF5F2;
--color-temp-title: #E8B06D;
}
&_error {
--color-temp-border: var(--color-12);
--color-temp-icon: url('/assets/recommendations/alert.svg');
--color-temp-bg: #FFEFEE;
--color-temp-title: #DD8B87;
}
&_title {
font-weight: bold;
font-size: var(--font-xs);
display: block;
padding: 2px 0 0 24px;
margin: 0 auto 4px auto;
text-align: left;
text-decoration: none;
vertical-align: bottom;
color: var(--color-temp-title);
}
&_wrapper {
background-color: var(--color-temp-bg);
border-left-color: var(--color-temp-border);
}
}
} }
.recommendations_full { .recommendations_card:hover > .recommendations_card_wrapper {
max-height: none;
}
.more,
.card {
display: inline-block;
min-height: 100px;
max-height: 100px;
text-align: left;
vertical-align: top;
box-sizing: border-box;
white-space: normal;
border-radius: var(--border-radius-m);
background-color: white;
}
.more {
position: absolute;
top: 0;
right: 0;
width: 30px;
margin: 0 0 8px 0;
text-align: center;
line-height: 100px;
cursor: pointer;
border: 1px solid var(--color-border);
color: #AAAAAA;
}
.card {
position: relative;
width: 220px;
margin: 0 12px 16px 0;
border-left: none;
}
.card_wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
display: block;
min-height: 100px;
max-height: 100px;
padding: 16px;
box-sizing: border-box;
overflow: hidden;
border-radius: var(--border-radius-m);
border: 1px solid var(--color-border);
border-left: 8px solid var(--color-border);
background-color: white;
}
.card:hover > .card_wrapper {
z-index: 2; z-index: 2;
width: 170%; width: 170%;
max-height: 450px; max-height: 450px;
@ -75,91 +137,30 @@
overflow-y: scroll; overflow-y: scroll;
} }
.card_wrapper::-webkit-scrollbar { .recommendations_card_wrapper::-webkit-scrollbar {
width: 8px; width: 8px;
background-color: transparent; background-color: transparent;
} }
.card_wrapper::-webkit-scrollbar-thumb { .recommendations_card_wrapper::-webkit-scrollbar-thumb {
background: #AAAAAA; background: #AAAAAA;
} }
.card_icon {
position: absolute;
top: 16px;
left: 16px;
display: inline-block;
width: 18px;
height: 18px;
background-repeat: no-repeat;
background-position: center center;
background-size: 100% auto;
}
.card_info {
--color-temp-border: #97C2A9;
--color-temp-icon: url('/assets/recommendations/info.svg');
--color-temp-bg: #E3F8EC;
--color-temp-title: #58866B;
}
.card_fact {
--color-temp-border: var(--color-11);
--color-temp-icon: url('/assets/recommendations/info.svg');
--color-temp-bg: #EFF7FF;
--color-temp-title: var(--color-first);
}
.card_warning {
--color-temp-border: var(--color-21);
--color-temp-icon: url('/assets/recommendations/warning.svg');
--color-temp-bg: #FFF5F2;
--color-temp-title: #E8B06D;
}
.card_error {
--color-temp-border: var(--color-12);
--color-temp-icon: url('/assets/recommendations/alert.svg');
--color-temp-bg: #FFEFEE;
--color-temp-title: #DD8B87;
}
.card_title {
font-weight: bold;
font-size: var(--font-xs);
display: block;
padding: 2px 0 0 24px;
margin: 0 auto 4px auto;
text-align: left;
text-decoration: none;
vertical-align: bottom;
color: var(--color-temp-title);
}
.card_wrapper {
background-color: var(--color-temp-bg);
border-left-color: var(--color-temp-border);
}
.recommendations_title { .recommendations_title {
color: var(--color-temp-border); color: var(--color-temp-border);
} }
.card_icon { .recommendations_card_icon {
background-image: var(--color-temp-icon); background-image: var(--color-temp-icon);
} }
.card_shortcut { .recommendations_card_shortcut {
display: none; display: none;
padding: 6px 0 0 0; padding: 6px 0 0 0;
margin: 6px 0 0 0; margin: 6px 0 0 0;
border-top: 1px solid var(--color-temp-border); border-top: 1px solid var(--color-temp-border);
} }
.card:hover .card_shortcut { .recommendations_card:hover .recommendations_card_shortcut {
display: block; display: block;
} }

View file

@ -16,9 +16,13 @@ function Title({
className, className,
}: ITitleProps) { }: ITitleProps) {
return ( return (
<h3 className={`${style.title} ${addPadding ? style.title_padding : ''} ${className || ''}`}> <>
{localization.get(title || '')} <a // @ts-ignore
</h3> name={title}></a>
<h3 className={`${style.title} ${addPadding ? style.title_padding : ''} ${className || ''}`}>
{localization.get(title || '')}
</h3>
</>
); );
} }

View file

@ -1,747 +0,0 @@
import localization from 'ts/helpers/Localization';
localization.parse('en', `
§ uiKit.console: Copy
§ uiKit.dataLoader.page: Page
§ uiKit.dataLoader.size: Отображается по
§ uiKit.dataLoader.from: from
§ uiKit.dataLoader.all: Show all
§ uiKit.hoursChart.work: стандартное рабочее время (будни, с 07:00 до 20:00)
§ uiKit.hoursChart.weekend: выходные дни или время до/после рабочего дня
§ uiKit.hoursChart.days: суммарное количество коммитов за все время в конкретный день и час
§ uiKit.page.remove: 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: Task_number type(фича): message
§ uiKit.nothingFound.common.example: Example:
§ uiKit.nothingFound.staff.title: Нет данных для этого сотрудника
§ uiKit.nothingFound.staff.description1:
Он вносил правки не каждый рабочий день и получил статус «Помошник».
Работой сотрудников с таким статусом по данному проекту можно пренебречь, т.к. его влад на общем фоне незначителен.
§ uiKit.nothingFound.staff.description2:
Поэтому система не рассчитывает для него ряд показателей.
Если это ошибка и данного сотрудника нужно рассчитать как обычного, перейдите в раздел «Настройки» и измените его тип.
§ common.filters: Filters
§ common.notifications.save: Изменения сохранены
§ common.notifications.setting: Настройки сохранены
§ sidebar.switch.team: Team
§ sidebar.switch.person: Employee
§ sidebar.buttons.settings: Settings
§ sidebar.buttons.print: Print
§ sidebar.filters.all: all time
§ sidebar.filters.year: year
§ sidebar.filters.halfYear: half year
§ sidebar.filters.month: month
§ sidebar.filters.week: week
§ sidebar.team.total: Common info
§ sidebar.team.scope: Features
§ sidebar.team.author: Employees
§ sidebar.team.type: Task types
§ sidebar.team.pr: Pull requests
§ sidebar.team.day: By day
§ sidebar.team.week: By week
§ sidebar.team.month: By month
§ sidebar.team.tree: Files
§ sidebar.team.hours: Расписание
§ sidebar.team.commits: All commits
§ sidebar.team.changes: All changes
§ sidebar.team.words: Popular words
§ sidebar.team.top: Викторина
§ sidebar.team.settings: Settings
§ sidebar.person.total: Common info
§ sidebar.person.money: Work cost
§ sidebar.person.speed: Speed
§ sidebar.person.day: By day
§ sidebar.person.week: By week
§ sidebar.person.month: By month
§ sidebar.person.hours: Расписание
§ sidebar.person.commits: All commits
§ sidebar.person.changes: All changes
§ sidebar.person.words: Popular words
§ sidebar.person.settings: Settings
§ page.welcome.step1: Run this command in your project folder
§ page.welcome.step2: Move the file log.txt to this page
§ page.welcome.description1: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл
§ 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: Statistic by words
§ page.common.words.description: самое популярное слово. Встречается $1 раза.
§ page.common.commits.title: Commits number by days
§ page.common.commits.description: ($1) самый продуктивный день по числу коммитов.
§ page.common.commits.title2: $1 сделано коммитов: $2
§ page.common.filter.allUsers: Не имеет значения
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Language
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task number
§ page.settings.links.pr: For Pull Requests
§ page.settings.user.title: Employees settings
§ page.settings.user.notFound: Индивидуальных настроек нет. Данные по всем сотрудникам вычисляются по общим параметрам.
§ page.settings.user.subTitle: Дополнение к трудовому договору $1
§ page.settings.user.from: Дата начала действия
§ page.settings.mailmap: .mailmap settings
§ page.settings.common.title: Общие данные по зарплате
§ page.settings.common.type.title: Work type
§ page.settings.common.type.full: Full-time
§ page.settings.common.type.part: Проектная работа
§ page.settings.common.salary: Зарплата в месяц
§ page.settings.common.currency: Currency
§ page.settings.common.workDaysInYear: Количество рабочих дней в году
§ page.settings.common.vacationDaysInYear: Количество дней отпуска в год
§ page.settings.common.workDaysInWeek: Рабочие дни
§ page.settings.form.save: Save
§ page.settings.form.cancel: Cancel
§ page.settings.form.remove: Remove
§ page.settings.form.addEmployee: Add employee
§ page.settings.form.addContract: Добавить трудовой договор
§ page.print.title: What are we printing?
§ page.print.page: This page
§ page.print.type: This section
§ page.print.all: All statistics
§ page.print.cancel: Cancel
§ page.team.author.title: Статистика по сотрудникам
§ page.team.author.description1: *Часть статитики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помошник» не считается*, т.к. это эпизодическая роль в проекте. Предпологаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы.
§ page.team.author.description2: *Сортировка по умолчанию* это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники).
§ page.team.author.types: Types
§ page.team.author.commits: Commits
§ page.team.author.commitsSmall: commits
§ page.team.author.tasks: Tasks
§ page.team.author.tasksSmall: tasks
§ page.team.author.workedLosses: Days with and without commits
§ page.team.author.worked: work
§ page.team.author.losses: days without commits
§ page.team.author.days: days
§ page.team.author.daysForTask: Дней на задачу
§ page.team.author.scopes: Features
§ page.team.author.moneyAll: Получил
§ page.team.author.moneyWorked: Отработал
§ page.team.author.moneyLosses: Переплата
§ page.team.hours.title: Распределение коммитов в течении каждого дня недели
§ page.team.month.title: Календарь работы по проекту
§ page.team.scope.title: Statistic by features
§ page.team.scope.scope: Feature
§ page.team.scope.days: Раб. дней
§ page.team.scope.authorsDays: Человеко-дней
§ page.team.scope.tasks: Tasks
§ page.team.scope.commits: Commits
§ page.team.scope.commitsSmall: commits
§ page.team.scope.types: Types
§ page.team.scope.authors: Персональный вклад
§ page.team.scope.cost: Cost
§ page.team.type.title: Статистика по типам задач
§ page.team.type.description: *Персональный вклад* считается по количеству коммитов, а не объему измененных строк или файлов. Поэтому следует так же смотреть раздел «Анализ файлов», чтобы оценить масштаб изменений.
§ page.team.type.type: Task types
§ page.team.type.tasks: Tasks
§ page.team.type.tasksSmall: tasks
§ page.team.type.days: Days
§ page.team.type.daysSmall: days
§ page.team.type.authorsDays: Человеко-дней
§ page.team.type.commits: Commits
§ page.team.type.authors: Персональный вклад
§ page.team.total.titleA: Scope of work
§ page.team.total.titleB: Cost
§ page.team.total.daysWorked.title: человеко-дней
§ page.team.total.daysWorked.description: Учтены только дни, в которые делались коммиты
§ page.team.total.commits.title: commits
§ page.team.total.commits.description: Удалённые ветки не считаются
§ page.team.total.daysLosses.title: days without commits
§ page.team.total.daysLosses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.team.total.employment.title: работает / уволилось
§ page.team.total.employment.description: Если сотрудник в течении месяца не сделал ни одного коммита, он считается уволенным
§ page.team.total.moneyAll.title: общая
§ page.team.total.moneyAll.description: Суммарные затраты на зп
§ page.team.total.moneyWorked.title: фактическая
§ page.team.total.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.team.total.moneyLosses.title: possible overpayment
§ page.team.total.moneyLosses.description: Оплаченные рабочие дни, когда коммитов не было
§ page.team.total.weekendPayment.title: work on weekend
§ page.team.total.weekendPayment.description: Суммарная переплата за работу в выходные дни
§ page.team.total.workSpeed.title: tasks in day
§ page.team.total.workSpeed.description: Средняя скорость работы команды при текущем составе сотрудников
§ page.team.total.moneySpeed.title: в месяц
§ page.team.total.moneySpeed.description: Прогнозируемая сумма выплаты на зп при текущем составе сотрудников без учета налогов и сопутствующих затрат
§ page.team.total.description1: *Человеко-дни* это работа одного сотрудника в течение одного рабочего дня. Например, за один календарный день, команда из трех сотрудников выдает объем работы в три человеко-дня.
§ page.team.total.description2: *Днями прогулов* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют.
§ page.team.total.description3: Карточка *работает и уволилось* показывает фактический состав сотрудников, которые постоянно участвуют в работе. Кроме этого, есть «помощники» это сотрудники, как правило другой специализации, которые могут иногда делать коммиты в проект.
§ page.team.total.description4: *Переплатой* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют. Именно поэтому переплата + фактическая стоимость != общей. В общей стоимости заложена оплата выходных, государственных праздников и отпусков.
§ page.team.total.description5: *Работой на выходных* считается по коэфициенту х2 от оплаты обычного дня. Выше отображена именно переплата (х1), т.к. сам факт переработки в данном контексте не интересен. Мы не смотрим скорость сжигания бюджета. Мы смотрим переплату при увеличении скорости работы.
§ page.team.tree.title: Дерево проекта с учётом выбранных фильтров
§ page.team.tree.filters.author: Employee
§ page.team.tree.filters.commits: Commits number
§ page.team.tree.filters.help: Минимальное количество коммитов, которое сделал сотрудник в файле
§ page.team.tree.filters.all: All employees
§ page.team.tree.add: Who added it
§ page.team.tree.change: Who changed it
§ page.team.tree.remove: Who removed it
§ page.team.tree.line: lines
§ page.team.tree.lineAdd: added
§ page.team.tree.lineRemove: changed
§ page.team.week.date: Date
§ page.team.week.numberTasks: Количество задач
§ page.team.week.people: Количество человек
§ page.team.week.line: Изменение строк
§ page.team.week.days: Days with and without commits
§ page.team.week.lossesDetails: Кто не коммитил
§ page.team.week.add: added
§ page.team.week.change: changed
§ page.team.week.remove: removed
§ page.team.week.hasCommits: были коммиты
§ page.team.week.hasNotCommits: небыло коммитов
§ page.team.week.days: days
§ page.team.week.tasks: tasks
§ page.team.pr.task: Task
§ page.team.pr.tasks: tasks
§ page.team.pr.firstCommitTime: First commit
§ page.team.pr.lastCommitTime: Last
§ page.team.pr.workDays: Дней разработки
§ page.team.pr.delayDays: Дней ожидания влития
§ page.team.pr.commits: Commits
§ page.team.pr.date: Дата влития
§ page.team.pr.mergeAuthor: Влил
§ page.team.pr.author: Employee
§ page.team.pr.middleTimeRelease: Среднее время поставки (дни)
§ page.team.pr.work: разработка
§ page.team.pr.delay: waiting
§ page.team.pr.days: days
§ page.team.pr.oneTaskDays: Время потраченное на одну задачу
§ page.team.pr.description1: *Время разработки* это разница времени от первого до последнего коммита по задаче. Не важно были перерывы в несколько дней между коммитами или нет. Сам факт какого-либо коммита увеличивает время.
§ page.team.pr.description2: *Время ожидания* это время между последним коммитом и влитием кода. Оно показывает фактический простой в ожидании чего-либо.
§ page.team.pr.description3: *Зачем отображать время разработки* без разбивки на кодинг и код-ревью? Затем, чтобы показать бизнесу фактическое время поставки кода. Ожидание тестирования, замечания на ревью, проблемы DevOps и прочие несовершенства процесса, как раз уже заложены в этот срок.
§ page.team.pr.statByAuthors: Statistics by employee
§ page.team.pr.longDelay: Длительное ожидание влития
§ page.person.print.photo.title: Photo
§ page.person.print.photo.description: место для фотографии
§ page.person.total.title: Основные характеристики
§ page.person.total.daysWorked.title: days of work
§ page.person.total.daysWorked.description: Учтены только дни, в которые делались коммиты
§ page.person.total.tasks.title: tasks
§ page.person.total.tasks.description: Если коммиты правильно подписаны
§ page.person.character.title: Персонаж
§ page.person.achievement.title: Achievements
§ page.person.achievement.positive: Positive
§ page.person.achievement.normal: Neutral
§ page.person.achievement.negative: Negative
§ page.person.achievement.description: Чем больше сотрудник набрал отрицательных достижений, тем больше вероятность, что ситуация нестандартная. Возможно, стоит изменить режим его работы, задачи или отчётность. Следует поговорить с ним и узнать, какие проблемы мешают его работе.
§ page.person.gets.title: Взятые геты:
§ page.person.gets.description: «Взять гет» в данном случае означает первым оставить коммит к&nbsp;задаче с&nbsp;&laquo;красивым&raquo; номером.
§ page.person.business.days.title: дней работы
§ page.person.business.days.description: Учтены только дни, в которые делались коммиты
§ page.person.business.tasks.title: tasks
§ page.person.business.tasks.description: Если коммиты правильно подписаны
§ page.person.business.losses.title: days without commits
§ page.person.business.losses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.person.business.commits.title: commits
§ page.person.business.commits.description: Удалённые ветки не считаются
§ page.person.business.time.description: Время от первого, до последнего коммита (в том числе, нерабочие дни)
§ page.person.business.time.title: Дней на проекте:
§ page.person.business.time.dismissed: (dismissed)
§ page.person.business.time.staff: (not in the team)
§ page.person.business.achievements: Achievements
§ page.person.changes.title: Achievements
§ page.person.changes.description:
При некоторых видах форматирования git отмечает строки как «удалённые» и «добавленные»,
хотя на самом деле они были «изменёны». Поэтому, если вы провели большой рефакторинг,
git может показать малое количество изменений в статистике, а фактический результат
будет отмечен, как скачок «удаленных» и «добавленных» строк.
§ page.person.changes.description: Список коммитов и количество изменений в них за этот день:
§ page.person.commits.title: Commits list:
§ page.person.money.title.total: For all the time
§ page.person.money.title.middle: Middle cost
§ page.person.money.moneyAll.title: received
§ page.person.money.moneyAll.description: Предполагаемая сумма зп с проекта (см. настройки)
§ page.person.money.moneyWorked.title: отработал
§ page.person.money.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.person.money.moneyLosses.title: possible overpayment
§ page.person.money.moneyLosses.description: Дни без коммитов умноженные на среднюю зп
§ page.person.money.tasks.title: task
§ page.person.money.tasks.description: Количество закрытых задач к стоимости дня
§ page.person.money.commits.title: commit
§ page.person.money.commits.description: Количество коммитов к стоимости рабочего дня
§ page.person.speed.task: One task on average is
§ page.person.speed.max: Максимальная скорость в день
§ page.person.speed.days.title: days
§ page.person.speed.days.description: Имеются ввиду рабочие дни, если коммиты правильно подписаны
§ page.person.speed.commits.title: commits
§ page.person.speed.commits.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.line.title: code lines
§ page.person.speed.line.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.tasks.title: tasks
§ page.person.speed.tasks.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.speed.maxCommits.title: commits
§ page.person.speed.maxCommits.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.hours.title: Распределение коммитов в течении каждого дня недели
§ page.person.week.date: Date
§ page.person.week.tasks: Number of tasks
§ page.person.week.workDays: Days with commits
§ page.person.week.taskInDay: Tasks per day
§ page.person.week.days: days
§ page.person.week.workDay: weekdays
§ page.person.week.weekends: weekends
§ recommendations.title
Рекомендации и факты
§ recommendations.scope.parallelism.not.title
Нет паралельных работ
§ recommendations.scope.parallelism.not.description
любую фичу в один момент времени делает один человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат меньше 1.3 считаем, что паралельных работ в рамках большинства фичей обычно нет;
# Почему это плохо:
- повышается bus factor;
- сотрудники медленее развиваются;
- трудно качественно проверить работу сотрудника;
# Почему это хорошо:
- появляюся эксперты, которые очень глубоко погружены в предметную область и могут предложить более качественные решения;
- скорее всего не бывает merge конфликтов;
- проект может очень быстро паралельно развиваться в разные стороны;
§ recommendations.scope.parallelism.has.title
Часть работ паралельно
§ recommendations.scope.parallelism.has.description
Иногда фичу делают одновременно несколько человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат от 1.3 до 2.0 считаем, что часть работ в рамках разных фичей иногда делалается паралельно;
§ recommendations.scope.parallelism.every.title
Паралельные работы
§ recommendations.scope.parallelism.every.description
любую фичу в один момент времени делают несколько человек
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат больше двух считаем, что большая часть работ в рамках разных фичей обычно делалается паралельно;
§ recommendations.scope.money
в такую сумму можно оценить работу по данному проекту.
# Метод расчёта:
- человеко-дни затраченные на разработку умножаются на индивидуальную зарплату разработчиков;
Изменить зарплату каждого разработчика, для более точной суммы, можно в разделе «Настройки»
# Это много или мало?
Для ответа на этот вопрос, нужно ответить на следующие:
- Можно ли за эти деньги было купить готовое решение?
- Можно ли за эти деньги сделать более хороший продукт?
Если ответ на оба вопроса «да», то возможно, разработка с нуля не стоила потраченных на неё денег.
§ recommendations.scope.bus.everyHasOne.title
Bus factor = 1
§ recommendations.scope.bus.everyHasOne.description
В большинство фич погружен один человек.
Надо переключать людей.
# Почему это плохо:
- если сотрудники будут увольнятся, будет трудно продолжить их работу;
- невозможно контролировать качество его кода;
# Как делается выборка:
- более 80% коммитов в фичу делает один человек;
- проект имеет более 60% таких фичей;
§ recommendations.scope.bus.oneMaintainer
в фичи погружен один человек.
# Почему это плохо:
- если он уволится, будет трудно продолжить разработку;
- снижается качество code-review;
- трудно запаралелить разработку при необходимости;
# Как делается выборка:
- более 80% коммитов в фичу сделал один человек;
§ recommendations.scope.types.process.title
Плохие процессы
§ recommendations.scope.types.process.description
Большинство фич содержат один тип задач.
§ recommendations.scope.types.one
фичи содержат один тип задач.
§ recommendations.scope.types.common
Возможно, разработчики неправильно подписывают коммиты или менеджер заводит один и тот же тип задач.
# Почему это важно:
- невозможно передать поддержку другой команде;
- невозможно выпустить "коробочную" версию;
- сильная зависимость от конкретных разработчиков;
- большое количество ошибок и низкое качество кода;
- вероятное замедление разработки в будущем;
# В чём ошибка менеджера:
- взгляд на продукт, только с позиции «работающей демки»;
# Что должно быть:
- тесты;
- ошибки (выявленные по результатам тестов);
- рефакторинг (т.к. архитектура может измениться);
- документация;
- правки стиля (как результат опроса фокус-группы);
§ recommendations.scope.plan.title
Постройте долгосрочный план
§ recommendations.scope.plan.description
с учетом архитектуры.
При том опираться этот план должен сразу на самые трудные задачи.
# Почему отсутствие плана плохо:
- сотрудники делают минимально работающую версию, не закладывая точки расширения. После этого пишется не масштабируемый код, который тормозит следующие фичи;
# В чём ошибка менеджера:
- он не показал, как продукт будет развиваться далее и в каких точках будет рост;
# Как должно быть:
- составлятся глобальный план развития продукта;
- составлятся глобальный план развития архитектуры (с разработчиками и DBA);
- на уровне схем сразу проговариваются моменты, которые могут сильно измениться;
§ recommendations.scope.cost.title
Оцените инвестиции в фичу
§ recommendations.scope.cost.description
с количеством потенциальной прибыли.
Фичи которые дорого стоят в разработке, но приносят мало прибыли, возможно, стоит отложить или вообще отменить. Это сделает проект более комерчески успешным.
§ recommendations.author.lotOfLazy
пишет слишком мало кода.
# Может уволить?
- он тимлид, архитектор, аналитик?
- это его основной проект?
- есть какие-то зависимости от него?
# Почему нет смысла исправлять
Суммарные затраты на разработчика уже больше чем прибыль от его работы.
Если мы считаем, что обьективных помех его работе не было, то человек либо не хочет работать вообще, либо работает на двух проектах одновременно.
Увольнение и замена новым сотрудником выглядит оправданным с точки зрения общей статистики.
§ recommendations.author.manyLazy
пишет мало кода. Нужно взять на контроль.
# Как делается выборка:
- на тестовых выборках хороший программист пишет код больше 80% времени;
- в данном случае показатель от 60% до 80%;
# Как контролировать:
- дробить задачи на 1..2 дня;
- каждый день спрашивать статус;
- убедиться, что задачи хорошо расписаны и готовы к началу разработки;
- устроить парное программирование, чтобы проверить фактическую скорость;
§ recommendations.author.oneTypeMans
получает слишком однообразные задачи по типу. Может выгореть.
# Почему это важно:
- если сотрудник выгорит, его скорость работы снизится;
- замедляется профессиональный рост;
- повышается вероятность увольнения;
# Как делается выборка:
- для каждого коммита определятся тип задачи;
- если больше 70% задач одного типа, значит человек делает одно и тоже;
§ recommendations.author.projectType.openSource.title
Открытый проект
§ recommendations.author.projectType.openSource.description
пять дней в неделю тут не работают.
Проект может быть и закрытым, просто такой темп работы обычно у открытых библиотек на GitHub.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- у open-source библиотек рабочих дней обычно максимум 15..20%;
# Последствия
Для проектов, где работа не постоянна, нет смысла во многих показателях. Поэтому показатели без коммитов, скорости и т.п. будут скрыты.
Как правило, оценку таких проектов делают перед началом разработки своей закрытой версии. Самые интересные показатели в этом случае вероятная стоимость и суммарное время на разработку.
§ recommendations.author.projectType.easy.title
Слабая загрузка
§ recommendations.author.projectType.easy.description
слишком много дней без коммитов. Нужно понять почему команда не пишет код.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- загрузка считается слабой, если процент без коммитов от 5% до 20%;
# Возможные причины:
- фактически нет задач;
- задачи есть, но хорошо ложатся на текущую архитектуру;
- разработчиков отвлекают совещаниями;
- команда не работает;
# Варианты решения:
- обсудить проблему с командой;
- уменьшить гранулярность задач, чтобы за день можно было успеть сделать одну или две задачи;
- ввести ежедневные совещания, чтобы проверять движение задач по статусу;
- устроить сеансы парного программирования, чтобы убедиться, что разработчик может работать быстрее;
§ recommendations.author.manager.title
Обозначьте дедлайны
§ recommendations.author.manager.description
У любой задачи должен быть чёткий дедлайн.
Это позволит не затягивать её выполнение на несколько дней или недель.
# Какие показатели стоит проверить:
- количество дней на одну задачу, которое тратит работник;
- количество дней ожидания влития PR (страница статистики по PR);
§ recommendations.author.shorTalk.title
Проводите ежедневные совещания
§ recommendations.author.shorTalk.description
они помогают быть в курсе проекта.
Не растягивайте их отвлекаясь на постороние темы.
# На какие вопросы должен ответить сотрудник:
- что было сделано;
- что будет сделано;
- есть ли какие-либо проблемы;
# Следует обрывать монолог, если:
- начинают подробно описывать мелкие детали, которые не важны;
- уводят диалог в сторону, от первоначального плана;
# Почему это важно:
Часто сотрудник, который ничего не делает, старается уйти от ответа. Для этого он рассказывает кучу ненужных подробностей свой работы. Это позволяет усыпить внимание участников и растянуть время ответа. Создается ощущение что он чем-то занят, хотя по факту работы не было.
§ recommendations.author.ipr.title
Составьте план обучения
§ recommendations.author.ipr.description
на каждого сотрудника.
*Индивидуальный план обучения* это список целей и задач, которые помогают человеку развиваться в определенной области.
# Как составить план:
- составить матрицу компетенций;
- определить по каким компетенциям меньше всего знаний и опыта;
- узнать какие из этих компетенций интересны сотруднику;
- придумать 3..5 целей в рамках каждой такой компетенции на пол-года или год;
- каждый месяц пытаться сделать что-либо для достижения одной цели;
- каждый месяц напоминать об общем плане достижения этих целей;
# Нужен ли план руководителю?
Да, руководитель так же должен составить план на себя. Если нет вышестоящего руководителя, то он должен проверять сам себя.
# Почему это важно:
- сотрудники становятся более лояльны к компании;
- за теже деньги вы получаете более квалифицированные кадры;
§ recommendations.author.oneToOne.title
Проводите 1-1 каждый месяц
§ recommendations.author.oneToOne.description
это поможет выявить проблемы на ранней стадии.
*One-to-one* это регулярные личные встречи руководителя с подчиненным. На таких встречах обычно обсуждают всё, что важно для сотрудника, что его волнует, и то, чем он может поделиться с руководителем только наедине.
# Почему это важно:
- легко выяснить, кто из сотрудников перегружен, а у кого есть свободное время;
- можно предотвратить выгорание сотрудника;
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается мотивация и вовлеченность сотрудников;
§ recommendations.author.club.title
Ходите в бар
§ recommendations.author.club.description
один раз в месяц или два.
Это поможет выстроить неформальную коммуникацию в коллективе и сплотить команду, даже если общение будет сжатым.
# Почему это важно:
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается вовлеченность сотрудников;
§ recommendations.hour.onlyWork.title
Выходных тут нет
§ recommendations.hour.onlyWork.description
Вероятно, стоит уволить менеджера проекта.
§ recommendations.hour.weekends.title
Работа на выходных
§ recommendations.hour.weekends.description
Вероятно, стоит проверить менеджера проекта.
§ recommendations.hour.easy.title
Бывают проблемы
§ recommendations.hour.easy.description
Вероятно, бывают завалы и приходится работать на выходных.
§ recommendations.week.lazyDays.down.title
Стало меньше прогулов
§ recommendations.week.lazyDays.down.description
за последние три недели этот показатель упал
§ recommendations.week.lazyDays.up.title
Стало больше прогулов
§ recommendations.week.lazyDays.up.description
нет задач или нужен более жесткий контроль
§ recommendations.week.notWork.title
Стабильно не дорабатывает
§ recommendations.week.notWork.description
т.к. каждую неделю пишет код не 100% времени
§ recommendations.week.upWork.title
Стабильно перерабатывает
§ recommendations.week.upWork.description
т.к. каждую неделю пишет код в выходные дни
§ recommendations.week.task.up.title
Растёт производительность
§ recommendations.week.task.up.description
или задачи стали слишком мелкие. Нужно проверить. Если гранулярность та же - закрепить результат.
§ recommendations.week.task.down.title
Падает производительность
§ recommendations.week.task.down.description
или задачи хуже разбивают. Нужно проверить. Если гранулярность та же - взять на контроль.
# Метод оценки:
- количество задач в день, над которыми работают, на протяжении последних трех недель стабильно падает.
# Возможные ошибки:
- задачи могли быть сложнее, чем казались;
- задачи могли иметь большой объём работы (нужно проверить количество изменений, падают они или нет за этот же период)
§ recommendations.type.everyHasOne.title
Не подписывают тип задачи
§ recommendations.type.everyHasOne.description
большинство типов задач делает один человек.
§ recommendations.type.oneMaintainer.title
Узкая специализация
§ recommendations.type.oneMaintainer.description
большинство задач одного типа делают одни и те же люди.
# Типы задач:
§ recommendations.type.common
# Возможно, это не так
Нужно убедиться, что остальные сотрудники верно подписывают коммиты.
Шаги, которые помогут это сделать:
- настроить пре-коммит проверку для commit message;
- объяснить команде, что нужно указывать тип;
- проверить в новых ветках, что сотрудники следуют правилу;
# Если это действительно так
Вы настроили проверки и убедились что один и тот же сотрудник, делает задачи одного и того же типа.
Почему это плохо:
- его увольнение остановит целую пачку процессов;
- уменьшается компетенция остальных членов команды;
- трудно верхнеуровнево понять его правки;
Как это исправить:
- распределять разные типы задач равномерно;
- менять область работы (тесты, документация, ошибки) между сотрудниками через спринт;
§ recommendations.type.fewTypes.title
Это локальный продукт
§ recommendations.type.fewTypes.description
для конкретного заказчика или проблемы.
# Какие признаки есть у «глобального» продукта:
- локализация;
- документация;
- большой обьем тестов;
- визуальная кастомизация;
- рефакторинг узких мест;
- и т.п.
# Почему этот продукт выглядит как «локальный»:
- у каждого «глобального» признака будет перевес по своему типу задач;
- чем больше «глобальных» признаков, тем больше вероятность «глобального» продукта;
В данном случае мы видим небольшое число типов, а следовательно, скорее всего есть недоработки, мешающие легко масштабировать продукт на мировой рынок и продавать его в других странах.
# Возможно, это не так
По типам файлов мы можем предположить тип программы (сайт, серверное приложение, 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 {};

View file

@ -1,889 +0,0 @@
import localization from 'ts/helpers/Localization';
localization.parse('ru', `
§ achievements.commitsAfter1500.title: Сова
§ achievements.commitsAfter1500.description: 70% коммитов после 15:00
§ achievements.commitsBefore1500.title: Ранняя пташка
§ achievements.commitsBefore1500.description: 70% коммитов до обеда
§ achievements.workEveryTime.title: Раб божий
§ achievements.workEveryTime.description: есть коммит на каждый час суток
§ achievements.workNotWork.title: Стрельба холостыми
§ achievements.workNotWork.description: коммиты есть, а закрытых задач нет
§ achievements.userNotWork.title: Залётный
§ achievements.userNotWork.description: это не его основной проект
§ achievements.userIsDied.title: Мёртвая душа
§ achievements.userIsDied.description: работал, но уволился
§ achievements.lessTasks.title: Зашел и вышел
§ achievements.lessTasks.description: меньше всего закрытых задач
§ achievements.moreTasks.title: Батя грит малаца
§ achievements.moreTasks.description: больше всего закрытых задач
§ achievements.everyMessageLong.title: Мастер красноречия
§ achievements.everyMessageLong.description: стабильно самые длинные подписи коммитов
§ achievements.everyMessageShort.title: Болтун находка для шпиона
§ achievements.everyMessageShort.description: стабильно, самые короткие подписи коммитов
§ achievements.shortestName.title: Размер не главное
§ achievements.shortestName.description: самое короткое имя
§ achievements.longestName.title: Азим Азиз Иль Ам Кадир Имран II
§ achievements.longestName.description: самое длинное имя
§ achievements.moreCommits.title: Мастер бекапов
§ achievements.moreCommits.description: больше всего коммитов
§ achievements.lessCommits.title: Редко но метко
§ achievements.lessCommits.description: меньше всего коммитов
§ achievements.oneCommitOneTask.title: Точно в цель
§ achievements.oneCommitOneTask.description: в среднем один коммит на задачу
§ achievements.moreLazyDays.title: Мысленно я с вами
§ achievements.moreLazyDays.description: больше всего дней без коммитов
§ achievements.lessLazyDays.title: Папа Карло
§ achievements.lessLazyDays.description: меньше всего дней без коммитов
§ achievements.zeroLazyDays.title: Ни единого разрыва
§ achievements.zeroLazyDays.description: ни одного дня без коммитов
§ achievements.moreWorkDays.title: Ценный работник
§ achievements.moreWorkDays.description: больше всего рабочих дней
§ achievements.moreScopes.title: Стартапер
§ achievements.moreScopes.description: сделал больше всего фичей
§ achievements.lessScopes.title: Щегол
§ achievements.lessScopes.description: сделал меньше всего фичей
§ achievements.moreDaysForTask.title: Улитка на склоне
§ achievements.moreDaysForTask.description: работа по задачам идёт медленнее чем у остальных
§ achievements.more2DaysForTask.title: Cо слоу
§ achievements.more2DaysForTask.description: больше двух дней на задачу
§ achievements.moreDaysInProject.title: Старожил
§ achievements.moreDaysInProject.description: больше всего дней на проекте
§ achievements.lessDaysInProject.title: А это кто?
§ achievements.lessDaysInProject.description: меньше всего дней на проекте
§ achievements.more90DaysInProject.title: Добро пожаловать
§ achievements.more90DaysInProject.description: не уволили на испытательном
§ achievements.lessDaysForTask.title: Скорострел
§ achievements.lessDaysForTask.description: одна задача занимает меньше дня
§ achievements.adam.title: Адам
§ achievements.adam.description: первый стабильный сотрудник на проекте
§ achievements.more666DaysInProject.title: Чёрт
§ achievements.more666DaysInProject.description: отработал 666 дней на проекте
§ achievements.more777DaysInProject.title: Азино 3 топора
§ achievements.more777DaysInProject.description: отработал 777 дней на проекте
§ achievements.moreRefactoring.title: Выпускающий редактор
§ achievements.moreRefactoring.description: сделал больше всех меток «рефакторинг»
§ achievements.longestMessage.title: А разговоров то было...
§ achievements.longestMessage.description: самая длинная подпись коммита за все время
§ achievements.moreTasksInDay.title: Спиди-гонщик
§ achievements.moreTasksInDay.description: рекорд по количеству закрытых задач в день
§ achievements.hasCommitFrom0to7.title: Ночной дозор
§ achievements.hasCommitFrom0to7.description: есть коммит на каждый час ночи
§ achievements.noCommitOnDay.title: Технический перерыв
§ achievements.noCommitOnDay.description: есть определенный час и день в рабочее время в который никогда не комитит
§ achievements.hasCommitEveryTime.title: Умер на работе
§ achievements.hasCommitEveryTime.description: есть коммит на час каждого дня (включая выходные)
§ achievements.commitsAfter1800.title: Делу время
§ achievements.commitsAfter1800.description: нет ни одного коммита после 18:00
§ achievements.more1488DaysInProject.title: им. Максима Марцинкевича
§ achievements.more1488DaysInProject.description: отработал 1488 дней на проекте
§ achievements.taskNumber300.title: Знаком с трактористом
§ achievements.taskNumber300.description: первый взял в работу задачу с номером 300
§ achievements.moreFix.title: Bug hunter
§ achievements.moreFix.description: больше всего закрытых багов
§ achievements.lessWorkDays.title: Дальше без меня
§ achievements.lessWorkDays.description: меньше всего рабочих дней
§ achievements.moreCreateCode.title: Созидатель
§ achievements.moreCreateCode.description: склонен больше остальных добавлять код
§ achievements.moreRemoveCode.title: Разрушитель
§ achievements.moreRemoveCode.description: склонен больше остальных удалять код
§ achievements.moreChangeCode.title: Реформатор
§ achievements.moreChangeCode.description: склонен больше остальных изменять код
§ achievements.moreStyle.title: Полиция моды
§ achievements.moreStyle.description: склонен больше остальных изменять CSS
§ achievements.moreOnHoliday.title: Нет жизни
§ achievements.moreOnHoliday.description: относительно много коммитов в нерабочее время
§ 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: Настройки сохранены
§ sidebar.switch.team: Команда
§ sidebar.switch.person: Сотрудник
§ sidebar.buttons.settings: Настройки
§ sidebar.buttons.print: Печать
§ sidebar.filters.all: всё время
§ sidebar.filters.year: год
§ sidebar.filters.halfYear: пол года
§ sidebar.filters.month: месяц
§ sidebar.filters.week: неделя
§ sidebar.team.total: Общая информация
§ sidebar.team.scope: Фичи
§ sidebar.team.author: Сотрудники
§ sidebar.team.type: Типы задач
§ sidebar.team.pr: Влитие кода
§ sidebar.team.day: По дням
§ sidebar.team.week: По неделям
§ sidebar.team.month: По месяцам
§ sidebar.team.tree: Анализ файлов
§ sidebar.team.hours: Расписание
§ sidebar.team.commits: Все коммиты
§ sidebar.team.changes: Все изменения
§ sidebar.team.words: Популярные слова
§ sidebar.team.top: Викторина
§ sidebar.team.settings: Настройки
§ sidebar.person.total: Общая информация
§ sidebar.person.money: Стоимость работы
§ sidebar.person.speed: Скорость
§ sidebar.person.day: По дням
§ sidebar.person.week: По неделям
§ sidebar.person.month: По месяцам
§ sidebar.person.hours: Расписание
§ sidebar.person.commits: Все коммиты
§ sidebar.person.changes: Все изменения
§ sidebar.person.words: Популярные слова
§ sidebar.person.settings: Настройки
§ page.welcome.step1: Выполните команду в корне вашего проекта
§ page.welcome.step3: Перетащите
§ page.welcome.step4: файл log.txt на эту страницу
§ page.welcome.description1: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл
§ 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.modal.title: Что распечатываем?
§ page.print.modal.page: Текущую страницу
§ page.print.modal.type: Текущий раздел
§ page.print.modal.all: Всю статистику
§ page.print.modal.cancel: Отмена
§ page.print.tableOfContents: Оглавление
§ page.print.title: Отчёт по git-репозиторию «$1»
§ page.print.description: Данные для отчёта были получены из истории коммитов.
§ page.team.author.title: Статистика по сотрудникам
§ page.team.author.description1: *Часть статитики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помошник» не считается*, т.к. это эпизодическая роль в проекте. Предпологаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы.
§ page.team.author.description2: *Сортировка по умолчанию* это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники).
§ page.team.author.types: Тип работ
§ page.team.author.commits: Коммитов
§ page.team.author.commitsSmall: коммитов
§ page.team.author.tasks: Задач
§ page.team.author.tasksSmall: задач
§ page.team.author.workedLosses: Дни с коммитами и без
§ page.team.author.worked: работа
§ page.team.author.losses: дни без коммитов
§ page.team.author.days: дней
§ page.team.author.daysForTask: Дней на задачу
§ page.team.author.scopes: Фич
§ page.team.author.moneyAll: Получил
§ page.team.author.moneyWorked: Отработал
§ page.team.author.moneyLosses: Переплата
§ page.team.hours.title: Распределение коммитов в течении каждого дня недели
§ page.team.month.title: Календарь работы по проекту
§ page.team.scope.title: Статистика по фичам
§ page.team.scope.scope: Фича
§ page.team.scope.days: Раб. дней
§ page.team.scope.authorsDays: Человеко-дней
§ page.team.scope.tasks: Задач
§ page.team.scope.commits: Коммитов
§ page.team.scope.commitsSmall: коммитов
§ page.team.scope.types: Тип работ
§ page.team.scope.authors: Персональный вклад
§ page.team.scope.cost: Стоимость
§ page.team.type.title: Статистика по типам задач
§ page.team.type.description: *Персональный вклад* считается по количеству коммитов, а не объему измененных строк или файлов. Поэтому следует так же смотреть раздел «Анализ файлов», чтобы оценить масштаб изменений.
§ page.team.type.type: Тип работы
§ page.team.type.tasks: Задач
§ page.team.type.tasksSmall: задач
§ page.team.type.days: Дней
§ page.team.type.daysSmall: дней
§ page.team.type.authorsDays: Человеко-дней
§ page.team.type.commits: Коммитов
§ page.team.type.authors: Персональный вклад
§ page.team.total.titleA: Объём работ
§ page.team.total.titleB: Стоимость
§ page.team.total.daysWorked.title: человеко-дней
§ page.team.total.daysWorked.description: Учтены только дни, в которые делались коммиты
§ page.team.total.commits.title: коммитов
§ page.team.total.commits.description: Удалённые ветки не считаются
§ page.team.total.daysLosses.title: дней без коммитов
§ page.team.total.daysLosses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.team.total.employment.title: работает / уволилось
§ page.team.total.employment.description: Если сотрудник в течении месяца не сделал ни одного коммита, он считается уволенным
§ page.team.total.moneyAll.title: общая
§ page.team.total.moneyAll.description: Суммарные затраты на зп
§ page.team.total.moneyWorked.title: фактическая
§ page.team.total.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.team.total.moneyLosses.title: возможная переплата
§ page.team.total.moneyLosses.description: Оплаченные рабочие дни, когда коммитов не было
§ page.team.total.weekendPayment.title: работа на выходных
§ page.team.total.weekendPayment.description: Суммарная переплата за работу в выходные дни
§ page.team.total.workSpeed.title: задач в день
§ page.team.total.workSpeed.description: Средняя скорость работы команды при текущем составе сотрудников
§ page.team.total.moneySpeed.title: в месяц
§ page.team.total.moneySpeed.description: Прогнозируемая сумма выплаты на зп при текущем составе сотрудников без учета налогов и сопутствующих затрат
§ page.team.total.description1: *Человеко-дни* это работа одного сотрудника в течение одного рабочего дня. Например, за один календарный день, команда из трех сотрудников выдает объем работы в три человеко-дня.
§ page.team.total.description2: *Днями прогулов* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют.
§ page.team.total.description3: Карточка *работает и уволилось* показывает фактический состав сотрудников, которые постоянно участвуют в работе. Кроме этого, есть «помощники» это сотрудники, как правило другой специализации, которые могут иногда делать коммиты в проект.
§ page.team.total.description4: *Переплатой* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют. Именно поэтому переплата + фактическая стоимость != общей. В общей стоимости заложена оплата выходных, государственных праздников и отпусков.
§ page.team.total.description5: *Работой на выходных* считается по коэфициенту х2 от оплаты обычного дня. Выше отображена именно переплата (х1), т.к. сам факт переработки в данном контексте не интересен. Мы не смотрим скорость сжигания бюджета. Мы смотрим переплату при увеличении скорости работы.
§ page.team.tree.title: Дерево проекта с учётом выбранных фильтров
§ page.team.tree.filters.author: Сотрудник
§ page.team.tree.filters.commits: Количество коммитов
§ page.team.tree.filters.help: Минимальное количество коммитов, которое сделал сотрудник в файле
§ page.team.tree.filters.all: Все сотрудники
§ page.team.tree.add: Кто добавлял
§ page.team.tree.change: Кто менял
§ page.team.tree.remove: Кто удалял
§ page.team.tree.line: строк
§ page.team.tree.lineAdd: добавили
§ page.team.tree.lineRemove: изменили
§ page.team.week.date: Дата
§ page.team.week.numberTasks: Количество задач
§ page.team.week.people: Количество человек
§ page.team.week.line: Изменение строк
§ page.team.week.days: Дни с коммитами и без
§ page.team.week.lossesDetails: Кто не коммитил
§ page.team.week.add: добавили
§ page.team.week.change: изменили
§ page.team.week.remove: удалили
§ page.team.week.hasCommits: были коммиты
§ 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: Основные характеристики
§ 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: «Взять гет» в данном случае означает первым оставить коммит к&nbsp;задаче с&nbsp;&laquo;красивым&raquo; номером.
§ page.person.business.days.title: дней работы
§ page.person.business.days.description: Учтены только дни, в которые делались коммиты
§ page.person.business.tasks.title: задач
§ page.person.business.tasks.description: Если коммиты правильно подписаны
§ page.person.business.losses.title: дней без коммитов
§ page.person.business.losses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.person.business.commits.title: коммитов
§ page.person.business.commits.description: Удалённые ветки не считаются
§ page.person.business.time.description: Время от первого, до последнего коммита (в том числе, нерабочие дни)
§ page.person.business.time.title: Дней на проекте:
§ page.person.business.time.dismissed: (уволен)
§ page.person.business.time.staff: (не в команде)
§ page.person.business.achievements: Достижения
§ page.person.changes.title: Достижения
§ page.person.changes.description:
При некоторых видах форматирования git отмечает строки как «удалённые» и «добавленные»,
хотя на самом деле они были «изменёны». Поэтому, если вы провели большой рефакторинг,
git может показать малое количество изменений в статистике, а фактический результат
будет отмечен, как скачок «удаленных» и «добавленных» строк.
§ page.person.changes.description: Список коммитов и количество изменений в них за этот день:
§ page.person.commits.title: Список коммитов:
§ page.person.money.title.total: За всё время
§ page.person.money.title.middle: Средняя стоимость
§ page.person.money.moneyAll.title: получил
§ page.person.money.moneyAll.description: Предполагаемая сумма зп с проекта (см. настройки)
§ page.person.money.moneyWorked.title: отработал
§ page.person.money.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.person.money.moneyLosses.title: возможная переплата
§ page.person.money.moneyLosses.description: Дни без коммитов умноженные на среднюю зп
§ page.person.money.tasks.title: задача
§ page.person.money.tasks.description: Количество закрытых задач к стоимости дня
§ page.person.money.commits.title: коммит
§ page.person.money.commits.description: Количество коммитов к стоимости рабочего дня
§ page.person.speed.task: Одна задача в среднем это
§ page.person.speed.max: Максимальная скорость в день
§ page.person.speed.days.title: дней
§ page.person.speed.days.description: Имеются ввиду рабочие дни, если коммиты правильно подписаны
§ page.person.speed.commits.title: коммитов
§ page.person.speed.commits.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.line.title: строк кода
§ page.person.speed.line.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.tasks.title: задач
§ page.person.speed.tasks.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.speed.maxCommits.title: коммитов
§ page.person.speed.maxCommits.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.hours.title: Распределение коммитов в течении каждого дня недели
§ page.person.week.date: Дата
§ page.person.week.tasks: Количество задач
§ page.person.week.workDays: Дни с коммитами
§ page.person.week.taskInDay: Задач в день
§ page.person.week.days: дней
§ page.person.week.workDay: будни
§ page.person.week.weekends: выходные
§ recommendations.title
Рекомендации и факты
§ recommendations.timestamp.firstCommit.description
сделал первый коммит
День недели: $1
§ recommendations.timestamp.lastCommit.description
сделал последний коммит
День недели: $1
§ recommendations.timestamp.common.title: $1 дней
§ recommendations.timestamp.allDays.description: от первого до последнего коммита (включая выходные и праздники).
§ recommendations.timestamp.lossesDays.description: без коммитов, даже с учётом выходных, отпуска и государственных праздников.
§ recommendations.timestamp.weekendDays.description
работы на выходных
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- сотрудники быстрее выгорают;
§ recommendations.timestamp.regularWeekendWord.title: Регулярные переработки
§ recommendations.timestamp.sometimeWeekendWord.title: Бывают переработки
§ recommendations.timestamp.weekendWord.description
Вероятно, стоит сменить менеджера проекта, аналитика и архитектора.
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- качество продуката, как правило, получается низкое;
- часть сотрудников увольняется;
- из-за спешки появляются новые ошибки;
# Скорее всего:
- неверно оценили сроки в самом начале;
- тех. задание отсутствует;
- слабая аналитика;
- слабая архитектура (архитектора не нанимали, а команда состоит из мидл разработчиков);
- сначала начали писать код, потом проектировать;
- нет нормальных процессов, чтобы понять ошибки;
§ recommendations.timestamp.neverWeekendWord.title: Обычно без переработок
§ recommendations.timestamp.neverWeekendWord.description
Но иногда бывают.
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- сотрудники быстрее выгорают;
§ recommendations.scope.parallelism.not.title
Нет паралельных работ
§ recommendations.scope.parallelism.not.description
любую фичу в один момент времени делает один человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат меньше 1.3 считаем, что паралельных работ в рамках большинства фичей обычно нет;
# Почему это плохо:
- повышается bus factor;
- сотрудники медленее развиваются;
- трудно качественно проверить работу сотрудника;
# Почему это хорошо:
- появляюся эксперты, которые очень глубоко погружены в предметную область и могут предложить более качественные решения;
- скорее всего не бывает merge конфликтов;
- проект может очень быстро паралельно развиваться в разные стороны;
§ recommendations.scope.parallelism.has.title
Часть работ паралельно
§ recommendations.scope.parallelism.has.description
Иногда фичу делают одновременно несколько человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат от 1.3 до 2.0 считаем, что часть работ в рамках разных фичей иногда делалается паралельно;
§ recommendations.scope.parallelism.every.title
Паралельные работы
§ recommendations.scope.parallelism.every.description
любую фичу в один момент времени делают несколько человек
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат больше двух считаем, что большая часть работ в рамках разных фичей обычно делалается паралельно;
§ recommendations.scope.money
в такую сумму можно оценить работу по данному проекту.
# Метод расчёта:
- человеко-дни затраченные на разработку умножаются на индивидуальную зарплату разработчиков;
Изменить зарплату каждого разработчика, для более точной суммы, можно в разделе «Настройки»
# Это много или мало?
Для ответа на этот вопрос, нужно ответить на следующие:
- Можно ли за эти деньги было купить готовое решение?
- Можно ли за эти деньги сделать более хороший продукт?
Если ответ на оба вопроса «да», то возможно, разработка с нуля не стоила потраченных на неё денег.
§ recommendations.scope.bus.everyHasOne.title
Bus factor = 1
§ recommendations.scope.bus.everyHasOne.description
В большинство фич погружен один человек.
Надо переключать людей.
# Почему это плохо:
- если сотрудники будут увольнятся, будет трудно продолжить их работу;
- невозможно контролировать качество его кода;
# Как делается выборка:
- более 80% коммитов в фичу делает один человек;
- проект имеет более 60% таких фичей;
§ recommendations.scope.bus.oneMaintainer
в фичи погружен один человек.
# Почему это плохо:
- если он уволится, будет трудно продолжить разработку;
- снижается качество code-review;
- трудно запаралелить разработку при необходимости;
# Как делается выборка:
- более 80% коммитов в фичу сделал один человек;
§ recommendations.scope.types.process.title
Плохие процессы
§ recommendations.scope.types.process.description
Большинство фич содержат один тип задач.
§ recommendations.scope.types.one
фичи содержат один тип задач.
§ recommendations.scope.types.common
Возможно, разработчики неправильно подписывают коммиты или менеджер заводит один и тот же тип задач.
# Почему это важно:
- невозможно передать поддержку другой команде;
- невозможно выпустить "коробочную" версию;
- сильная зависимость от конкретных разработчиков;
- большое количество ошибок и низкое качество кода;
- вероятное замедление разработки в будущем;
# В чём ошибка менеджера:
- взгляд на продукт, только с позиции «работающей демки»;
# Что должно быть:
- тесты;
- ошибки (выявленные по результатам тестов);
- рефакторинг (т.к. архитектура может измениться);
- документация;
- правки стиля (как результат опроса фокус-группы);
§ recommendations.scope.plan.title
Постройте долгосрочный план
§ recommendations.scope.plan.description
с учетом архитектуры.
При том опираться этот план должен сразу на самые трудные задачи.
# Почему отсутствие плана плохо:
- сотрудники делают минимально работающую версию, не закладывая точки расширения. После этого пишется не масштабируемый код, который тормозит следующие фичи;
# В чём ошибка менеджера:
- он не показал, как продукт будет развиваться далее и в каких точках будет рост;
# Как должно быть:
- составлятся глобальный план развития продукта;
- составлятся глобальный план развития архитектуры (с разработчиками и DBA);
- на уровне схем сразу проговариваются моменты, которые могут сильно измениться;
§ recommendations.scope.cost.title
Оцените инвестиции в фичу
§ recommendations.scope.cost.description
с количеством потенциальной прибыли.
Фичи которые дорого стоят в разработке, но приносят мало прибыли, возможно, стоит отложить или вообще отменить. Это сделает проект более комерчески успешным.
§ recommendations.author.lotOfLazy
пишет слишком мало кода.
# Может уволить?
- он тимлид, архитектор, аналитик?
- это его основной проект?
- есть какие-то зависимости от него?
# Почему нет смысла исправлять
Суммарные затраты на разработчика уже больше чем прибыль от его работы.
Если мы считаем, что обьективных помех его работе не было, то человек либо не хочет работать вообще, либо работает на двух проектах одновременно.
Увольнение и замена новым сотрудником выглядит оправданным с точки зрения общей статистики.
§ recommendations.author.manyLazy
пишет мало кода. Нужно взять на контроль.
# Как делается выборка:
- на тестовых выборках хороший программист пишет код больше 80% времени;
- в данном случае показатель от 60% до 80%;
# Как контролировать:
- дробить задачи на 1..2 дня;
- каждый день спрашивать статус;
- убедиться, что задачи хорошо расписаны и готовы к началу разработки;
- устроить парное программирование, чтобы проверить фактическую скорость;
§ recommendations.author.oneTypeMans
получает слишком однообразные задачи по типу. Может выгореть.
# Почему это важно:
- если сотрудник выгорит, его скорость работы снизится;
- замедляется профессиональный рост;
- повышается вероятность увольнения;
# Как делается выборка:
- для каждого коммита определятся тип задачи;
- если больше 70% задач одного типа, значит человек делает одно и тоже;
§ recommendations.author.workToday.title: Работает $1
§ recommendations.author.workToday.description
над проектом в данный момент.
# Состав:
- $1;
# Почему именно они:
- рабочих дней более 50%;
- работали в течении последних 30 дней;
§ recommendations.author.dismissed.title: Уволилось $1
§ recommendations.author.dismissed.description
или работало короткий промежуток времени.
# Состав:
- $1;
# Почему именно они:
- работали в нормальном ритме (видимо, это их основной репозиторий);
- за последний месяц не было ни одного коммита;
- отпуск обычно 14 дней (их отсутствие не похоже на отпуск);
§ recommendations.author.staff.title: Помогают $1
§ recommendations.author.staff.description
Люди другой специализации, которые что-либо коммитили.
# Состав:
- $1;
# Почему именно они:
- это не open-source проект;
- рабочих дней менее 15% от общего числа;
- изменяют примерно одни и те же файлы;
§ recommendations.author.projectType.openSource.title
Открытый проект
§ recommendations.author.projectType.openSource.description
пять дней в неделю тут не работают.
Проект может быть и закрытым, просто такой темп работы обычно у открытых библиотек на GitHub.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- у open-source библиотек рабочих дней обычно максимум 15..20%;
# Последствия
Для проектов, где работа не постоянна, нет смысла во многих показателях. Поэтому показатели без коммитов, скорости и т.п. будут скрыты.
Как правило, оценку таких проектов делают перед началом разработки своей закрытой версии. Самые интересные показатели в этом случае вероятная стоимость и суммарное время на разработку.
§ recommendations.author.projectType.easy.title
Слабая загрузка
§ recommendations.author.projectType.easy.description
слишком много дней без коммитов. Нужно понять почему команда не пишет код.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- загрузка считается слабой, если процент без коммитов от 5% до 20%;
# Возможные причины:
- фактически нет задач;
- задачи есть, но хорошо ложатся на текущую архитектуру;
- разработчиков отвлекают совещаниями;
- команда не работает;
# Варианты решения:
- обсудить проблему с командой;
- уменьшить гранулярность задач, чтобы за день можно было успеть сделать одну или две задачи;
- ввести ежедневные совещания, чтобы проверять движение задач по статусу;
- устроить сеансы парного программирования, чтобы убедиться, что разработчик может работать быстрее;
§ recommendations.author.manager.title
Обозначьте дедлайны
§ recommendations.author.manager.description
У любой задачи должен быть чёткий дедлайн.
Это позволит не затягивать её выполнение на несколько дней или недель.
# Какие показатели стоит проверить:
- количество дней на одну задачу, которое тратит работник;
- количество дней ожидания влития PR (страница статистики по PR);
§ recommendations.author.shorTalk.title
Проводите ежедневные совещания
§ recommendations.author.shorTalk.description
они помогают быть в курсе проекта.
Не растягивайте их отвлекаясь на постороние темы.
# На какие вопросы должен ответить сотрудник:
- что было сделано;
- что будет сделано;
- есть ли какие-либо проблемы;
# Следует обрывать монолог, если:
- начинают подробно описывать мелкие детали, которые не важны;
- уводят диалог в сторону, от первоначального плана;
# Почему это важно:
Часто сотрудник, который ничего не делает, старается уйти от ответа. Для этого он рассказывает кучу ненужных подробностей свой работы. Это позволяет усыпить внимание участников и растянуть время ответа. Создается ощущение что он чем-то занят, хотя по факту работы не было.
§ recommendations.author.ipr.title
Составьте план обучения
§ recommendations.author.ipr.description
на каждого сотрудника.
*Индивидуальный план обучения* это список целей и задач, которые помогают человеку развиваться в определенной области.
# Как составить план:
- составить матрицу компетенций;
- определить по каким компетенциям меньше всего знаний и опыта;
- узнать какие из этих компетенций интересны сотруднику;
- придумать 3..5 целей в рамках каждой такой компетенции на пол-года или год;
- каждый месяц пытаться сделать что-либо для достижения одной цели;
- каждый месяц напоминать об общем плане достижения этих целей;
# Нужен ли план руководителю?
Да, руководитель так же должен составить план на себя. Если нет вышестоящего руководителя, то он должен проверять сам себя.
# Почему это важно:
- сотрудники становятся более лояльны к компании;
- за теже деньги вы получаете более квалифицированные кадры;
§ recommendations.author.oneToOne.title
Проводите 1-1 каждый месяц
§ recommendations.author.oneToOne.description
это поможет выявить проблемы на ранней стадии.
*One-to-one* это регулярные личные встречи руководителя с подчиненным. На таких встречах обычно обсуждают всё, что важно для сотрудника, что его волнует, и то, чем он может поделиться с руководителем только наедине.
# Почему это важно:
- легко выяснить, кто из сотрудников перегружен, а у кого есть свободное время;
- можно предотвратить выгорание сотрудника;
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается мотивация и вовлеченность сотрудников;
§ recommendations.author.club.title
Ходите в бар
§ recommendations.author.club.description
один раз в месяц или два.
Это поможет выстроить неформальную коммуникацию в коллективе и сплотить команду, даже если общение будет сжатым.
# Почему это важно:
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается вовлеченность сотрудников;
§ recommendations.hour.onlyWork.title: Выходных тут нет
§ recommendations.hour.onlyWork.description: Вероятно, стоит уволить менеджера проекта.
§ recommendations.hour.weekends.title: Работа на выходных
§ recommendations.hour.weekends.description: Вероятно, стоит проверить менеджера проекта.
§ recommendations.hour.easy.title: Бывают проблемы
§ recommendations.hour.easy.description: Вероятно, бывают завалы и приходится работать на выходных.
§ recommendations.week.lazyDays.down.title: Стало меньше прогулов
§ recommendations.week.lazyDays.down.description: за последние три недели этот показатель упал
§ recommendations.week.lazyDays.up.title: Стало больше прогулов
§ recommendations.week.lazyDays.up.description: нет задач или нужен более жесткий контроль
§ recommendations.week.notWork.title: Стабильно не дорабатывает
§ recommendations.week.notWork.description: т.к. каждую неделю пишет код не 100% времени
§ recommendations.week.upWork.title: Стабильно перерабатывает
§ recommendations.week.upWork.description: т.к. каждую неделю пишет код в выходные дни
§ recommendations.week.task.up.title: Растёт производительность
§ recommendations.week.task.up.description: или задачи стали слишком мелкие. Нужно проверить. Если гранулярность та же - закрепить результат.
§ recommendations.week.task.lazyMaintainer.description: стабильный лидер по прогулам. Уволить?
§ recommendations.week.task.down.title: Падает производительность
§ recommendations.week.task.down.description
или задачи хуже разбивают. Нужно проверить. Если гранулярность та же - взять на контроль.
# Метод оценки:
- количество задач в день, над которыми работают, на протяжении последних трех недель стабильно падает.
# Возможные ошибки:
- задачи могли быть сложнее, чем казались;
- задачи могли иметь большой объём работы (нужно проверить количество изменений, падают они или нет за этот же период)
§ recommendations.type.everyHasOne.title: Не подписывают тип задачи
§ recommendations.type.everyHasOne.description: большинство типов задач делает один человек.
§ recommendations.type.oneMaintainer.title: Узкая специализация
§ recommendations.type.oneMaintainer.description
большинство задач одного типа делают одни и те же люди.
# Типы задач:
§ recommendations.type.common
# Возможно, это не так
Нужно убедиться, что остальные сотрудники верно подписывают коммиты.
Шаги, которые помогут это сделать:
- настроить пре-коммит проверку для commit message;
- объяснить команде, что нужно указывать тип;
- проверить в новых ветках, что сотрудники следуют правилу;
# Если это действительно так
Вы настроили проверки и убедились что один и тот же сотрудник, делает задачи одного и того же типа.
Почему это плохо:
- его увольнение остановит целую пачку процессов;
- уменьшается компетенция остальных членов команды;
- трудно верхнеуровнево понять его правки;
Как это исправить:
- распределять разные типы задач равномерно;
- менять область работы (тесты, документация, ошибки) между сотрудниками через спринт;
§ recommendations.type.fewTypes.title
Это локальный продукт
§ recommendations.type.fewTypes.description
для конкретного заказчика или проблемы.
# Какие признаки есть у «глобального» продукта:
- локализация;
- документация;
- большой обьем тестов;
- визуальная кастомизация;
- рефакторинг узких мест;
- и т.п.
# Почему этот продукт выглядит как «локальный»:
- у каждого «глобального» признака будет перевес по своему типу задач;
- чем больше «глобальных» признаков, тем больше вероятность «глобального» продукта;
В данном случае мы видим небольшое число типов, а следовательно, скорее всего есть недоработки, мешающие легко масштабировать продукт на мировой рынок и продавать его в других странах.
# Возможно, это не так
По типам файлов мы можем предположить тип программы (сайт, серверное приложение, 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 {};

82
src/ts/helpers/File.ts Normal file
View file

@ -0,0 +1,82 @@
import React from 'react';
import { ColumnTypesEnum, IColumn } from '../components/Table/interfaces/Column';
// import localization from './Localization';
export function downloadFile(file: Blob, fileName: string) {
const link = document.createElement('a');
link.href = URL.createObjectURL(file);
link.download = fileName;
document.body.append(link);
link.click();
link.remove();
setTimeout(() => URL.revokeObjectURL(link.href), 7000);
}
function getColumnsFromChildren(children: React.ReactNode) {
const columns = React.Children.map(children, (child: React.ReactNode) => {
if (!React.isValidElement(child)) return null;
const template = child?.props?.template || ColumnTypesEnum.STRING;
return {
...child.props as object,
template,
};
});
// @ts-ignore
const correctColumns = Array.from(columns)
.filter((column: IColumn) => column?.title);
return correctColumns;
}
function getTitles(columns: IColumn[]) {
return columns.map((column: IColumn) => (column.title || '').split('.').pop());
}
function getFormatter(columns: IColumn[]) {
return (item: any) => {
return columns.map((column: IColumn) => {
let value = column.properties
? item[column.properties]
: item;
if (column.formatter) {
value = column.formatter(value);
}
if (Array.isArray(value)) {
return value.length;
}
const type = typeof value;
if (type === 'object') {
return JSON.stringify(value);
}
if (type === 'string') {
return value.replace('.', ',');
}
return value;
});
};
}
export function downloadCsv(
list: Array<any>,
children: React.ReactNode,
name?: string,
) {
const columns = getColumnsFromChildren(children);
console.dir(columns);
const formatter = getFormatter(columns);
const csvFile = [
getTitles(columns).join(';'),
...list.map((item: any) => formatter(item).join(';')),
].join('\n');
const type = 'text/csv;charset=windows-1251;'; // utf-8;';
const file = new Blob([csvFile], { type });
const fileName = `${document.title} - ${name || ''}.csv`;
return downloadFile(file, fileName);
}

View file

@ -6,7 +6,6 @@ class Localization {
insertArguments(message: string, args?: any) { insertArguments(message: string, args?: any) {
if (!args) return message; if (!args) return message;
const list = Array.isArray(args) ? args : [args]; const list = Array.isArray(args) ? args : [args];
console.log(list);
list.forEach((text: any, index: number) => { list.forEach((text: any, index: number) => {
message = message.replace(`$${index + 1}`, text || '_'); message = message.replace(`$${index + 1}`, text || '_');
}); });

59
src/ts/helpers/RPC.ts Normal file
View file

@ -0,0 +1,59 @@
import IHashMap from 'ts/interfaces/HashMap';
function getParametersFromString(text: string): IHashMap<string> {
return Object.fromEntries((text || '')
.substring(1, Infinity)
.split('&')
.map((token: string) => token.split('=')));
}
function getParametersFromURL(): IHashMap<string> {
return {
...getParametersFromString(location.search),
...getParametersFromString(location.hash),
};
}
function loadJsDump(url: string, callback: Function) {
const script = document.createElement('script');
script.src = url;
script.async = true; // @ts-ignore
script.onload = callback; // @ts-ignore
script.onerror = callback;
document.body.appendChild(script);
}
function loadCssFile(url: string) {
const node = document.createElement('link');
node.setAttribute('rel', 'stylesheet');
node.setAttribute('href', url);
document.body.appendChild(node);
}
export let applicationHasCustom = {
theme: false,
title: false,
};
export default function applyUrlCommands(callback: Function) {
const parameters: IHashMap<string> = getParametersFromURL();
const cssUrl = parameters.style || parameters.theme;
if (cssUrl) {
loadCssFile(cssUrl);
applicationHasCustom.theme = true;
}
const title = parameters.title;
if (title) {
document.title = decodeURIComponent(title);
applicationHasCustom.title = true;
}
const jsUrl = parameters.dump || parameters.log;
if (jsUrl) {
loadJsDump(jsUrl, callback);
} else {
callback();
}
}

View file

@ -56,6 +56,5 @@ export default function getTitle(dataGrip: any, commits: any) {
const formattedTask = task.split('-').shift().toUpperCase() || ''; const formattedTask = task.split('-').shift().toUpperCase() || '';
const formattedAuthor = author.split(' ').shift() || ''; const formattedAuthor = author.split(' ').shift() || '';
const title = `${type} ${formattedTask} (${year}, ${formattedAuthor})`; return `${type} ${formattedTask} (${year}, ${formattedAuthor})`;
return `${title}. Git статистика`;
} }

View file

@ -59,7 +59,7 @@ export default function getAchievementByAuthor(author: string) {
if (getList?.some((commit: ICommit) => commit.taskNumber === '300')) list.push('taskNumber300'); if (getList?.some((commit: ICommit) => commit.taskNumber === '300')) list.push('taskNumber300');
return list.reduce((acc: any, type: string) => { return list.reduce((acc: any, type: string) => {
const index = ALL_ACHIEVEMENTS[type][2]; const index = ALL_ACHIEVEMENTS[type] - 1;
acc[index].push(type); acc[index].push(type);
return acc; return acc;
}, [[], [], []]); }, [[], [], []]);

View file

@ -11,20 +11,21 @@ interface ITableOfContents {
function TableOfContents({ titles }: ITableOfContents) { function TableOfContents({ titles }: ITableOfContents) {
const items = (titles || []).map((title) => ( const items = (titles || []).map((title) => (
<li <a
key={title} key={title}
className={style.table_of_contents_item} className={style.table_of_contents_item}
href={`#${title}`}
> >
{localization.get(title || '')} {localization.get(title || '')}
</li> </a>
)); ));
return ( return (
<> <>
<Title title="page.print.tableOfContents" /> <Title title="page.print.tableOfContents" />
<ul className={style.table_of_contents}> <nav className={style.table_of_contents}>
{items} {items}
</ul> </nav>
</> </>
); );
} }

View file

@ -1,13 +1,17 @@
@import '../../../../styles/variables'; @import '../../../../styles/variables';
.table_of_contents { .table_of_contents {
display: block;
margin-bottom: var(--space-xxl); margin-bottom: var(--space-xxl);
&_item { &_item {
position: relative; position: relative;
display: block;
padding: 0 0 0 22px; padding: 0 0 0 22px;
margin: var(--space-m) 0; margin: var(--space-m) 0;
list-style-type: none; list-style-type: none;
text-decoration: none;
color: var(--color-black);
&:before { &:before {
position: absolute; position: absolute;

View file

@ -23,7 +23,7 @@ interface IAchievementBlockProps {
} }
function AchievementBlock({ title, achievements }: IAchievementBlockProps) { function AchievementBlock({ title, achievements }: IAchievementBlockProps) {
if (!achievements.length) return null; if (!achievements?.length) return null;
return ( return (
<> <>
<Description text={`# ${localization.get(title)}`}/> <Description text={`# ${localization.get(title)}`}/>

View file

@ -21,7 +21,7 @@ interface IAchievementBlockProps {
} }
function AchievementBlock({ title, achievements }: IAchievementBlockProps) { function AchievementBlock({ title, achievements }: IAchievementBlockProps) {
if (!achievements.length) return null; if (!achievements?.length) return null;
return ( return (
<> <>
<Description text={`# ${title}`}/> <Description text={`# ${title}`}/>

View file

@ -6,6 +6,7 @@ import Select from 'ts/components/UiKit/components/Select';
import PageBox from 'ts/components/Page/Box'; import PageBox from 'ts/components/Page/Box';
import Title from 'ts/components/Title'; import Title from 'ts/components/Title';
import localization from 'ts/helpers/Localization'; import localization from 'ts/helpers/Localization';
import { applicationHasCustom } from 'ts/helpers/RPC';
const Common = observer((): React.ReactElement | null => { const Common = observer((): React.ReactElement | null => {
const [title, setTitle] = useState<string>(document.title); const [title, setTitle] = useState<string>(document.title);
@ -22,6 +23,7 @@ const Common = observer((): React.ReactElement | null => {
onChange={(value: string) => { onChange={(value: string) => {
setTitle(value); setTitle(value);
document.title = value || 'Git статистика'; document.title = value || 'Git статистика';
applicationHasCustom.title = true;
}} }}
/> />
<Select <Select

View file

@ -29,9 +29,10 @@ import Description from 'ts/components/Description';
interface IAuthorViewProps { interface IAuthorViewProps {
response?: IPagination<any>; response?: IPagination<any>;
updateSort?: Function; updateSort?: Function;
mode?: string;
} }
function AuthorView({ response, updateSort }: IAuthorViewProps) { function AuthorView({ response, updateSort, mode }: IAuthorViewProps) {
if (!response) return null; if (!response) return null;
const textWork = localization.get('page.team.author.worked'); const textWork = localization.get('page.team.author.worked');
@ -46,6 +47,8 @@ function AuthorView({ response, updateSort }: IAuthorViewProps) {
rows={response.content} rows={response.content}
sort={response.sort} sort={response.sort}
updateSort={updateSort} updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
> >
<Column <Column
isFixed isFixed
@ -163,17 +166,15 @@ const Author = observer(({
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<Title title="page.team.author.title"/> <Title title="page.team.author.title"/>
<PageWrapper template="table"> <DataLoader
<DataLoader to="response"
to="response" loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ content: rows, pagination, sort, mode,
content: rows, pagination, sort, mode, })}
})} >
> <AuthorView mode={mode} />
<AuthorView /> <Pagination />
<Pagination /> </DataLoader>
</DataLoader>
</PageWrapper>
<PageWrapper> <PageWrapper>
<PageColumn> <PageColumn>
<Description <Description

View file

@ -39,6 +39,8 @@ function AllPR({
rows={response.content} rows={response.content}
sort={response.sort} sort={response.sort}
updateSort={updateSort} updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 2 : undefined}
> >
{mode === 'print' ? ( {mode === 'print' ? (
<Column <Column

View file

@ -22,9 +22,10 @@ const order = Object.values(TITLES);
interface IAuthorsProps { interface IAuthorsProps {
response?: IPagination<any>; response?: IPagination<any>;
updateSort?: Function; updateSort?: Function;
mode?: string;
} }
function Authors({ response, updateSort }: IAuthorsProps) { function Authors({ response, updateSort, mode }: IAuthorsProps) {
if (!response) return null; if (!response) return null;
const timeChart = getOptions({ order, limit: 3 }); const timeChart = getOptions({ order, limit: 3 });
@ -42,6 +43,8 @@ function Authors({ response, updateSort }: IAuthorsProps) {
rows={response.content} rows={response.content}
sort={response.sort} sort={response.sort}
updateSort={updateSort} updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
> >
<Column <Column
isSortable isSortable

View file

@ -34,9 +34,7 @@ const PR = observer(({
return ( return (
<> <>
<Title title="page.team.pr.oneTaskDays"/> <Title title="page.team.pr.oneTaskDays"/>
<PageWrapper template="table"> <Total/>
<Total/>
</PageWrapper>
<PageWrapper> <PageWrapper>
<PageColumn> <PageColumn>
@ -57,17 +55,15 @@ const PR = observer(({
<br/> <br/>
<Title title="page.team.pr.statByAuthors"/> <Title title="page.team.pr.statByAuthors"/>
<PageWrapper template="table"> <DataLoader
<DataLoader to="response"
to="response" loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ content: authorsStat, pagination, sort, mode,
content: authorsStat, pagination, sort, mode, })}
})} >
> <Authors mode={mode}/>
<Authors/> <Pagination/>
<Pagination/> </DataLoader>
</DataLoader>
</PageWrapper>
<PageBreak/> <PageBreak/>
<Title title="page.team.pr.longDelay"/> <Title title="page.team.pr.longDelay"/>

View file

@ -6,7 +6,6 @@ import { getMoney } from 'ts/helpers/formatter';
import dataGripStore from 'ts/store/DataGrip'; import dataGripStore from 'ts/store/DataGrip';
import ICommonPageProps from 'ts/components/Page/interfaces/CommonPageProps'; import ICommonPageProps from 'ts/components/Page/interfaces/CommonPageProps';
import PageWrapper from 'ts/components/Page/wrapper';
import DataLoader from 'ts/components/DataLoader'; import DataLoader from 'ts/components/DataLoader';
import Pagination from 'ts/components/DataLoader/components/Pagination'; import Pagination from 'ts/components/DataLoader/components/Pagination';
import getFakeLoader from 'ts/components/DataLoader/helpers/formatter'; import getFakeLoader from 'ts/components/DataLoader/helpers/formatter';
@ -22,15 +21,24 @@ import RecommendationsWrapper from 'ts/components/Recommendations/wrapper';
interface IScopeViewProps { interface IScopeViewProps {
response?: IPagination<any>; response?: IPagination<any>;
updateSort?: Function;
mode?: string;
} }
function ScopeView({ response }: IScopeViewProps) { function ScopeView({ response, updateSort, mode }: IScopeViewProps) {
if (!response) return null; if (!response) return null;
const typeChart = getOptions({ order: dataGripStore.dataGrip.type.list }); const typeChart = getOptions({ order: dataGripStore.dataGrip.type.list });
const authorChart = getOptions({ order: dataGripStore.dataGrip.author.list }); const authorChart = getOptions({ order: dataGripStore.dataGrip.author.list });
return ( return (
<DataView rows={response.content}> <DataView
rows={response.content}
sort={response.sort}
updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
>
<Column <Column
isFixed isFixed
template={ColumnTypesEnum.STRING} template={ColumnTypesEnum.STRING}
@ -118,17 +126,15 @@ const Scope = observer(({
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<Title title="page.team.scope.title"/> <Title title="page.team.scope.title"/>
<PageWrapper template="table"> <DataLoader
<DataLoader to="response"
to="response" loader={(pagination?: IPaginationRequest) => getFakeLoader({
loader={(pagination?: IPaginationRequest) => getFakeLoader({ content: rows, pagination, mode,
content: rows, pagination, mode, })}
})} >
> <ScopeView mode={mode} />
<ScopeView /> <Pagination />
<Pagination /> </DataLoader>
</DataLoader>
</PageWrapper>
</> </>
); );
}); });

View file

@ -11,7 +11,7 @@ import Races from 'ts/components/Races';
import Tv100And1 from 'ts/components/Tv100And1'; import Tv100And1 from 'ts/components/Tv100And1';
import ACHIEVEMENT_TYPE from 'ts/helpers/achievement/constants/type'; // import ACHIEVEMENT_TYPE from 'ts/helpers/achievement/constants/type';
import getAchievementByAuthor from 'ts/helpers/achievement/byAuthor'; import getAchievementByAuthor from 'ts/helpers/achievement/byAuthor';
import Description from 'ts/components/Description'; import Description from 'ts/components/Description';
import DataView from 'ts/components/DataView'; import DataView from 'ts/components/DataView';
@ -51,16 +51,17 @@ const Top = observer((): React.ReactElement => {
const authors = dataGripStore.dataGrip.author.statistic.map((statistic: any) => { const authors = dataGripStore.dataGrip.author.statistic.map((statistic: any) => {
const achievements = getAchievementByAuthor(statistic.author); const achievements = getAchievementByAuthor(statistic.author);
console.dir(achievements);
const from = getDate(statistic.firstCommit.date); const from = getDate(statistic.firstCommit.date);
const to = getDate(statistic.lastCommit.date); const to = getDate(statistic.lastCommit.date);
const achievementsList = [ const achievementsList = [
...achievements[ACHIEVEMENT_TYPE.GOOD], // ...achievements[ACHIEVEMENT_TYPE.GOOD],
...achievements[ACHIEVEMENT_TYPE.NORMAL], // ...achievements[ACHIEVEMENT_TYPE.NORMAL],
...achievements[ACHIEVEMENT_TYPE.BAD], // ...achievements[ACHIEVEMENT_TYPE.BAD],
].map((type: string) => ( ].map((code: string) => (
<Achievement <Achievement
key={type} key={code}
type={type} code={code}
/> />
)); ));

View file

@ -27,9 +27,10 @@ import localization from 'ts/helpers/Localization';
interface ITypeViewProps { interface ITypeViewProps {
response?: IPagination<any>; response?: IPagination<any>;
updateSort?: Function; updateSort?: Function;
mode?: string;
} }
function TypeView({ response, updateSort }: ITypeViewProps) { function TypeView({ response, updateSort, mode }: ITypeViewProps) {
if (!response) return null; if (!response) return null;
const taskChart = getOptions({ max: getMax(response, 'tasks'), suffix: 'page.team.type.tasksSmall' }); const taskChart = getOptions({ max: getMax(response, 'tasks'), suffix: 'page.team.type.tasksSmall' });
@ -41,6 +42,8 @@ function TypeView({ response, updateSort }: ITypeViewProps) {
rows={response.content} rows={response.content}
sort={response.sort} sort={response.sort}
updateSort={updateSort} updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
> >
<Column <Column
isFixed isFixed
@ -123,17 +126,15 @@ const Type = observer(({
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<Title title="page.team.type.title"/> <Title title="page.team.type.title"/>
<PageWrapper template="table"> <DataLoader
<DataLoader to="response"
to="response" loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ content: rows, pagination, sort, mode,
content: rows, pagination, sort, mode, })}
})} >
> <TypeView mode={mode} />
<TypeView /> <Pagination />
<Pagination /> </DataLoader>
</DataLoader>
</PageWrapper>
<PageWrapper> <PageWrapper>
<Description <Description
text={localization.get('page.team.type.description')} text={localization.get('page.team.type.description')}

View file

@ -8,7 +8,7 @@ import { getShortDateRange } from 'ts/helpers/formatter';
import dataGripStore from 'ts/store/DataGrip'; import dataGripStore from 'ts/store/DataGrip';
import ICommonPageProps from 'ts/components/Page/interfaces/CommonPageProps'; import ICommonPageProps from 'ts/components/Page/interfaces/CommonPageProps';
import PageWrapper from 'ts/components/Page/wrapper'; import Title from 'ts/components/Title';
import DataLoader from 'ts/components/DataLoader'; import DataLoader from 'ts/components/DataLoader';
import Pagination from 'ts/components/DataLoader/components/Pagination'; import Pagination from 'ts/components/DataLoader/components/Pagination';
import getFakeLoader from 'ts/components/DataLoader/helpers/formatter'; import getFakeLoader from 'ts/components/DataLoader/helpers/formatter';
@ -25,9 +25,10 @@ import { getMax } from 'ts/pages/Common/helpers/getMax';
interface IWeekViewProps { interface IWeekViewProps {
response?: IPagination<any>; response?: IPagination<any>;
updateSort?: Function; updateSort?: Function;
mode?: string;
} }
function WeekView({ response, updateSort }: IWeekViewProps) { function WeekView({ response, updateSort, mode }: IWeekViewProps) {
if (!response) return null; if (!response) return null;
const tasksChart = getOptions({ max: getMax(response, 'tasks'), order: dataGripStore.dataGrip.type.list, suffix: 'page.team.week.tasks' }); const tasksChart = getOptions({ max: getMax(response, 'tasks'), order: dataGripStore.dataGrip.type.list, suffix: 'page.team.week.tasks' });
@ -48,6 +49,8 @@ function WeekView({ response, updateSort }: IWeekViewProps) {
rows={response.content} rows={response.content}
sort={response.sort} sort={response.sort}
updateSort={updateSort} updateSort={updateSort}
type={mode === 'print' ? 'cards' : undefined}
columnCount={mode === 'print' ? 3 : undefined}
> >
<Column <Column
isFixed isFixed
@ -161,17 +164,18 @@ const Week = observer(({
{mode !== 'print' && ( {mode !== 'print' && (
<RecommendationsWrapper recommendations={recommendations} /> <RecommendationsWrapper recommendations={recommendations} />
)} )}
<PageWrapper template="table"> {mode === 'print' && (
<DataLoader <Title title="page.team.week.title"/>
to="response" )}
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ <DataLoader
content: rows, pagination, sort, to="response"
})} loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
> content: rows, pagination, sort,
<WeekView /> })}
{mode !== 'print' && <Pagination />} >
</DataLoader> <WeekView mode={mode} />
</PageWrapper> {mode !== 'print' && <Pagination />}
</DataLoader>
</> </>
); );
}); });

View file

@ -8,6 +8,7 @@ import getFileTreeWithStatistic from 'ts/helpers/DataGrip/helpers/tree';
import Parser from 'ts/helpers/Parser'; import Parser from 'ts/helpers/Parser';
import { setDefaultValues } from 'ts/pages/Settings/helpers/getEmptySettings'; import { setDefaultValues } from 'ts/pages/Settings/helpers/getEmptySettings';
import getTitle from 'ts/helpers/Title'; import getTitle from 'ts/helpers/Title';
import { applicationHasCustom } from 'ts/helpers/RPC';
import settingsStore from './Settings'; import settingsStore from './Settings';
@ -70,7 +71,10 @@ class DataGripStore implements IDataGripStore {
this.dataGrip = dataGrip; this.dataGrip = dataGrip;
console.dir(this.dataGrip); console.dir(this.dataGrip);
document.title = getTitle(this.dataGrip, this.commits); console.dir(getTitle(this.dataGrip, this.commits));
if (!applicationHasCustom.title) {
document.title = getTitle(this.dataGrip, this.commits);
}
} }
updateChars() { // todo: remove, never use updateChars() { // todo: remove, never use

View file

@ -0,0 +1,94 @@
export default `
§ achievements.commitsAfter1500.title: Сова
§ achievements.commitsAfter1500.description: 70% коммитов после 15:00
§ achievements.commitsBefore1500.title: Ранняя пташка
§ achievements.commitsBefore1500.description: 70% коммитов до обеда
§ achievements.workEveryTime.title: Раб божий
§ achievements.workEveryTime.description: есть коммит на каждый час суток
§ achievements.workNotWork.title: Стрельба холостыми
§ achievements.workNotWork.description: коммиты есть, а закрытых задач нет
§ achievements.userNotWork.title: Залётный
§ achievements.userNotWork.description: это не его основной проект
§ achievements.userIsDied.title: Мёртвая душа
§ achievements.userIsDied.description: работал, но уволился
§ achievements.lessTasks.title: Зашел и вышел
§ achievements.lessTasks.description: меньше всего закрытых задач
§ achievements.moreTasks.title: Батя грит малаца
§ achievements.moreTasks.description: больше всего закрытых задач
§ achievements.everyMessageLong.title: Мастер красноречия
§ achievements.everyMessageLong.description: стабильно самые длинные подписи коммитов
§ achievements.everyMessageShort.title: Болтун находка для шпиона
§ achievements.everyMessageShort.description: стабильно, самые короткие подписи коммитов
§ achievements.shortestName.title: Размер не главное
§ achievements.shortestName.description: самое короткое имя
§ achievements.longestName.title: Азим Азиз Иль Ам Кадир Имран II
§ achievements.longestName.description: самое длинное имя
§ achievements.moreCommits.title: Мастер бекапов
§ achievements.moreCommits.description: больше всего коммитов
§ achievements.lessCommits.title: Редко но метко
§ achievements.lessCommits.description: меньше всего коммитов
§ achievements.oneCommitOneTask.title: Точно в цель
§ achievements.oneCommitOneTask.description: в среднем один коммит на задачу
§ achievements.moreLazyDays.title: Мысленно я с вами
§ achievements.moreLazyDays.description: больше всего дней без коммитов
§ achievements.lessLazyDays.title: Папа Карло
§ achievements.lessLazyDays.description: меньше всего дней без коммитов
§ achievements.zeroLazyDays.title: Ни единого разрыва
§ achievements.zeroLazyDays.description: ни одного дня без коммитов
§ achievements.moreWorkDays.title: Ценный работник
§ achievements.moreWorkDays.description: больше всего рабочих дней
§ achievements.moreScopes.title: Стартапер
§ achievements.moreScopes.description: сделал больше всего фичей
§ achievements.lessScopes.title: Щегол
§ achievements.lessScopes.description: сделал меньше всего фичей
§ achievements.moreDaysForTask.title: Улитка на склоне
§ achievements.moreDaysForTask.description: работа по задачам идёт медленнее чем у остальных
§ achievements.more2DaysForTask.title: Cо слоу
§ achievements.more2DaysForTask.description: больше двух дней на задачу
§ achievements.moreDaysInProject.title: Старожил
§ achievements.moreDaysInProject.description: больше всего дней на проекте
§ achievements.lessDaysInProject.title: А это кто?
§ achievements.lessDaysInProject.description: меньше всего дней на проекте
§ achievements.more90DaysInProject.title: Добро пожаловать
§ achievements.more90DaysInProject.description: не уволили на испытательном
§ achievements.lessDaysForTask.title: Скорострел
§ achievements.lessDaysForTask.description: одна задача занимает меньше дня
§ achievements.adam.title: Адам
§ achievements.adam.description: первый стабильный сотрудник на проекте
§ achievements.more666DaysInProject.title: Чёрт
§ achievements.more666DaysInProject.description: отработал 666 дней на проекте
§ achievements.more777DaysInProject.title: Азино 3 топора
§ achievements.more777DaysInProject.description: отработал 777 дней на проекте
§ achievements.moreRefactoring.title: Выпускающий редактор
§ achievements.moreRefactoring.description: сделал больше всех меток «рефакторинг»
§ achievements.longestMessage.title: А разговоров то было...
§ achievements.longestMessage.description: самая длинная подпись коммита за все время
§ achievements.moreTasksInDay.title: Спиди-гонщик
§ achievements.moreTasksInDay.description: рекорд по количеству закрытых задач в день
§ achievements.hasCommitFrom0to7.title: Ночной дозор
§ achievements.hasCommitFrom0to7.description: есть коммит на каждый час ночи
§ achievements.noCommitOnDay.title: Технический перерыв
§ achievements.noCommitOnDay.description: есть определенный час и день в рабочее время в который никогда не комитит
§ achievements.hasCommitEveryTime.title: Умер на работе
§ achievements.hasCommitEveryTime.description: есть коммит на час каждого дня (включая выходные)
§ achievements.commitsAfter1800.title: Делу время
§ achievements.commitsAfter1800.description: нет ни одного коммита после 18:00
§ achievements.more1488DaysInProject.title: им. Максима Марцинкевича
§ achievements.more1488DaysInProject.description: отработал 1488 дней на проекте
§ achievements.taskNumber300.title: Знаком с трактористом
§ achievements.taskNumber300.description: первый взял в работу задачу с номером 300
§ achievements.moreFix.title: Bug hunter
§ achievements.moreFix.description: больше всего закрытых багов
§ achievements.lessWorkDays.title: Дальше без меня
§ achievements.lessWorkDays.description: меньше всего рабочих дней
§ achievements.moreCreateCode.title: Созидатель
§ achievements.moreCreateCode.description: склонен больше остальных добавлять код
§ achievements.moreRemoveCode.title: Разрушитель
§ achievements.moreRemoveCode.description: склонен больше остальных удалять код
§ achievements.moreChangeCode.title: Реформатор
§ achievements.moreChangeCode.description: склонен больше остальных изменять код
§ achievements.moreStyle.title: Полиция моды
§ achievements.moreStyle.description: склонен больше остальных изменять CSS
§ achievements.moreOnHoliday.title: Нет жизни
§ achievements.moreOnHoliday.description: относительно много коммитов в нерабочее время
`;

View file

@ -0,0 +1,28 @@
export default `
§ 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: Настройки сохранены
`;

View file

@ -0,0 +1,15 @@
import achievements from './achievements';
import common from './common';
import navigation from './navigation';
import recommendations from './recommendations';
import settings from './settings';
import pages from './pages';
export default [
achievements,
common,
navigation,
recommendations,
settings,
pages,
].join('');

View file

@ -0,0 +1,37 @@
export default `
§ sidebar.switch.team: Team
§ sidebar.switch.person: Employee
§ sidebar.buttons.settings: Settings
§ sidebar.buttons.print: Print
§ sidebar.filters.all: all time
§ sidebar.filters.year: year
§ sidebar.filters.halfYear: half year
§ sidebar.filters.month: month
§ sidebar.filters.week: week
§ sidebar.team.total: Common info
§ sidebar.team.scope: Features
§ sidebar.team.author: Employees
§ sidebar.team.type: Task types
§ sidebar.team.pr: Pull requests
§ sidebar.team.day: By day
§ sidebar.team.week: By week
§ sidebar.team.month: By month
§ sidebar.team.tree: Files
§ sidebar.team.hours: Расписание
§ sidebar.team.commits: All commits
§ sidebar.team.changes: All changes
§ sidebar.team.words: Popular words
§ sidebar.team.top: Викторина
§ sidebar.team.settings: Settings
§ sidebar.person.total: Common info
§ sidebar.person.money: Work cost
§ sidebar.person.speed: Speed
§ sidebar.person.day: By day
§ sidebar.person.week: By week
§ sidebar.person.month: By month
§ sidebar.person.hours: Расписание
§ sidebar.person.commits: All commits
§ sidebar.person.changes: All changes
§ sidebar.person.words: Popular words
§ sidebar.person.settings: Settings
`;

View file

@ -0,0 +1,203 @@
export default `
§ page.welcome.step1: Выполните команду в корне вашего проекта
§ page.welcome.step3: Перетащите
§ page.welcome.step4: файл log.txt на эту страницу
§ page.welcome.description1: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл
§ 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.print.modal.title: Что распечатываем?
§ page.print.modal.page: Текущую страницу
§ page.print.modal.type: Текущий раздел
§ page.print.modal.all: Всю статистику
§ page.print.modal.cancel: Отмена
§ page.print.tableOfContents: Оглавление
§ page.print.title: Отчёт по git-репозиторию «$1»
§ page.print.description: Данные для отчёта были получены из истории коммитов.
§ page.team.author.title: Статистика по сотрудникам
§ page.team.author.description1: *Часть статистики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помощник» не считается*, т.к. это эпизодическая роль в проекте. Предполагаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы.
§ page.team.author.description2: *Сортировка по умолчанию* это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники).
§ page.team.author.types: Тип работ
§ page.team.author.commits: Коммитов
§ page.team.author.commitsSmall: коммитов
§ page.team.author.tasks: Задач
§ page.team.author.tasksSmall: задач
§ page.team.author.workedLosses: Дни с коммитами и без
§ page.team.author.worked: работа
§ page.team.author.losses: дни без коммитов
§ page.team.author.days: дней
§ page.team.author.daysForTask: Дней на задачу
§ page.team.author.scopes: Фич
§ page.team.author.moneyAll: Получил
§ page.team.author.moneyWorked: Отработал
§ page.team.author.moneyLosses: Переплата
§ page.team.hours.title: Распределение коммитов в течении каждого дня недели
§ page.team.month.title: Календарь работы по проекту
§ page.team.scope.title: Статистика по фичам
§ page.team.scope.scope: Фича
§ page.team.scope.days: Раб. дней
§ page.team.scope.authorsDays: Человеко-дней
§ page.team.scope.tasks: Задач
§ page.team.scope.commits: Коммитов
§ page.team.scope.commitsSmall: коммитов
§ page.team.scope.types: Тип работ
§ page.team.scope.authors: Персональный вклад
§ page.team.scope.cost: Стоимость
§ page.team.type.title: Статистика по типам задач
§ page.team.type.description: *Персональный вклад* считается по количеству коммитов, а не объему измененных строк или файлов. Поэтому следует так же смотреть раздел «Анализ файлов», чтобы оценить масштаб изменений.
§ page.team.type.type: Тип работы
§ page.team.type.tasks: Задач
§ page.team.type.tasksSmall: задач
§ page.team.type.days: Дней
§ page.team.type.daysSmall: дней
§ page.team.type.authorsDays: Человеко-дней
§ page.team.type.commits: Коммитов
§ page.team.type.authors: Персональный вклад
§ page.team.total.titleA: Объём работ
§ page.team.total.titleB: Стоимость
§ page.team.total.daysWorked.title: человеко-дней
§ page.team.total.daysWorked.description: Учтены только дни, в которые делались коммиты
§ page.team.total.commits.title: коммитов
§ page.team.total.commits.description: Удалённые ветки не считаются
§ page.team.total.daysLosses.title: дней без коммитов
§ page.team.total.daysLosses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.team.total.employment.title: работает / уволилось
§ page.team.total.employment.description: Если сотрудник в течении месяца не сделал ни одного коммита, он считается уволенным
§ page.team.total.moneyAll.title: общая
§ page.team.total.moneyAll.description: Суммарные затраты на зп
§ page.team.total.moneyWorked.title: фактическая
§ page.team.total.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.team.total.moneyLosses.title: возможная переплата
§ page.team.total.moneyLosses.description: Оплаченные рабочие дни, когда коммитов не было
§ page.team.total.weekendPayment.title: работа на выходных
§ page.team.total.weekendPayment.description: Суммарная переплата за работу в выходные дни
§ page.team.total.workSpeed.title: задач в день
§ page.team.total.workSpeed.description: Средняя скорость работы команды при текущем составе сотрудников
§ page.team.total.moneySpeed.title: в месяц
§ page.team.total.moneySpeed.description: Прогнозируемая сумма выплаты на зп при текущем составе сотрудников без учета налогов и сопутствующих затрат
§ page.team.total.description1: *Человеко-дни* это работа одного сотрудника в течение одного рабочего дня. Например, за один календарный день, команда из трех сотрудников выдает объем работы в три человеко-дня.
§ page.team.total.description2: *Днями прогулов* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют.
§ page.team.total.description3: Карточка *работает и уволилось* показывает фактический состав сотрудников, которые постоянно участвуют в работе. Кроме этого, есть «помощники» это сотрудники, как правило другой специализации, которые могут иногда делать коммиты в проект.
§ page.team.total.description4: *Переплатой* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют. Именно поэтому переплата + фактическая стоимость != общей. В общей стоимости заложена оплата выходных, государственных праздников и отпусков.
§ page.team.total.description5: *Работой на выходных* считается по коэффициенту х2 от оплаты обычного дня. Выше отображена именно переплата (х1), т.к. сам факт переработки в данном контексте не интересен. Мы не смотрим скорость сжигания бюджета. Мы смотрим переплату при увеличении скорости работы.
§ page.team.tree.title: Дерево проекта с учётом выбранных фильтров
§ page.team.tree.filters.author: Сотрудник
§ page.team.tree.filters.commits: Количество коммитов
§ page.team.tree.filters.help: Минимальное количество коммитов, которое сделал сотрудник в файле
§ page.team.tree.filters.all: Все сотрудники
§ page.team.tree.add: Кто добавлял
§ page.team.tree.change: Кто менял
§ page.team.tree.remove: Кто удалял
§ page.team.tree.line: строк
§ page.team.tree.lineAdd: добавили
§ page.team.tree.lineRemove: изменили
§ page.team.week.title: Статистика по неделям
§ page.team.week.date: Дата
§ page.team.week.numberTasks: Количество задач
§ page.team.week.people: Количество человек
§ page.team.week.line: Изменение строк
§ page.team.week.days: Дни с коммитами и без
§ page.team.week.lossesDetails: Кто не коммитил
§ page.team.week.add: добавили
§ page.team.week.change: изменили
§ page.team.week.remove: удалили
§ page.team.week.hasCommits: были коммиты
§ 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: Основные характеристики
§ 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.description: Учтены только дни, в которые делались коммиты
§ page.person.business.tasks.title: задач
§ page.person.business.tasks.description: Если коммиты правильно подписаны
§ page.person.business.losses.title: дней без коммитов
§ page.person.business.losses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.person.business.commits.title: коммитов
§ page.person.business.commits.description: Удалённые ветки не считаются
§ page.person.business.time.description: Время от первого, до последнего коммита (в том числе, нерабочие дни)
§ page.person.business.time.title: Дней на проекте:
§ page.person.business.time.dismissed: (уволен)
§ page.person.business.time.staff: (не в команде)
§ page.person.business.achievements: Достижения
§ page.person.changes.title: Достижения
§ page.person.changes.description:
При некоторых видах форматирования git отмечает строки как «удалённые» и «добавленные»,
хотя на самом деле они были «изменены». Поэтому, если вы провели большой рефакторинг,
git может показать малое количество изменений в статистике, а фактический результат
будет отмечен, как скачок «удаленных» и «добавленных» строк.
§ page.person.changes.description: Список коммитов и количество изменений в них за этот день:
§ page.person.commits.title: Список коммитов:
§ page.person.money.title.total: За всё время
§ page.person.money.title.middle: Средняя стоимость
§ page.person.money.moneyAll.title: получил
§ page.person.money.moneyAll.description: Предполагаемая сумма зп с проекта (см. настройки)
§ page.person.money.moneyWorked.title: отработал
§ page.person.money.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.person.money.moneyLosses.title: возможная переплата
§ page.person.money.moneyLosses.description: Дни без коммитов умноженные на среднюю зп
§ page.person.money.tasks.title: задача
§ page.person.money.tasks.description: Количество закрытых задач к стоимости дня
§ page.person.money.commits.title: коммит
§ page.person.money.commits.description: Количество коммитов к стоимости рабочего дня
§ page.person.speed.task: Одна задача в среднем это
§ page.person.speed.max: Максимальная скорость в день
§ page.person.speed.days.title: дней
§ page.person.speed.days.description: Имеются ввиду рабочие дни, если коммиты правильно подписаны
§ page.person.speed.commits.title: коммитов
§ page.person.speed.commits.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.line.title: строк кода
§ page.person.speed.line.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.tasks.title: задач
§ page.person.speed.tasks.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.speed.maxCommits.title: коммитов
§ page.person.speed.maxCommits.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.hours.title: Распределение коммитов в течении каждого дня недели
§ page.person.week.date: Дата
§ page.person.week.tasks: Количество задач
§ page.person.week.workDays: Дни с коммитами
§ page.person.week.taskInDay: Задач в день
§ page.person.week.days: дней
§ page.person.week.workDay: будни
§ page.person.week.weekends: выходные
`;

View file

@ -0,0 +1,506 @@
export default `
§ recommendations.title
Рекомендации и факты
§ recommendations.timestamp.firstCommit.description
сделал первый коммит
День недели: $1
§ recommendations.timestamp.lastCommit.description
сделал последний коммит
День недели: $1
§ recommendations.timestamp.common.title: $1 дней
§ recommendations.timestamp.allDays.description: от первого до последнего коммита (включая выходные и праздники).
§ recommendations.timestamp.lossesDays.description: без коммитов, даже с учётом выходных, отпуска и государственных праздников.
§ recommendations.timestamp.weekendDays.description
работы на выходных
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- сотрудники быстрее выгорают;
§ recommendations.timestamp.regularWeekendWord.title: Регулярные переработки
§ recommendations.timestamp.sometimeWeekendWord.title: Бывают переработки
§ recommendations.timestamp.weekendWord.description
Вероятно, стоит сменить менеджера проекта, аналитика и архитектора.
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- качество продукта, как правило, получается низкое;
- часть сотрудников увольняется;
- из-за спешки появляются новые ошибки;
# Скорее всего:
- неверно оценили сроки в самом начале;
- тех. задание отсутствует;
- слабая аналитика;
- слабая архитектура (архитектора не нанимали, а команда состоит из мидл разработчиков);
- сначала начали писать код, потом проектировать;
- нет нормальных процессов, чтобы понять ошибки;
§ recommendations.timestamp.neverWeekendWord.title: Обычно без переработок
§ recommendations.timestamp.neverWeekendWord.description
Но иногда бывают.
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- сотрудники быстрее выгорают;
§ recommendations.scope.parallelism.not.title
Нет параллельных работ
§ recommendations.scope.parallelism.not.description
любую фичу в один момент времени делает один человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат меньше 1.3 считаем, что параллельных работ в рамках большинства фичей обычно нет;
# Почему это плохо:
- повышается bus factor;
- сотрудники медленнее развиваются;
- трудно качественно проверить работу сотрудника;
# Почему это хорошо:
- появляются эксперты, которые очень глубоко погружены в предметную область и могут предложить более качественные решения;
- скорее всего не бывает merge конфликтов;
- проект может очень быстро параллельно развиваться в разные стороны;
§ recommendations.scope.parallelism.has.title
Часть работ параллельно
§ recommendations.scope.parallelism.has.description
Иногда фичу делают одновременно несколько человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат от 1.3 до 2.0 считаем, что часть работ в рамках разных фичей иногда делается параллельно;
§ recommendations.scope.parallelism.every.title
Параллельные работы
§ recommendations.scope.parallelism.every.description
любую фичу в один момент времени делают несколько человек
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат больше двух считаем, что большая часть работ в рамках разных фичей обычно делается параллельно;
§ recommendations.scope.money
в такую сумму можно оценить работу по данному проекту.
# Метод расчёта:
- человеко-дни затраченные на разработку умножаются на индивидуальную зарплату разработчиков;
Изменить зарплату каждого разработчика, для более точной суммы, можно в разделе «Настройки»
# Это много или мало?
Для ответа на этот вопрос, нужно ответить на следующие:
- Можно ли за эти деньги было купить готовое решение?
- Можно ли за эти деньги сделать более хороший продукт?
Если ответ на оба вопроса «да», то возможно, разработка с нуля не стоила потраченных на неё денег.
§ recommendations.scope.bus.everyHasOne.title
Bus factor = 1
§ recommendations.scope.bus.everyHasOne.description
В большинство фич погружен один человек.
Надо переключать людей.
# Почему это плохо:
- если сотрудники будут увольняться, будет трудно продолжить их работу;
- невозможно контролировать качество его кода;
# Как делается выборка:
- более 80% коммитов в фичу делает один человек;
- проект имеет более 60% таких фичей;
§ recommendations.scope.bus.oneMaintainer
в фичи погружен один человек.
# Почему это плохо:
- если он уволится, будет трудно продолжить разработку;
- снижается качество code-review;
- трудно запараллелить разработку при необходимости;
# Как делается выборка:
- более 80% коммитов в фичу сделал один человек;
§ recommendations.scope.types.process.title
Плохие процессы
§ recommendations.scope.types.process.description
Большинство фич содержат один тип задач.
§ recommendations.scope.types.one
фичи содержат один тип задач.
§ recommendations.scope.types.common
Возможно, разработчики неправильно подписывают коммиты или менеджер заводит один и тот же тип задач.
# Почему это важно:
- невозможно передать поддержку другой команде;
- невозможно выпустить "коробочную" версию;
- сильная зависимость от конкретных разработчиков;
- большое количество ошибок и низкое качество кода;
- вероятное замедление разработки в будущем;
# В чём ошибка менеджера:
- взгляд на продукт, только с позиции «работающей демки»;
# Что должно быть:
- тесты;
- ошибки (выявленные по результатам тестов);
- рефакторинг (т.к. архитектура может измениться);
- документация;
- правки стиля (как результат опроса фокус-группы);
§ recommendations.scope.plan.title
Постройте долгосрочный план
§ recommendations.scope.plan.description
с учетом архитектуры.
При том опираться этот план должен сразу на самые трудные задачи.
# Почему отсутствие плана плохо:
- сотрудники делают минимально работающую версию, не закладывая точки расширения. После этого пишется не масштабируемый код, который тормозит следующие фичи;
# В чём ошибка менеджера:
- он не показал, как продукт будет развиваться далее и в каких точках будет рост;
# Как должно быть:
- составляется глобальный план развития продукта;
- составляется глобальный план развития архитектуры (с разработчиками и DBA);
- на уровне схем сразу проговариваются моменты, которые могут сильно измениться;
§ recommendations.scope.cost.title
Оцените инвестиции в фичу
§ recommendations.scope.cost.description
с количеством потенциальной прибыли.
Фичи которые дорого стоят в разработке, но приносят мало прибыли, возможно, стоит отложить или вообще отменить. Это сделает проект более коммерчески успешным.
§ recommendations.author.lotOfLazy
пишет слишком мало кода.
# Может уволить?
- он тимлид, архитектор, аналитик?
- это его основной проект?
- есть какие-то зависимости от него?
# Почему нет смысла исправлять
Суммарные затраты на разработчика уже больше чем прибыль от его работы.
Если мы считаем, что объективных помех его работе не было, то человек либо не хочет работать вообще, либо работает на двух проектах одновременно.
Увольнение и замена новым сотрудником выглядит оправданным с точки зрения общей статистики.
§ recommendations.author.manyLazy
пишет мало кода. Нужно взять на контроль.
# Как делается выборка:
- на тестовых выборках хороший программист пишет код больше 80% времени;
- в данном случае показатель от 60% до 80%;
# Как контролировать:
- дробить задачи на 1..2 дня;
- каждый день спрашивать статус;
- убедиться, что задачи хорошо расписаны и готовы к началу разработки;
- устроить парное программирование, чтобы проверить фактическую скорость;
§ recommendations.author.oneTypeMans
получает слишком однообразные задачи по типу. Может выгореть.
# Почему это важно:
- если сотрудник выгорит, его скорость работы снизится;
- замедляется профессиональный рост;
- повышается вероятность увольнения;
# Как делается выборка:
- для каждого коммита определятся тип задачи;
- если больше 70% задач одного типа, значит человек делает одно и тоже;
§ recommendations.author.workToday.title: Работает $1
§ recommendations.author.workToday.description
над проектом в данный момент.
# Состав:
- $1;
# Почему именно они:
- рабочих дней более 50%;
- работали в течении последних 30 дней;
§ recommendations.author.dismissed.title: Уволилось $1
§ recommendations.author.dismissed.description
или работало короткий промежуток времени.
# Состав:
- $1;
# Почему именно они:
- работали в нормальном ритме (видимо, это их основной репозиторий);
- за последний месяц не было ни одного коммита;
- отпуск обычно 14 дней (их отсутствие не похоже на отпуск);
§ recommendations.author.staff.title: Помогают $1
§ recommendations.author.staff.description
Люди другой специализации, которые что-либо коммитили.
# Состав:
- $1;
# Почему именно они:
- это не open-source проект;
- рабочих дней менее 15% от общего числа;
- изменяют примерно одни и те же файлы;
§ recommendations.author.projectType.openSource.title
Открытый проект
§ recommendations.author.projectType.openSource.description
пять дней в неделю тут не работают.
Проект может быть и закрытым, просто такой темп работы обычно у открытых библиотек на GitHub.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- у open-source библиотек рабочих дней обычно максимум 15..20%;
# Последствия
Для проектов, где работа не постоянна, нет смысла во многих показателях. Поэтому показатели без коммитов, скорости и т.п. будут скрыты.
Как правило, оценку таких проектов делают перед началом разработки своей закрытой версии. Самые интересные показатели в этом случае вероятная стоимость и суммарное время на разработку.
§ recommendations.author.projectType.easy.title
Слабая загрузка
§ recommendations.author.projectType.easy.description
слишком много дней без коммитов. Нужно понять почему команда не пишет код.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- загрузка считается слабой, если процент без коммитов от 5% до 20%;
# Возможные причины:
- фактически нет задач;
- задачи есть, но хорошо ложатся на текущую архитектуру;
- разработчиков отвлекают совещаниями;
- команда не работает;
# Варианты решения:
- обсудить проблему с командой;
- уменьшить гранулярность задач, чтобы за день можно было успеть сделать одну или две задачи;
- ввести ежедневные совещания, чтобы проверять движение задач по статусу;
- устроить сеансы парного программирования, чтобы убедиться, что разработчик может работать быстрее;
§ recommendations.author.manager.title
Обозначьте дедлайны
§ recommendations.author.manager.description
У любой задачи должен быть чёткий дедлайн.
Это позволит не затягивать её выполнение на несколько дней или недель.
# Какие показатели стоит проверить:
- количество дней на одну задачу, которое тратит работник;
- количество дней ожидания влития PR (страница статистики по PR);
§ recommendations.author.shorTalk.title
Проводите ежедневные совещания
§ recommendations.author.shorTalk.description
они помогают быть в курсе проекта.
Не растягивайте их отвлекаясь на посторонние темы.
# На какие вопросы должен ответить сотрудник:
- что было сделано;
- что будет сделано;
- есть ли какие-либо проблемы;
# Следует обрывать монолог, если:
- начинают подробно описывать мелкие детали, которые не важны;
- уводят диалог в сторону, от первоначального плана;
# Почему это важно:
Часто сотрудник, который ничего не делает, старается уйти от ответа. Для этого он рассказывает кучу ненужных подробностей свой работы. Это позволяет усыпить внимание участников и растянуть время ответа. Создается ощущение что он чем-то занят, хотя по факту работы не было.
§ recommendations.author.ipr.title
Составьте план обучения
§ recommendations.author.ipr.description
на каждого сотрудника.
*Индивидуальный план обучения* это список целей и задач, которые помогают человеку развиваться в определенной области.
# Как составить план:
- составить матрицу компетенций;
- определить по каким компетенциям меньше всего знаний и опыта;
- узнать какие из этих компетенций интересны сотруднику;
- придумать 3..5 целей в рамках каждой такой компетенции на полпостороние года или год;
- каждый месяц пытаться сделать что-либо для достижения одной цели;
- каждый месяц напоминать об общем плане достижения этих целей;
# Нужен ли план руководителю?
Да, руководитель так же должен составить план на себя. Если нет вышестоящего руководителя, то он должен проверять сам себя.
# Почему это важно:
- сотрудники становятся более лояльны к компании;
- за теже деньги вы получаете более квалифицированные кадры;
§ recommendations.author.oneToOne.title
Проводите 1-1 каждый месяц
§ recommendations.author.oneToOne.description
это поможет выявить проблемы на ранней стадии.
*One-to-one* это регулярные личные встречи руководителя с подчиненным. На таких встречах обычно обсуждают всё, что важно для сотрудника, что его волнует, и то, чем он может поделиться с руководителем только наедине.
# Почему это важно:
- легко выяснить, кто из сотрудников перегружен, а у кого есть свободное время;
- можно предотвратить выгорание сотрудника;
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается мотивация и вовлеченность сотрудников;
§ recommendations.author.club.title
Ходите в бар
§ recommendations.author.club.description
один раз в месяц или два.
Это поможет выстроить неформальную коммуникацию в коллективе и сплотить команду, даже если общение будет сжатым.
# Почему это важно:
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается вовлеченность сотрудников;
§ recommendations.hour.onlyWork.title: Выходных тут нет
§ recommendations.hour.onlyWork.description: Вероятно, стоит уволить менеджера проекта.
§ recommendations.hour.weekends.title: Работа на выходных
§ recommendations.hour.weekends.description: Вероятно, стоит проверить менеджера проекта.
§ recommendations.hour.easy.title: Бывают проблемы
§ recommendations.hour.easy.description: Вероятно, бывают завалы и приходится работать на выходных.
§ recommendations.week.lazyDays.down.title: Стало меньше прогулов
§ recommendations.week.lazyDays.down.description: за последние три недели этот показатель упал
§ recommendations.week.lazyDays.up.title: Стало больше прогулов
§ recommendations.week.lazyDays.up.description: нет задач или нужен более жесткий контроль
§ recommendations.week.notWork.title: Стабильно не дорабатывает
§ recommendations.week.notWork.description: т.к. каждую неделю пишет код не 100% времени
§ recommendations.week.upWork.title: Стабильно перерабатывает
§ recommendations.week.upWork.description: т.к. каждую неделю пишет код в выходные дни
§ recommendations.week.task.up.title: Растёт производительность
§ recommendations.week.task.up.description: или задачи стали слишком мелкие. Нужно проверить. Если гранулярность та же - закрепить результат.
§ recommendations.week.task.lazyMaintainer.description: стабильный лидер по прогулам. Уволить?
§ recommendations.week.task.down.title: Падает производительность
§ recommendations.week.task.down.description
или задачи хуже разбивают. Нужно проверить. Если гранулярность та же - взять на контроль.
# Метод оценки:
- количество задач в день, над которыми работают, на протяжении последних трех недель стабильно падает.
# Возможные ошибки:
- задачи могли быть сложнее, чем казались;
- задачи могли иметь большой объём работы (нужно проверить количество изменений, падают они или нет за этот же период)
§ recommendations.type.everyHasOne.title: Не подписывают тип задачи
§ recommendations.type.everyHasOne.description: большинство типов задач делает один человек.
§ recommendations.type.oneMaintainer.title: Узкая специализация
§ recommendations.type.oneMaintainer.description
большинство задач одного типа делают одни и те же люди.
# Типы задач:
§ recommendations.type.common
# Возможно, это не так
Нужно убедиться, что остальные сотрудники верно подписывают коммиты.
Шаги, которые помогут это сделать:
- настроить пре-коммит проверку для commit message;
- объяснить команде, что нужно указывать тип;
- проверить в новых ветках, что сотрудники следуют правилу;
# Если это действительно так
Вы настроили проверки и убедились что один и тот же сотрудник, делает задачи одного и того же типа.
Почему это плохо:
- его увольнение остановит целую пачку процессов;
- уменьшается компетенция остальных членов команды;
- трудно верхнеуровнево понять его правки;
Как это исправить:
- распределять разные типы задач равномерно;
- менять область работы (тесты, документация, ошибки) между сотрудниками через спринт;
§ recommendations.type.fewTypes.title
Это локальный продукт
§ recommendations.type.fewTypes.description
для конкретного заказчика или проблемы.
# Какие признаки есть у «глобального» продукта:
- локализация;
- документация;
- большой объём тестов;
- визуальная кастомизация;
- рефакторинг узких мест;
- и т.п.
# Почему этот продукт выглядит как «локальный»:
- у каждого «глобального» признака будет перевес по своему типу задач;
- чем больше «глобальных» признаков, тем больше вероятность «глобального» продукта;
В данном случае мы видим небольшое число типов, а следовательно, скорее всего есть недоработки, мешающие легко масштабировать продукт на мировой рынок и продавать его в других странах.
# Возможно, это не так
По типам файлов мы можем предположить тип программы (сайт, серверное приложение, 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-а.
`;

View file

@ -0,0 +1,27 @@
export default `
§ 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: Currency
§ page.settings.common.workDaysInYear: Количество рабочих дней в году
§ page.settings.common.vacationDaysInYear: Количество дней отпуска в год
§ page.settings.common.workDaysInWeek: Рабочие дни
§ page.settings.form.save: Save
§ page.settings.form.cancel: Cancel
§ page.settings.form.remove: Remove
§ page.settings.form.addEmployee: Добавить сотрудника
§ page.settings.form.addContract: Добавить трудовой договор
`;

View file

@ -0,0 +1,94 @@
export default `
§ achievements.commitsAfter1500.title: Сова
§ achievements.commitsAfter1500.description: 70% коммитов после 15:00
§ achievements.commitsBefore1500.title: Ранняя пташка
§ achievements.commitsBefore1500.description: 70% коммитов до обеда
§ achievements.workEveryTime.title: Раб божий
§ achievements.workEveryTime.description: есть коммит на каждый час суток
§ achievements.workNotWork.title: Стрельба холостыми
§ achievements.workNotWork.description: коммиты есть, а закрытых задач нет
§ achievements.userNotWork.title: Залётный
§ achievements.userNotWork.description: это не его основной проект
§ achievements.userIsDied.title: Мёртвая душа
§ achievements.userIsDied.description: работал, но уволился
§ achievements.lessTasks.title: Зашел и вышел
§ achievements.lessTasks.description: меньше всего закрытых задач
§ achievements.moreTasks.title: Батя грит малаца
§ achievements.moreTasks.description: больше всего закрытых задач
§ achievements.everyMessageLong.title: Мастер красноречия
§ achievements.everyMessageLong.description: стабильно самые длинные подписи коммитов
§ achievements.everyMessageShort.title: Болтун находка для шпиона
§ achievements.everyMessageShort.description: стабильно, самые короткие подписи коммитов
§ achievements.shortestName.title: Размер не главное
§ achievements.shortestName.description: самое короткое имя
§ achievements.longestName.title: Азим Азиз Иль Ам Кадир Имран II
§ achievements.longestName.description: самое длинное имя
§ achievements.moreCommits.title: Мастер бекапов
§ achievements.moreCommits.description: больше всего коммитов
§ achievements.lessCommits.title: Редко но метко
§ achievements.lessCommits.description: меньше всего коммитов
§ achievements.oneCommitOneTask.title: Точно в цель
§ achievements.oneCommitOneTask.description: в среднем один коммит на задачу
§ achievements.moreLazyDays.title: Мысленно я с вами
§ achievements.moreLazyDays.description: больше всего дней без коммитов
§ achievements.lessLazyDays.title: Папа Карло
§ achievements.lessLazyDays.description: меньше всего дней без коммитов
§ achievements.zeroLazyDays.title: Ни единого разрыва
§ achievements.zeroLazyDays.description: ни одного дня без коммитов
§ achievements.moreWorkDays.title: Ценный работник
§ achievements.moreWorkDays.description: больше всего рабочих дней
§ achievements.moreScopes.title: Стартапер
§ achievements.moreScopes.description: сделал больше всего фичей
§ achievements.lessScopes.title: Щегол
§ achievements.lessScopes.description: сделал меньше всего фичей
§ achievements.moreDaysForTask.title: Улитка на склоне
§ achievements.moreDaysForTask.description: работа по задачам идёт медленнее чем у остальных
§ achievements.more2DaysForTask.title: Cо слоу
§ achievements.more2DaysForTask.description: больше двух дней на задачу
§ achievements.moreDaysInProject.title: Старожил
§ achievements.moreDaysInProject.description: больше всего дней на проекте
§ achievements.lessDaysInProject.title: А это кто?
§ achievements.lessDaysInProject.description: меньше всего дней на проекте
§ achievements.more90DaysInProject.title: Добро пожаловать
§ achievements.more90DaysInProject.description: не уволили на испытательном
§ achievements.lessDaysForTask.title: Скорострел
§ achievements.lessDaysForTask.description: одна задача занимает меньше дня
§ achievements.adam.title: Адам
§ achievements.adam.description: первый стабильный сотрудник на проекте
§ achievements.more666DaysInProject.title: Чёрт
§ achievements.more666DaysInProject.description: отработал 666 дней на проекте
§ achievements.more777DaysInProject.title: Азино 3 топора
§ achievements.more777DaysInProject.description: отработал 777 дней на проекте
§ achievements.moreRefactoring.title: Выпускающий редактор
§ achievements.moreRefactoring.description: сделал больше всех меток «рефакторинг»
§ achievements.longestMessage.title: А разговоров то было...
§ achievements.longestMessage.description: самая длинная подпись коммита за все время
§ achievements.moreTasksInDay.title: Спиди-гонщик
§ achievements.moreTasksInDay.description: рекорд по количеству закрытых задач в день
§ achievements.hasCommitFrom0to7.title: Ночной дозор
§ achievements.hasCommitFrom0to7.description: есть коммит на каждый час ночи
§ achievements.noCommitOnDay.title: Технический перерыв
§ achievements.noCommitOnDay.description: есть определенный час и день в рабочее время в который никогда не комитит
§ achievements.hasCommitEveryTime.title: Умер на работе
§ achievements.hasCommitEveryTime.description: есть коммит на час каждого дня (включая выходные)
§ achievements.commitsAfter1800.title: Делу время
§ achievements.commitsAfter1800.description: нет ни одного коммита после 18:00
§ achievements.more1488DaysInProject.title: им. Максима Марцинкевича
§ achievements.more1488DaysInProject.description: отработал 1488 дней на проекте
§ achievements.taskNumber300.title: Знаком с трактористом
§ achievements.taskNumber300.description: первый взял в работу задачу с номером 300
§ achievements.moreFix.title: Bug hunter
§ achievements.moreFix.description: больше всего закрытых багов
§ achievements.lessWorkDays.title: Дальше без меня
§ achievements.lessWorkDays.description: меньше всего рабочих дней
§ achievements.moreCreateCode.title: Созидатель
§ achievements.moreCreateCode.description: склонен больше остальных добавлять код
§ achievements.moreRemoveCode.title: Разрушитель
§ achievements.moreRemoveCode.description: склонен больше остальных удалять код
§ achievements.moreChangeCode.title: Реформатор
§ achievements.moreChangeCode.description: склонен больше остальных изменять код
§ achievements.moreStyle.title: Полиция моды
§ achievements.moreStyle.description: склонен больше остальных изменять CSS
§ achievements.moreOnHoliday.title: Нет жизни
§ achievements.moreOnHoliday.description: относительно много коммитов в нерабочее время
`;

View file

@ -0,0 +1,28 @@
export default `
§ 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: Настройки сохранены
`;

View file

@ -0,0 +1,15 @@
import achievements from './achievements';
import common from './common';
import navigation from './navigation';
import recommendations from './recommendations';
import settings from './settings';
import pages from './pages';
export default [
achievements,
common,
navigation,
recommendations,
settings,
pages,
].join('');

View file

@ -0,0 +1,37 @@
export default `
§ sidebar.switch.team: Команда
§ sidebar.switch.person: Сотрудник
§ sidebar.buttons.settings: Настройки
§ sidebar.buttons.print: Печать
§ sidebar.filters.all: всё время
§ sidebar.filters.year: год
§ sidebar.filters.halfYear: пол года
§ sidebar.filters.month: месяц
§ sidebar.filters.week: неделя
§ sidebar.team.total: Общая информация
§ sidebar.team.scope: Фичи
§ sidebar.team.author: Сотрудники
§ sidebar.team.type: Типы задач
§ sidebar.team.pr: Влитие кода
§ sidebar.team.day: По дням
§ sidebar.team.week: По неделям
§ sidebar.team.month: По месяцам
§ sidebar.team.tree: Анализ файлов
§ sidebar.team.hours: Расписание
§ sidebar.team.commits: Все коммиты
§ sidebar.team.changes: Все изменения
§ sidebar.team.words: Популярные слова
§ sidebar.team.top: Викторина
§ sidebar.team.settings: Настройки
§ sidebar.person.total: Общая информация
§ sidebar.person.money: Стоимость работы
§ sidebar.person.speed: Скорость
§ sidebar.person.day: По дням
§ sidebar.person.week: По неделям
§ sidebar.person.month: По месяцам
§ sidebar.person.hours: Расписание
§ sidebar.person.commits: Все коммиты
§ sidebar.person.changes: Все изменения
§ sidebar.person.words: Популярные слова
§ sidebar.person.settings: Настройки
`;

View file

@ -0,0 +1,203 @@
export default `
§ page.welcome.step1: Выполните команду в корне вашего проекта
§ page.welcome.step3: Перетащите
§ page.welcome.step4: файл log.txt на эту страницу
§ page.welcome.description1: Git создаст файл log.txt. Он содержит данные для построения отчёта. Или git shortlog -s -n -e если отчёт вам не нужен. Создайте файл
§ 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.print.modal.title: Что распечатываем?
§ page.print.modal.page: Текущую страницу
§ page.print.modal.type: Текущий раздел
§ page.print.modal.all: Всю статистику
§ page.print.modal.cancel: Отмена
§ page.print.tableOfContents: Оглавление
§ page.print.title: Отчёт по git-репозиторию «$1»
§ page.print.description: Данные для отчёта были получены из истории коммитов.
§ page.team.author.title: Статистика по сотрудникам
§ page.team.author.description1: *Часть статистики* (скорость работы, затраченные деньги и т.п.) *по сотрудникам с типом «Помощник» не считается*, т.к. это эпизодическая роль в проекте. Предполагаем, что они не влияют на проект, а их правками можно пренебречь на фоне общего объема работы.
§ page.team.author.description2: *Сортировка по умолчанию* это сортировка по количеству задач и группам (текущие, уволенные, помогающие сотрудники).
§ page.team.author.types: Тип работ
§ page.team.author.commits: Коммитов
§ page.team.author.commitsSmall: коммитов
§ page.team.author.tasks: Задач
§ page.team.author.tasksSmall: задач
§ page.team.author.workedLosses: Дни с коммитами и без
§ page.team.author.worked: работа
§ page.team.author.losses: дни без коммитов
§ page.team.author.days: дней
§ page.team.author.daysForTask: Дней на задачу
§ page.team.author.scopes: Фич
§ page.team.author.moneyAll: Получил
§ page.team.author.moneyWorked: Отработал
§ page.team.author.moneyLosses: Переплата
§ page.team.hours.title: Распределение коммитов в течении каждого дня недели
§ page.team.month.title: Календарь работы по проекту
§ page.team.scope.title: Статистика по фичам
§ page.team.scope.scope: Фича
§ page.team.scope.days: Раб. дней
§ page.team.scope.authorsDays: Человеко-дней
§ page.team.scope.tasks: Задач
§ page.team.scope.commits: Коммитов
§ page.team.scope.commitsSmall: коммитов
§ page.team.scope.types: Тип работ
§ page.team.scope.authors: Персональный вклад
§ page.team.scope.cost: Стоимость
§ page.team.type.title: Статистика по типам задач
§ page.team.type.description: *Персональный вклад* считается по количеству коммитов, а не объему измененных строк или файлов. Поэтому следует так же смотреть раздел «Анализ файлов», чтобы оценить масштаб изменений.
§ page.team.type.type: Тип работы
§ page.team.type.tasks: Задач
§ page.team.type.tasksSmall: задач
§ page.team.type.days: Дней
§ page.team.type.daysSmall: дней
§ page.team.type.authorsDays: Человеко-дней
§ page.team.type.commits: Коммитов
§ page.team.type.authors: Персональный вклад
§ page.team.total.titleA: Объём работ
§ page.team.total.titleB: Стоимость
§ page.team.total.daysWorked.title: человеко-дней
§ page.team.total.daysWorked.description: Учтены только дни, в которые делались коммиты
§ page.team.total.commits.title: коммитов
§ page.team.total.commits.description: Удалённые ветки не считаются
§ page.team.total.daysLosses.title: дней без коммитов
§ page.team.total.daysLosses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.team.total.employment.title: работает / уволилось
§ page.team.total.employment.description: Если сотрудник в течении месяца не сделал ни одного коммита, он считается уволенным
§ page.team.total.moneyAll.title: общая
§ page.team.total.moneyAll.description: Суммарные затраты на зп
§ page.team.total.moneyWorked.title: фактическая
§ page.team.total.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.team.total.moneyLosses.title: возможная переплата
§ page.team.total.moneyLosses.description: Оплаченные рабочие дни, когда коммитов не было
§ page.team.total.weekendPayment.title: работа на выходных
§ page.team.total.weekendPayment.description: Суммарная переплата за работу в выходные дни
§ page.team.total.workSpeed.title: задач в день
§ page.team.total.workSpeed.description: Средняя скорость работы команды при текущем составе сотрудников
§ page.team.total.moneySpeed.title: в месяц
§ page.team.total.moneySpeed.description: Прогнозируемая сумма выплаты на зп при текущем составе сотрудников без учета налогов и сопутствующих затрат
§ page.team.total.description1: *Человеко-дни* это работа одного сотрудника в течение одного рабочего дня. Например, за один календарный день, команда из трех сотрудников выдает объем работы в три человеко-дня.
§ page.team.total.description2: *Днями прогулов* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют.
§ page.team.total.description3: Карточка *работает и уволилось* показывает фактический состав сотрудников, которые постоянно участвуют в работе. Кроме этого, есть «помощники» это сотрудники, как правило другой специализации, которые могут иногда делать коммиты в проект.
§ page.team.total.description4: *Переплатой* считаются только рабочие дни, когда коммиты могли бы быть сделаны. Выходные, государственные праздники и отпуска в расчёте не участвуют. Именно поэтому переплата + фактическая стоимость != общей. В общей стоимости заложена оплата выходных, государственных праздников и отпусков.
§ page.team.total.description5: *Работой на выходных* считается по коэффициенту х2 от оплаты обычного дня. Выше отображена именно переплата (х1), т.к. сам факт переработки в данном контексте не интересен. Мы не смотрим скорость сжигания бюджета. Мы смотрим переплату при увеличении скорости работы.
§ page.team.tree.title: Дерево проекта с учётом выбранных фильтров
§ page.team.tree.filters.author: Сотрудник
§ page.team.tree.filters.commits: Количество коммитов
§ page.team.tree.filters.help: Минимальное количество коммитов, которое сделал сотрудник в файле
§ page.team.tree.filters.all: Все сотрудники
§ page.team.tree.add: Кто добавлял
§ page.team.tree.change: Кто менял
§ page.team.tree.remove: Кто удалял
§ page.team.tree.line: строк
§ page.team.tree.lineAdd: добавили
§ page.team.tree.lineRemove: изменили
§ page.team.week.title: Статистика по неделям
§ page.team.week.date: Дата
§ page.team.week.numberTasks: Количество задач
§ page.team.week.people: Количество человек
§ page.team.week.line: Изменение строк
§ page.team.week.days: Дни с коммитами и без
§ page.team.week.lossesDetails: Кто не коммитил
§ page.team.week.add: добавили
§ page.team.week.change: изменили
§ page.team.week.remove: удалили
§ page.team.week.hasCommits: были коммиты
§ 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: Основные характеристики
§ 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.description: Учтены только дни, в которые делались коммиты
§ page.person.business.tasks.title: задач
§ page.person.business.tasks.description: Если коммиты правильно подписаны
§ page.person.business.losses.title: дней без коммитов
§ page.person.business.losses.description: Все дни минус: праздники, выходные, отпуск, дни с коммитами
§ page.person.business.commits.title: коммитов
§ page.person.business.commits.description: Удалённые ветки не считаются
§ page.person.business.time.description: Время от первого, до последнего коммита (в том числе, нерабочие дни)
§ page.person.business.time.title: Дней на проекте:
§ page.person.business.time.dismissed: (уволен)
§ page.person.business.time.staff: (не в команде)
§ page.person.business.achievements: Достижения
§ page.person.changes.title: Достижения
§ page.person.changes.description:
При некоторых видах форматирования git отмечает строки как «удалённые» и «добавленные»,
хотя на самом деле они были «изменены». Поэтому, если вы провели большой рефакторинг,
git может показать малое количество изменений в статистике, а фактический результат
будет отмечен, как скачок «удаленных» и «добавленных» строк.
§ page.person.changes.description: Список коммитов и количество изменений в них за этот день:
§ page.person.commits.title: Список коммитов:
§ page.person.money.title.total: За всё время
§ page.person.money.title.middle: Средняя стоимость
§ page.person.money.moneyAll.title: получил
§ page.person.money.moneyAll.description: Предполагаемая сумма зп с проекта (см. настройки)
§ page.person.money.moneyWorked.title: отработал
§ page.person.money.moneyWorked.description: Фактически отработанные дни умноженные на среднюю зп
§ page.person.money.moneyLosses.title: возможная переплата
§ page.person.money.moneyLosses.description: Дни без коммитов умноженные на среднюю зп
§ page.person.money.tasks.title: задача
§ page.person.money.tasks.description: Количество закрытых задач к стоимости дня
§ page.person.money.commits.title: коммит
§ page.person.money.commits.description: Количество коммитов к стоимости рабочего дня
§ page.person.speed.task: Одна задача в среднем это
§ page.person.speed.max: Максимальная скорость в день
§ page.person.speed.days.title: дней
§ page.person.speed.days.description: Имеются ввиду рабочие дни, если коммиты правильно подписаны
§ page.person.speed.commits.title: коммитов
§ page.person.speed.commits.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.line.title: строк кода
§ page.person.speed.line.description: Отрезаны 10% максимальных и минимальных значений
§ page.person.speed.tasks.title: задач
§ page.person.speed.tasks.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.speed.maxCommits.title: коммитов
§ page.person.speed.maxCommits.description: Задача может быть не доделана, но работа по ней должна быть
§ page.person.hours.title: Распределение коммитов в течении каждого дня недели
§ page.person.week.date: Дата
§ page.person.week.tasks: Количество задач
§ page.person.week.workDays: Дни с коммитами
§ page.person.week.taskInDay: Задач в день
§ page.person.week.days: дней
§ page.person.week.workDay: будни
§ page.person.week.weekends: выходные
`;

View file

@ -0,0 +1,506 @@
export default `
§ recommendations.title
Рекомендации и факты
§ recommendations.timestamp.firstCommit.description
сделал первый коммит
День недели: $1
§ recommendations.timestamp.lastCommit.description
сделал последний коммит
День недели: $1
§ recommendations.timestamp.common.title: $1 дней
§ recommendations.timestamp.allDays.description: от первого до последнего коммита (включая выходные и праздники).
§ recommendations.timestamp.lossesDays.description: без коммитов, даже с учётом выходных, отпуска и государственных праздников.
§ recommendations.timestamp.weekendDays.description
работы на выходных
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- сотрудники быстрее выгорают;
§ recommendations.timestamp.regularWeekendWord.title: Регулярные переработки
§ recommendations.timestamp.sometimeWeekendWord.title: Бывают переработки
§ recommendations.timestamp.weekendWord.description
Вероятно, стоит сменить менеджера проекта, аналитика и архитектора.
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- качество продукта, как правило, получается низкое;
- часть сотрудников увольняется;
- из-за спешки появляются новые ошибки;
# Скорее всего:
- неверно оценили сроки в самом начале;
- тех. задание отсутствует;
- слабая аналитика;
- слабая архитектура (архитектора не нанимали, а команда состоит из мидл разработчиков);
- сначала начали писать код, потом проектировать;
- нет нормальных процессов, чтобы понять ошибки;
§ recommendations.timestamp.neverWeekendWord.title: Обычно без переработок
§ recommendations.timestamp.neverWeekendWord.description
Но иногда бывают.
# Почему это плохо:
- заказчик платит двойную цену за работу в выходной день;
- сотрудники быстрее выгорают;
§ recommendations.scope.parallelism.not.title
Нет параллельных работ
§ recommendations.scope.parallelism.not.description
любую фичу в один момент времени делает один человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат меньше 1.3 считаем, что параллельных работ в рамках большинства фичей обычно нет;
# Почему это плохо:
- повышается bus factor;
- сотрудники медленнее развиваются;
- трудно качественно проверить работу сотрудника;
# Почему это хорошо:
- появляются эксперты, которые очень глубоко погружены в предметную область и могут предложить более качественные решения;
- скорее всего не бывает merge конфликтов;
- проект может очень быстро параллельно развиваться в разные стороны;
§ recommendations.scope.parallelism.has.title
Часть работ параллельно
§ recommendations.scope.parallelism.has.description
Иногда фичу делают одновременно несколько человек.
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат от 1.3 до 2.0 считаем, что часть работ в рамках разных фичей иногда делается параллельно;
§ recommendations.scope.parallelism.every.title
Параллельные работы
§ recommendations.scope.parallelism.every.description
любую фичу в один момент времени делают несколько человек
# Метод расчёта:
- человеко-дни делятся на фактические дни для каждой фичи;
- находим среднее арифметическое;
- если результат больше двух считаем, что большая часть работ в рамках разных фичей обычно делается параллельно;
§ recommendations.scope.money
в такую сумму можно оценить работу по данному проекту.
# Метод расчёта:
- человеко-дни затраченные на разработку умножаются на индивидуальную зарплату разработчиков;
Изменить зарплату каждого разработчика, для более точной суммы, можно в разделе «Настройки»
# Это много или мало?
Для ответа на этот вопрос, нужно ответить на следующие:
- Можно ли за эти деньги было купить готовое решение?
- Можно ли за эти деньги сделать более хороший продукт?
Если ответ на оба вопроса «да», то возможно, разработка с нуля не стоила потраченных на неё денег.
§ recommendations.scope.bus.everyHasOne.title
Bus factor = 1
§ recommendations.scope.bus.everyHasOne.description
В большинство фич погружен один человек.
Надо переключать людей.
# Почему это плохо:
- если сотрудники будут увольняться, будет трудно продолжить их работу;
- невозможно контролировать качество его кода;
# Как делается выборка:
- более 80% коммитов в фичу делает один человек;
- проект имеет более 60% таких фичей;
§ recommendations.scope.bus.oneMaintainer
в фичи погружен один человек.
# Почему это плохо:
- если он уволится, будет трудно продолжить разработку;
- снижается качество code-review;
- трудно запараллелить разработку при необходимости;
# Как делается выборка:
- более 80% коммитов в фичу сделал один человек;
§ recommendations.scope.types.process.title
Плохие процессы
§ recommendations.scope.types.process.description
Большинство фич содержат один тип задач.
§ recommendations.scope.types.one
фичи содержат один тип задач.
§ recommendations.scope.types.common
Возможно, разработчики неправильно подписывают коммиты или менеджер заводит один и тот же тип задач.
# Почему это важно:
- невозможно передать поддержку другой команде;
- невозможно выпустить "коробочную" версию;
- сильная зависимость от конкретных разработчиков;
- большое количество ошибок и низкое качество кода;
- вероятное замедление разработки в будущем;
# В чём ошибка менеджера:
- взгляд на продукт, только с позиции «работающей демки»;
# Что должно быть:
- тесты;
- ошибки (выявленные по результатам тестов);
- рефакторинг (т.к. архитектура может измениться);
- документация;
- правки стиля (как результат опроса фокус-группы);
§ recommendations.scope.plan.title
Постройте долгосрочный план
§ recommendations.scope.plan.description
с учетом архитектуры.
При том опираться этот план должен сразу на самые трудные задачи.
# Почему отсутствие плана плохо:
- сотрудники делают минимально работающую версию, не закладывая точки расширения. После этого пишется не масштабируемый код, который тормозит следующие фичи;
# В чём ошибка менеджера:
- он не показал, как продукт будет развиваться далее и в каких точках будет рост;
# Как должно быть:
- составляется глобальный план развития продукта;
- составляется глобальный план развития архитектуры (с разработчиками и DBA);
- на уровне схем сразу проговариваются моменты, которые могут сильно измениться;
§ recommendations.scope.cost.title
Оцените инвестиции в фичу
§ recommendations.scope.cost.description
с количеством потенциальной прибыли.
Фичи которые дорого стоят в разработке, но приносят мало прибыли, возможно, стоит отложить или вообще отменить. Это сделает проект более коммерчески успешным.
§ recommendations.author.lotOfLazy
пишет слишком мало кода.
# Может уволить?
- он тимлид, архитектор, аналитик?
- это его основной проект?
- есть какие-то зависимости от него?
# Почему нет смысла исправлять
Суммарные затраты на разработчика уже больше чем прибыль от его работы.
Если мы считаем, что объективных помех его работе не было, то человек либо не хочет работать вообще, либо работает на двух проектах одновременно.
Увольнение и замена новым сотрудником выглядит оправданным с точки зрения общей статистики.
§ recommendations.author.manyLazy
пишет мало кода. Нужно взять на контроль.
# Как делается выборка:
- на тестовых выборках хороший программист пишет код больше 80% времени;
- в данном случае показатель от 60% до 80%;
# Как контролировать:
- дробить задачи на 1..2 дня;
- каждый день спрашивать статус;
- убедиться, что задачи хорошо расписаны и готовы к началу разработки;
- устроить парное программирование, чтобы проверить фактическую скорость;
§ recommendations.author.oneTypeMans
получает слишком однообразные задачи по типу. Может выгореть.
# Почему это важно:
- если сотрудник выгорит, его скорость работы снизится;
- замедляется профессиональный рост;
- повышается вероятность увольнения;
# Как делается выборка:
- для каждого коммита определятся тип задачи;
- если больше 70% задач одного типа, значит человек делает одно и тоже;
§ recommendations.author.workToday.title: Работает $1
§ recommendations.author.workToday.description
над проектом в данный момент.
# Состав:
- $1;
# Почему именно они:
- рабочих дней более 50%;
- работали в течении последних 30 дней;
§ recommendations.author.dismissed.title: Уволилось $1
§ recommendations.author.dismissed.description
или работало короткий промежуток времени.
# Состав:
- $1;
# Почему именно они:
- работали в нормальном ритме (видимо, это их основной репозиторий);
- за последний месяц не было ни одного коммита;
- отпуск обычно 14 дней (их отсутствие не похоже на отпуск);
§ recommendations.author.staff.title: Помогают $1
§ recommendations.author.staff.description
Люди другой специализации, которые что-либо коммитили.
# Состав:
- $1;
# Почему именно они:
- это не open-source проект;
- рабочих дней менее 15% от общего числа;
- изменяют примерно одни и те же файлы;
§ recommendations.author.projectType.openSource.title
Открытый проект
§ recommendations.author.projectType.openSource.description
пять дней в неделю тут не работают.
Проект может быть и закрытым, просто такой темп работы обычно у открытых библиотек на GitHub.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- у open-source библиотек рабочих дней обычно максимум 15..20%;
# Последствия
Для проектов, где работа не постоянна, нет смысла во многих показателях. Поэтому показатели без коммитов, скорости и т.п. будут скрыты.
Как правило, оценку таких проектов делают перед началом разработки своей закрытой версии. Самые интересные показатели в этом случае вероятная стоимость и суммарное время на разработку.
§ recommendations.author.projectType.easy.title
Слабая загрузка
§ recommendations.author.projectType.easy.description
слишком много дней без коммитов. Нужно понять почему команда не пишет код.
# Метод оценки:
- берется статистика по всем активным разработчикам;
- подсчитывается среднее число дней работы и без коммитов;
- загрузка считается слабой, если процент без коммитов от 5% до 20%;
# Возможные причины:
- фактически нет задач;
- задачи есть, но хорошо ложатся на текущую архитектуру;
- разработчиков отвлекают совещаниями;
- команда не работает;
# Варианты решения:
- обсудить проблему с командой;
- уменьшить гранулярность задач, чтобы за день можно было успеть сделать одну или две задачи;
- ввести ежедневные совещания, чтобы проверять движение задач по статусу;
- устроить сеансы парного программирования, чтобы убедиться, что разработчик может работать быстрее;
§ recommendations.author.manager.title
Обозначьте дедлайны
§ recommendations.author.manager.description
У любой задачи должен быть чёткий дедлайн.
Это позволит не затягивать её выполнение на несколько дней или недель.
# Какие показатели стоит проверить:
- количество дней на одну задачу, которое тратит работник;
- количество дней ожидания влития PR (страница статистики по PR);
§ recommendations.author.shorTalk.title
Проводите ежедневные совещания
§ recommendations.author.shorTalk.description
они помогают быть в курсе проекта.
Не растягивайте их отвлекаясь на посторонние темы.
# На какие вопросы должен ответить сотрудник:
- что было сделано;
- что будет сделано;
- есть ли какие-либо проблемы;
# Следует обрывать монолог, если:
- начинают подробно описывать мелкие детали, которые не важны;
- уводят диалог в сторону, от первоначального плана;
# Почему это важно:
Часто сотрудник, который ничего не делает, старается уйти от ответа. Для этого он рассказывает кучу ненужных подробностей свой работы. Это позволяет усыпить внимание участников и растянуть время ответа. Создается ощущение что он чем-то занят, хотя по факту работы не было.
§ recommendations.author.ipr.title
Составьте план обучения
§ recommendations.author.ipr.description
на каждого сотрудника.
*Индивидуальный план обучения* это список целей и задач, которые помогают человеку развиваться в определенной области.
# Как составить план:
- составить матрицу компетенций;
- определить по каким компетенциям меньше всего знаний и опыта;
- узнать какие из этих компетенций интересны сотруднику;
- придумать 3..5 целей в рамках каждой такой компетенции на полпостороние года или год;
- каждый месяц пытаться сделать что-либо для достижения одной цели;
- каждый месяц напоминать об общем плане достижения этих целей;
# Нужен ли план руководителю?
Да, руководитель так же должен составить план на себя. Если нет вышестоящего руководителя, то он должен проверять сам себя.
# Почему это важно:
- сотрудники становятся более лояльны к компании;
- за теже деньги вы получаете более квалифицированные кадры;
§ recommendations.author.oneToOne.title
Проводите 1-1 каждый месяц
§ recommendations.author.oneToOne.description
это поможет выявить проблемы на ранней стадии.
*One-to-one* это регулярные личные встречи руководителя с подчиненным. На таких встречах обычно обсуждают всё, что важно для сотрудника, что его волнует, и то, чем он может поделиться с руководителем только наедине.
# Почему это важно:
- легко выяснить, кто из сотрудников перегружен, а у кого есть свободное время;
- можно предотвратить выгорание сотрудника;
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается мотивация и вовлеченность сотрудников;
§ recommendations.author.club.title
Ходите в бар
§ recommendations.author.club.description
один раз в месяц или два.
Это поможет выстроить неформальную коммуникацию в коллективе и сплотить команду, даже если общение будет сжатым.
# Почему это важно:
- можно получить быструю обратную связь о процессах, которые вы можете не замечать;
- формируется доверительное отношение, сотрудники становятся более лояльны к компании;
- повышается вовлеченность сотрудников;
§ recommendations.hour.onlyWork.title: Выходных тут нет
§ recommendations.hour.onlyWork.description: Вероятно, стоит уволить менеджера проекта.
§ recommendations.hour.weekends.title: Работа на выходных
§ recommendations.hour.weekends.description: Вероятно, стоит проверить менеджера проекта.
§ recommendations.hour.easy.title: Бывают проблемы
§ recommendations.hour.easy.description: Вероятно, бывают завалы и приходится работать на выходных.
§ recommendations.week.lazyDays.down.title: Стало меньше прогулов
§ recommendations.week.lazyDays.down.description: за последние три недели этот показатель упал
§ recommendations.week.lazyDays.up.title: Стало больше прогулов
§ recommendations.week.lazyDays.up.description: нет задач или нужен более жесткий контроль
§ recommendations.week.notWork.title: Стабильно не дорабатывает
§ recommendations.week.notWork.description: т.к. каждую неделю пишет код не 100% времени
§ recommendations.week.upWork.title: Стабильно перерабатывает
§ recommendations.week.upWork.description: т.к. каждую неделю пишет код в выходные дни
§ recommendations.week.task.up.title: Растёт производительность
§ recommendations.week.task.up.description: или задачи стали слишком мелкие. Нужно проверить. Если гранулярность та же - закрепить результат.
§ recommendations.week.task.lazyMaintainer.description: стабильный лидер по прогулам. Уволить?
§ recommendations.week.task.down.title: Падает производительность
§ recommendations.week.task.down.description
или задачи хуже разбивают. Нужно проверить. Если гранулярность та же - взять на контроль.
# Метод оценки:
- количество задач в день, над которыми работают, на протяжении последних трех недель стабильно падает.
# Возможные ошибки:
- задачи могли быть сложнее, чем казались;
- задачи могли иметь большой объём работы (нужно проверить количество изменений, падают они или нет за этот же период)
§ recommendations.type.everyHasOne.title: Не подписывают тип задачи
§ recommendations.type.everyHasOne.description: большинство типов задач делает один человек.
§ recommendations.type.oneMaintainer.title: Узкая специализация
§ recommendations.type.oneMaintainer.description
большинство задач одного типа делают одни и те же люди.
# Типы задач:
§ recommendations.type.common
# Возможно, это не так
Нужно убедиться, что остальные сотрудники верно подписывают коммиты.
Шаги, которые помогут это сделать:
- настроить пре-коммит проверку для commit message;
- объяснить команде, что нужно указывать тип;
- проверить в новых ветках, что сотрудники следуют правилу;
# Если это действительно так
Вы настроили проверки и убедились что один и тот же сотрудник, делает задачи одного и того же типа.
Почему это плохо:
- его увольнение остановит целую пачку процессов;
- уменьшается компетенция остальных членов команды;
- трудно верхнеуровнево понять его правки;
Как это исправить:
- распределять разные типы задач равномерно;
- менять область работы (тесты, документация, ошибки) между сотрудниками через спринт;
§ recommendations.type.fewTypes.title
Это локальный продукт
§ recommendations.type.fewTypes.description
для конкретного заказчика или проблемы.
# Какие признаки есть у «глобального» продукта:
- локализация;
- документация;
- большой объём тестов;
- визуальная кастомизация;
- рефакторинг узких мест;
- и т.п.
# Почему этот продукт выглядит как «локальный»:
- у каждого «глобального» признака будет перевес по своему типу задач;
- чем больше «глобальных» признаков, тем больше вероятность «глобального» продукта;
В данном случае мы видим небольшое число типов, а следовательно, скорее всего есть недоработки, мешающие легко масштабировать продукт на мировой рынок и продавать его в других странах.
# Возможно, это не так
По типам файлов мы можем предположить тип программы (сайт, серверное приложение, 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-а.
`;

View file

@ -0,0 +1,27 @@
export default `
§ 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: Добавить трудовой договор
`;