This commit is contained in:
bakhirev 2024-08-10 17:09:54 +03:00
parent b87d79cff9
commit 407d51c291
34 changed files with 79250 additions and 11 deletions

13
build/asset-manifest.json Normal file
View file

@ -0,0 +1,13 @@
{
"files": {
"main.css": "./static/css/main.1e4b6bfb.css",
"main.js": "./static/js/main.a991d9b4.js",
"index.html": "./index.html",
"main.1e4b6bfb.css.map": "./static/css/main.1e4b6bfb.css.map",
"main.a991d9b4.js.map": "./static/js/main.a991d9b4.js.map"
},
"entrypoints": [
"static/css/main.1e4b6bfb.css",
"static/js/main.a991d9b4.js"
]
}

View file

@ -1 +1 @@
<!doctype html><html><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="default"><meta name="theme-color" content="white"/><meta name="defaultLanguage" content="ru"><meta name="availableLanguages" content="en, es, fr, ja, pt, de, zh, ru"><link rel="canonical" href="https://assayo.online/demo/"><script type="text/javascript">var report=[]</script><script src='./log.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='../log.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='../../log.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='/log.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><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>Git Statistics</title><meta name="description" content="Simple and fast report on git commit history."><meta name="keywords" content="git, statistics, audit, history, log, monitoring, employee control"><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 statistics"><meta name="msapplication-tooltip" content="Simple and fast report on Git commit history."><meta property="og:title" content="Git Statistics"><meta property="og:description" content="Simple and fast report on Git commit history."><meta property="og:image" content="https://assayo.online/assets/seo/custom_icon_256.png"><meta property="og:site_name" content="Assayo"><meta property="og:url" content="https://assayo.online/"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Statistics"><meta name="twitter:description" content="Simple and fast report on Git commit history."><meta name="twitter:creator" content="Bakhirev Aleksei"><meta name="twitter:image:src" content="https://assayo.online/assets/seo/custom_icon_256.png"><meta name="twitter:domain" content="assayo.online"><meta name="twitter:site" content="assayo.online"><meta itemprop="name" content="Git Statistics"><meta itemprop="description" content="Simple and fast report on Git commit history."><meta itemprop="image" content="https://assayo.online/assets/seo/custom_icon_256.png"><script defer="defer" src="./static/index.js"></script><link href="./static/index.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><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="default"><meta name="theme-color" content="white"/><meta name="defaultLanguage" content="ru"><meta name="availableLanguages" content="en, es, fr, ja, pt, de, zh, ru"><link rel="canonical" href="https://assayo.online/demo/"><script type="text/javascript">var report=[]</script><link rel="icon" href="./favicon.svg"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>Git Statistics</title><meta name="description" content="Simple and fast report on git commit history."><meta name="keywords" content="git, statistics, audit, history, log, monitoring, employee control"><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 statistics"><meta name="msapplication-tooltip" content="Simple and fast report on Git commit history."><meta property="og:title" content="Git Statistics"><meta property="og:description" content="Simple and fast report on Git commit history."><meta property="og:image" content="https://assayo.online/assets/seo/custom_icon_256.png"><meta property="og:site_name" content="Assayo"><meta property="og:url" content="https://assayo.online/"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Statistics"><meta name="twitter:description" content="Simple and fast report on Git commit history."><meta name="twitter:creator" content="Bakhirev Aleksei"><meta name="twitter:image:src" content="https://assayo.online/assets/seo/custom_icon_256.png"><meta name="twitter:domain" content="assayo.online"><meta name="twitter:site" content="assayo.online"><meta itemprop="name" content="Git Statistics"><meta itemprop="description" content="Simple and fast report on Git commit history."><meta itemprop="image" content="https://assayo.online/assets/seo/custom_icon_256.png"><script defer="defer" src="./static/js/main.a991d9b4.js"></script><link href="./static/css/main.1e4b6bfb.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

View file

@ -0,0 +1,76 @@
/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @remix-run/router v1.3.1
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router DOM v6.8.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router v6.8.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/

File diff suppressed because one or more lines are too long

78281
build/test.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
import React, { useEffect, useState } from 'react';
import UiKitSelectOption from './Option';
import style from '../styles/index.module.scss';
interface UiKitSelectListProps {
value: any;
options: any;
search?: string;
keyCode?: string;
setKeyCode: Function;
className?: string;
onClick: Function;
}
function UiKitSelectList({
value,
options,
search,
keyCode,
className,
setKeyCode,
onClick,
}: UiKitSelectListProps) {
const [selectedIndex, setSelectedIndex] = useState<number>(-1);
console.log(value);
const searchResult = options
?.filter((option: any) => option.title.indexOf(search) !== -1);
useEffect(() => {
if (!keyCode) return;
if (keyCode === 'down') {
let nextIndex = selectedIndex + 1;
if (nextIndex >= searchResult.length) nextIndex = 0;
setSelectedIndex(nextIndex);
}
if (keyCode === 'up') {
let nextIndex = selectedIndex - 1;
if (nextIndex < 0) nextIndex = searchResult.length - 1;
setSelectedIndex(nextIndex);
}
if (keyCode === 'enter') {
const selected = searchResult[selectedIndex];
onClick(selected, selectedIndex);
}
setKeyCode('');
}, [keyCode]);
useEffect(() => {
setSelectedIndex(-1);
}, [search]);
const items = searchResult?.map((option: any, index: number) => {
return (
<UiKitSelectOption
key={option.id}
focus={index === selectedIndex}
option={option}
className={className}
onClick={() => {
onClick(option.source, index);
}}
/>
);
});
if (!items.length) return null;
return (
<ul className={`${style.ui_kit_select_list} scroll_y ${className || ''}`}>
{items}
</ul>
);
}
export default UiKitSelectList;

View file

@ -0,0 +1,33 @@
import React from 'react';
import style from '../styles/index.module.scss';
interface UiKitSelectOptionProps {
option: any;
focus?: boolean;
className?: string;
onClick: (event: React.MouseEvent<HTMLLIElement, MouseEvent>) => void;
}
function UiKitSelectOption({
option,
focus,
className,
onClick,
}: UiKitSelectOptionProps) {
let localClassName = [style.ui_kit_select_option];
if (className) localClassName.push(className);
if (focus) localClassName.push(style.ui_kit_select_option_focus);
return (
<li
className={localClassName.join(' ')}
onClick={onClick}
>
{option.title}
</li>
);
}
export default UiKitSelectOption;

View file

@ -0,0 +1,74 @@
import React, { useEffect, useRef, useState } from 'react';
import { CLOSE_DELAY } from '../helpers/constants';
import style from '../styles/index.module.scss';
function getKeyCode(key?: string): string {
return {
ArrowUp: 'up',
ArrowDown: 'down',
Enter: 'enter',
}[key || ''] || '';
}
interface UiKitSelectSearchProps {
value: string;
placeholder?: string;
className?: string;
onClose: Function;
onChange: Function;
onKeyDown: Function;
}
function UiKitSelectSearch({
value,
placeholder,
className,
onChange,
onClose,
onKeyDown,
}: UiKitSelectSearchProps) {
const ref = useRef(null);
const [timer, setTimer] = useState<any>(0);
useEffect(() => {
setTimeout(() => {
// @ts-ignore
if (ref?.current) ref.current.focus();
}, CLOSE_DELAY);
}, []);
return (
<input
ref={ref}
type="text"
value={value}
placeholder={placeholder}
className={`${style.ui_kit_select_search} ${className || ''}`}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
clearTimeout(timer);
onChange(event.target.value);
}}
onBlur={() => {
clearTimeout(timer);
const timerId = setTimeout(() => {
onClose();
}, CLOSE_DELAY);
setTimer(timerId);
}}
onFocus={() => {
clearTimeout(timer);
}}
onKeyDown={() => {
// onKeyDown(getKeyCode(event.key));
}}
onKeyUp={(event: React.KeyboardEvent<HTMLInputElement>) => {
onKeyDown(getKeyCode(event.key));
// onKeyDown('');
}}
/>
);
}
export default UiKitSelectSearch;

View file

@ -0,0 +1,28 @@
import React from 'react';
import style from '../styles/index.module.scss';
interface UiKitSelectValueProps {
value: any;
options: any;
className?: string;
onClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
}
function UiKitSelectValue({
value,
className,
onClick,
}: UiKitSelectValueProps) {
return (
<div
className={`${style.ui_kit_select_value} ${className || ''}`}
onClick={onClick}
>
{value}
</div>
);
}
export default UiKitSelectValue;

View file

@ -0,0 +1 @@
export const CLOSE_DELAY = 250;

View file

@ -0,0 +1,49 @@
function getStringFromObject(value: any) {
return value?.title
|| value?.name
|| value?.label
|| value?.description
|| value?.value
|| value?.id
|| value?.uuid
|| value?.key
|| JSON.stringify(value);
}
function getIdFromObject(value: any, index: number) {
return value?.id
?? value?.uuid
?? value?.key
?? index
?? getStringFromObject(value);
}
function getValue(
value: any,
formatter: (a: any, i?: number) => string,
) {
const type = typeof value;
if (type === 'boolean') return value ? 'yes' : 'no';
if (type === 'number' || type === 'string') return value;
if (!value) return '';
return Array.isArray(value)
? value.map(formatter).join(', ')
: formatter(value);
}
export function getTitle(value: any) {
return getValue(value, getStringFromObject);
}
export function getId(value: any, index: number) {
return getValue(value, (v: any) => getIdFromObject(v, index));
}
export function getOption(value: any, index: number) {
return {
id: getId(value, index),
title: getTitle(value),
source: value,
};
}

View file

@ -0,0 +1,78 @@
import React, { useMemo, useState } from 'react';
import UiKitSelectValue from './components/Value';
import UiKitSelectSearch from './components/Search';
import UiKitSelectList from './components/List';
import { getOption, getTitle } from './helpers';
import style from './styles/index.module.scss';
interface UiKitSelectProps {
value: any;
options: any;
className?: string;
onChange?: Function;
}
function UiKitSelect({
value,
options,
className,
onChange,
}: UiKitSelectProps) {
const [openSearch, setOpenSearch] = useState<boolean>(false);
const [search, setSearch] = useState<string>('');
const [keyCode, setKeyCode] = useState<string>('');
const formattedOptions = useMemo(() => options?.map(getOption) || [], [options]);
const formattedValue = useMemo(() => {
const selectedOption = options.find((option: any) => option.id === value);
return getTitle(selectedOption) || getTitle(value);
}, [value]);
return (
<div className={`${style.ui_kit_select_container} ${className || ''}`}>
{!openSearch ? (
<UiKitSelectValue
value={formattedValue}
options={formattedOptions}
className={className}
onClick={() => setOpenSearch(true)}
/>
) : null}
{openSearch ? (
<UiKitSelectSearch
value={search}
placeholder={formattedValue}
className={className}
onChange={setSearch}
onKeyDown={setKeyCode}
onClose={() => {
setSearch('');
setOpenSearch(false);
}}
/>
) : null}
{openSearch ? (
<UiKitSelectList
value={value}
options={formattedOptions}
search={search}
keyCode={keyCode}
setKeyCode={setKeyCode}
className={className}
onClick={(selected: any) => {
setSearch('');
setOpenSearch(false);
if (onChange) onChange(selected?.id);
}}
/>
) : null}
</div>
);
}
export default UiKitSelect;

View file

@ -0,0 +1,67 @@
@import 'src/styles/variables';
.ui_kit_select {
&_value,
&_search,
&_option {
font-size: var(--font-s);
font-weight: 100;
display: inline-block;
width: 100%;
height: 42px;
padding: 0 var(--space-l);
margin: 0;
line-height: 42px;
text-align: left;
box-sizing: border-box;
vertical-align: top;
outline-color: transparent;
border-radius: var(--border-radius-s);
border: 1px solid var(--color-border);
color: var(--color-black);
background-color: var(--color-white);
}
&_container {
position: relative;
}
&_list {
position: absolute;
top: 45px;
left: 0;
right: 0;
z-index: 1;
display: block;
max-height: 300px;
padding: var(--space-xxs) 0;
text-align: left;
border-radius: var(--border-radius-s);
border: 1px solid var(--color-border);
box-shadow: 0 0 5px var(--color-border);
background-color: var(--color-white);
}
&_option {
display: block;
text-align: left;
cursor: pointer;
border-radius: 0;
border: none;
&_focus,
&:hover {
background-color: var(--color-border);
}
}
}
.ui_kit_select_option + .ui_kit_select_option {
border-top: 1px solid var(--color-border);
}

View file

@ -0,0 +1,69 @@
import { observable, action, makeObservable } from 'mobx';
class DataViewStore {
key: string = 'view_settings';
version: number = 1;
settings: any = {};
constructor() {
this.load();
makeObservable(this, {
settings: observable,
load: action,
setItem: action,
});
}
load() {
const settings = JSON.parse(localStorage.getItem(this.key) || '{}') || {};
if (settings.version === this.version) {
this.settings = settings.settings;
}
}
save() {
if (Object.keys(this.settings).length === 0) {
localStorage.removeItem(this.key);
return;
}
localStorage.setItem(this.key, JSON.stringify({
version: this.version,
settings: this.settings,
}));
}
#getPath(path: any): string {
if (!path) return '';
if (Array.isArray(path)) {
return path.join('.');
} else if (typeof path === 'object') {
return [path.type, path.page].join('.');
}
return path;
}
setItem(path: any, value: any, defaultValue?: any) {
const formattedPath = this.#getPath(path);
if (!formattedPath) return;
if (!value || value === defaultValue) {
delete this.settings[formattedPath];
} else {
this.settings[formattedPath] = value;
}
this.save();
}
getItem(path: any, defaultValue?: any): any {
const formattedPath = this.#getPath(path);
return this.settings?.[formattedPath] || defaultValue;
}
}
const dataViewStore = new DataViewStore();
export default dataViewStore;

View file

@ -0,0 +1,52 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import Wrapper, { IUiKitWrapperProps } from './Wrapper';
import style from '../styles/checkbox.module.scss';
interface IUiKitCheckboxProps extends IUiKitWrapperProps {
value: any;
onChange: Function;
}
function UiKitCheckbox({
title,
description,
help,
error,
className,
value,
onChange,
}: IUiKitCheckboxProps) {
const { t } = useTranslation();
const id = `checkbox-${Math.ceil(Math.random() * 10000)}`;
return (
<Wrapper
description={description}
help={help}
error={error}
className={className}
>
<div className={style.ui_kit_checkbox}>
<input
type="checkbox"
id={id}
checked={!!value}
className={style.ui_kit_checkbox_box}
onChange={() => {
onChange(!value);
}}
/>
<label
htmlFor={id}
className={style.ui_kit_checkbox_title}
>
{t(title || '')}
</label>
</div>
</Wrapper>
);
}
export default UiKitCheckbox;

View file

@ -0,0 +1,35 @@
@import 'src/styles/variables';
.ui_kit_checkbox {
position: relative;
display: block;
padding: 0 0 0 32px;
&_box {
position: absolute;
top: 0;
left: 0;
display: block;
width: var(--space-xl);
height: var(--space-xl);
cursor: pointer;
box-shadow: none;
border-radius: var(--border-radius-s);
border: 1px solid var(--color-border);
}
&_title {
font-size: var(--font-s);
font-weight: 100;
display: block;
padding: var(--space-xxxs) 0 0;
cursor: pointer;
white-space: normal;
color: var(--color-black);
}
}

View file

@ -0,0 +1,21 @@
import IHashMap from 'ts/interfaces/HashMap';
export default class FakeName {
refOldNewName: IHashMap<string> = {};
dictionary: string[] = [];
index: number = 0;
constructor(dictionary: string[]) {
this.dictionary = dictionary;
}
get(name: string) {
if (!this.refOldNewName[name]) {
this.refOldNewName[name] = this.dictionary[this.index] || `${Math.random()}`;
this.index += 1;
}
return this.refOldNewName[name];
}
}

View file

@ -0,0 +1,111 @@
export const FAKE_AUTHORS = [
'Fyodor Dostoevsky',
'Dante Alighieri',
'Lev Tolstoy',
'Victor Hugo',
'William Shakespeare',
'Johann Wolfgang von Goethe',
'Miguel de Cervantes y Saavedra',
'Italo Calvino',
'Stendhal',
'Charles Baudelaire',
'Marcel Proust',
'Giovanni Boccaccio',
'Alexander Pushkin',
'Jalaluddin Muhammad Rumi',
'Franz Kafka',
'Anton Chekhov',
'Gabriel García Márquez',
'Umberto Eco',
'J.R.R. Tolkien',
'William Faulkner',
'Aesop',
'Arthur Rimbaud',
'Aristophanes',
'Ivan Turgenev',
'Sophocles',
'Molière',
'Charles Dickens',
'Maxim Gorky',
'George Orwell',
'Edgar Allan Poe',
'Publius Vergilius Maro',
'Julio Cortázar',
'Nazim Hikmet',
'Oscar Wilde',
'Jean de La Fontaine',
'Rainer Maria Rilke',
'Lord Byron',
'Hans Christian Andersen',
'Thomas Mann',
'Alexandre Dumas',
'James Joyce',
'Louis-Ferdinand Céline',
'Boris Pasternak',
'Federico García Lorca',
'Pablo Neruda',
'Borges',
'Beaumarchais',
'Naguib Mahfouz',
'Ursula K. Le Guin',
'Nikolay Gogol',
'Honoré de Balzac',
'Ernest Hemingway',
'Neil Gaiman',
'Jean Racine',
'Albert Camus',
'Jean-Paul Sartre',
'Chingiz Aitmatov',
'John Steinbeck',
'Milan Kundera',
'Jules Verne',
'Mark Twain',
'Francois Rabelais',
'Yasar Kemal',
'George Bernard Shaw',
'Arthur Conan Doyle',
'Jane Austen',
'Geoffrey Chaucer',
'Antoine de Saint-Exupéry',
'Erich Maria Remarque',
'J.D. Salinger',
'Virginia Woolf',
'Louis Aragon',
'Herman Melville',
'Alphonse Daudet',
'Mikhail Sholokhov',
'Stefan Zweig',
'José Saramago',
'Bertolt Brecht',
'Mario Vargas Llosa',
'T.S. Eliot',
'Guy de Maupassant',
'John Keats',
'Sabahattin Ali',
'Ahmet Hamdi Tanpinar',
'John Fante',
'Henri-Frédéric Blanc',
'Isaac Asimov',
'Fitzgerald Scott',
'J.M. Coetzee',
'Kazuo Ishiguro',
'Hermann Hesse',
'Robert Louis Stevenson',
'Salman Rushdie',
'Mario Vargas Llosa',
'Aldous Huxley',
'Paul Valéry',
'Thomas Pynchon',
'H.P. Lovecraft',
'Haruki Murakami',
'Nikos Kazantzakis',
];
export const FAKE_EMAILS = FAKE_AUTHORS
.map((name: string, index: number) => (
name.replace(/([\s.]+)|([^A-Za-z]+)/gim, '-').toLowerCase() + index + '@yahoo.com'
));
export const FAKE_TASK_PREFIXES = 'axeurtyqwpsdfghjklzcvbnm'
.split('')
.map((symbol) => (new Array(5)).fill(symbol.toUpperCase()).join(''));

View file

@ -0,0 +1,60 @@
import ICommit, { ISystemCommit } from 'ts/interfaces/Commit';
import {
FAKE_AUTHORS,
FAKE_EMAILS,
FAKE_TASK_PREFIXES,
} from './constants';
import FakeName from './FakeName';
export default class Depersonalized {
fakeName: any = null;
fakeEmail: any = null;
fakeTaskPrefix: any = null;
constructor() {
this.fakeName = new FakeName(FAKE_AUTHORS);
this.fakeEmail = new FakeName(FAKE_EMAILS);
this.fakeTaskPrefix = new FakeName(FAKE_TASK_PREFIXES);
}
getCommit(commit: ICommit | ISystemCommit): ICommit | ISystemCommit {
const author = this.fakeName.get(commit.author);
const email = this.fakeEmail.get(commit.author);
if (!commit.task) {
return {
...commit,
author,
email,
};
}
const taskPrefix = commit.task.split(/[-_\s:#=]+/gim).shift() || '';
const newTaskPrefix = this.fakeTaskPrefix.get(taskPrefix);
const task = commit.task.replace(taskPrefix, newTaskPrefix);
const message = commit.message.replace(taskPrefix, newTaskPrefix);
// @ts-ignore
const branch = commit.branch // @ts-ignore
? commit.branch.replace(taskPrefix, newTaskPrefix)
: undefined;
// @ts-ignore
const toBranch = commit.toBranch// @ts-ignore
? commit.toBranch.replace(taskPrefix, newTaskPrefix)
: undefined;
return {
...commit,
task,
message,
author,
email,
branch,
toBranch,
};
}
}

View file

@ -3,9 +3,11 @@ import { observer } from 'mobx-react-lite';
import { useTranslation } from 'react-i18next';
import InputString from 'ts/components/UiKit/components/InputString';
import Select from 'ts/components/UiKit/components/Select';
import UiKitSelect from 'ts/components/UiKit/components/Select';
import UiKitCheckbox from 'ts/components/UiKit/components/Checkbox';
import PageBox from 'ts/components/Page/Box';
import Title from 'ts/components/Title';
import dataGripStore from 'ts/store/DataGrip';
import localization from 'ts/helpers/Localization';
import { applicationHasCustom } from 'ts/helpers/RPC';
@ -32,7 +34,7 @@ const Common = observer((): React.ReactElement | null => {
applicationHasCustom.title = true;
}}
/>
<Select
<UiKitSelect
title="page.settings.document.language"
value={language}
options={[
@ -50,6 +52,13 @@ const Common = observer((): React.ReactElement | null => {
setLanguage(id);
}}
/>
<UiKitCheckbox
value={dataGripStore.isDepersonalized}
title="page.settings.document.depersonalize"
onChange={() => {
dataGripStore.depersonalized(!dataGripStore.isDepersonalized);
}}
/>
</PageBox>
</>
);

View file

@ -10,6 +10,7 @@ import getTitle from 'ts/helpers/Title';
import { setDefaultValues } from 'ts/pages/Settings/helpers/getEmptySettings';
import { applicationHasCustom } from 'ts/helpers/RPC';
import Depersonalized from 'ts/helpers/Depersonalized';
import filtersInHeaderStore from './FiltersInHeader';
@ -24,6 +25,7 @@ interface IDataGripStore {
dataGrip: any;
fileGrip: any;
status: DataParseStatusEnum;
isDepersonalized: boolean;
setCommits: (log?: string[]) => void;
}
@ -36,6 +38,8 @@ class DataGripStore implements IDataGripStore {
hash: number = 0;
isDepersonalized: boolean = false;
status: DataParseStatusEnum = DataParseStatusEnum.PROCESSING;
constructor() {
@ -43,8 +47,10 @@ class DataGripStore implements IDataGripStore {
commits: observable,
dataGrip: observable,
hash: observable,
isDepersonalized: observable,
status: observable,
setCommits: action,
depersonalized: action,
updateStatistic: action,
});
}
@ -88,15 +94,31 @@ class DataGripStore implements IDataGripStore {
}
}
depersonalized(status?: boolean) {
this.isDepersonalized = !!status;
setTimeout(() => {
this.updateStatistic();
}, 100);
}
updateStatistic() {
dataGrip.clear();
fileGrip.clear();
const depersonalized = new Depersonalized();
this.commits.forEach((commit: ICommit | ISystemCommit) => {
if (commit.timestamp < filtersInHeaderStore.from
|| commit.timestamp > filtersInHeaderStore.to) return;
dataGrip.addCommit(commit);
fileGrip.addCommit(commit);
const localCommit = this.isDepersonalized
? depersonalized.getCommit(commit)
: commit;
dataGrip.addCommit(localCommit);
fileGrip.addCommit(localCommit);
});
console.log(depersonalized.fakeTaskPrefix);
fileGrip.updateTotalInfo();
dataGrip.updateTotalInfo();
achievements.updateByGrip(dataGrip, fileGrip);

View file

@ -0,0 +1,71 @@
import { makeObservable, observable, action } from 'mobx';
import { ONE_DAY } from 'ts/helpers/formatter';
import ICommit from '../interfaces/Commit';
interface IFiltersInHeaderStore {
defaultFrom: string;
defaultTo: string;
from: string;
to: string;
updateByCommits: (firstCommit: ICommit, lastCommit: ICommit) => void,
setFilterByDateType: (type: string) => void,
}
class FiltersInHeaderStore implements IFiltersInHeaderStore {
defaultFrom: string = ''; // "2021-02-09"
defaultTo: string = ''; // "2021-02-09"
from: string = ''; // "2021-02-09"
to: string = ''; // "2021-02-09"
lastCommitTime: number = 0; // 1612828800000
constructor() {
makeObservable(this, {
defaultFrom: observable,
defaultTo: observable,
from: observable,
to: observable,
updateByCommits: action,
setFilterByDateType: action,
updateProperty: action,
});
}
updateByCommits(firstCommit: ICommit, lastCommit: ICommit) {
this.defaultFrom = firstCommit.timestamp;
this.defaultTo = lastCommit.timestamp;
this.from = this.defaultFrom;
this.to = this.defaultTo;
this.lastCommitTime = (new Date(this.defaultTo)).getTime();
}
setFilterByDateType(type: string) {
const count = {
year: 365,
halfYear: 183,
month: 30,
week: 7,
day: 1,
}[type];
this.from = count
? (new Date(this.lastCommitTime - ONE_DAY * count)).toISOString().split('T')[0]
: this.defaultFrom;
this.to = this.defaultTo;
}
updateProperty(propertyName: string, value?: any) {
this[propertyName] = value ?? null;
}
}
const filtersInHeaderStore = new FiltersInHeaderStore();
export default filtersInHeaderStore;

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Настройки отображения
§ page.settings.document.name: Заголовок страницы
§ page.settings.document.language: Язык интерфейса
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Префиксы ссылок
§ page.settings.links.task: Для номеров задач
§ page.settings.links.pr: Для PR
@ -24,4 +25,4 @@ export default `
§ page.settings.form.remove: Удалить
§ page.settings.form.addEmployee: Добавить сотрудника
§ page.settings.form.addContract: Добавить трудовой договор
`;
`;

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Настройки отображения
§ page.settings.document.name: Заголовок страницы
§ page.settings.document.language: Язык интерфейса
§ page.settings.document.depersonalize: Деперсонализировать данные
§ page.settings.links.title: Префиксы ссылок
§ page.settings.links.task: Для номеров задач
§ page.settings.links.pr: Для PR

View file

@ -2,6 +2,7 @@ export default `
§ page.settings.document.title: Display settings
§ page.settings.document.name: Page title
§ page.settings.document.language: Interface language
§ page.settings.document.depersonalize: Depersonalize the data
§ page.settings.links.title: Link prefixes
§ page.settings.links.task: For task numbers
§ page.settings.links.pr: For PR