This commit is contained in:
bakhirev 2024-10-26 01:26:53 +03:00
parent 05a3874efd
commit d8b49a579b
15 changed files with 211 additions and 95 deletions

View file

@ -29,10 +29,11 @@ class SponsorStore {
const ONE_MINUTE = 60 * 1000; const ONE_MINUTE = 60 * 1000;
setInterval(() => { setInterval(() => {
if (this.type) return; if (this.type) return;
this.type = Math.random() > 0.5 this.type = MODAL_TYPE.SHARE;
? MODAL_TYPE.MONEY // Math.random() > 0.5
: MODAL_TYPE.SHARE; // ? MODAL_TYPE.MONEY
}, 10 * ONE_MINUTE); // : MODAL_TYPE.SHARE;
}, 7 * ONE_MINUTE);
} }
open() { open() {

View file

@ -1,7 +1,4 @@
import React from 'react'; import React from 'react';
import { observer } from 'mobx-react-lite';
import dataGripStore from 'ts/store/DataGrip';
import PageWrapper from 'ts/components/Page/wrapper'; import PageWrapper from 'ts/components/Page/wrapper';
import getOptions from 'ts/components/LineChart/helpers/getOptions'; import getOptions from 'ts/components/LineChart/helpers/getOptions';
@ -25,18 +22,23 @@ function getTimeZoneChart(authors: any[]) {
increment(acc, author.lastCommit.timezone.replace(':', '.')); increment(acc, author.lastCommit.timezone.replace(':', '.'));
return acc; return acc;
}, {}); }, {});
const options = getOptions({ const options = getOptions({
order: Object.keys(details).sort(), order: Object.keys(details).sort(),
limit: 5, limit: 5,
suffix: 'page.team.country.chart.item', suffix: 'page.team.country.chart.item',
}); });
return [options, details]; return [options, details];
} }
const PieCharts = observer((): React.ReactElement | null => { interface PieChartsProps {
const authors = dataGripStore.dataGrip.author.statistic; authors: any[];
const rows = dataGripStore.dataGrip.country.statistic; countries: any[];
const [countryOptions, countryDetails] = getCountryChart(rows); }
function PieCharts({ authors, countries }: PieChartsProps): React.ReactElement | null {
const [countryOptions, countryDetails] = getCountryChart(countries);
const [timezoneOptions, timezoneDetails] = getTimeZoneChart(authors); const [timezoneOptions, timezoneDetails] = getTimeZoneChart(authors);
return ( return (
@ -57,6 +59,6 @@ const PieCharts = observer((): React.ReactElement | null => {
</PageColumn> </PageColumn>
</PageWrapper> </PageWrapper>
); );
}); }
export default PieCharts; export default PieCharts;

View file

@ -0,0 +1,68 @@
import React, { useMemo } from 'react';
import { observer } from 'mobx-react-lite';
import dataGripStore from 'ts/store/DataGrip';
import SelectWithButtons from 'ts/components/UiKit/components/SelectWithButtons';
import UiKitCheckbox from 'ts/components/UiKit/components/Checkbox';
import Title from 'ts/components/Title';
import IFilters from '../interfaces/Filters';
import { getOptions } from '../helpers';
import style from '../styles/index.module.scss';
interface FiltersProps {
filters: IFilters,
onChange: Function;
}
const Filters = observer(({
filters,
onChange,
}: FiltersProps) => {
const companies = dataGripStore.dataGrip.company.statistic;
const companyOptions = useMemo(() => getOptions(companies), companies);
const update = (property: string, value: any) => {
onChange({
...filters,
[property]: value,
hash: Math.random(),
});
};
return (
<>
<Title title="common.filters"/>
<div className={style.team_country_filter}>
<SelectWithButtons
title="page.team.tree.filters.author"
className={style.team_country_filter_select}
value={filters.company}
options={companyOptions}
onChange={(company: string) => update('company', company)}
/>
<UiKitCheckbox
title="page.team.country.filters.active"
className={style.team_country_filter_checkbox}
value={filters.isActive}
onChange={() => update('isActive', !filters.isActive)}
/>
<UiKitCheckbox
title="page.team.country.filters.dismissed"
className={style.team_country_filter_checkbox}
value={filters.isDismissed}
onChange={() => update('isDismissed', !filters.isDismissed)}
/>
<UiKitCheckbox
title="page.team.country.filters.staff"
className={style.team_country_filter_checkbox}
value={filters.isStaff}
onChange={() => update('isStaff', !filters.isStaff)}
/>
</div>
</>
);
});
export default Filters;

View file

@ -1,77 +1,20 @@
import React, { useMemo, useState } from 'react'; import React from 'react';
import { observer } from 'mobx-react-lite';
import dataGripStore from 'ts/store/DataGrip';
import SelectWithButtons from 'ts/components/UiKit/components/SelectWithButtons';
import UiKitCheckbox from 'ts/components/UiKit/components/Checkbox';
import TimeZoneMap from 'ts/components/TimeZoneMap'; import TimeZoneMap from 'ts/components/TimeZoneMap';
import PageWrapper from 'ts/components/Page/Box'; import PageWrapper from 'ts/components/Page/Box';
import Title from 'ts/components/Title'; import Title from 'ts/components/Title';
import { t } from 'ts/helpers/Localization';
import style from '../../../styles/country.module.scss'; interface CustomMapProps {
authors: any[];
function getOptions(companies: any[]) {
const options = companies.map((item: any) => ({ id: item.company, title: item.company }));
return [
{ id: '', title: t('page.common.filter.allUsers') },
{ id: Math.random(), title: 'Unknown' },
...options,
];
} }
const CustomMap = observer(() => { function CustomMap({ authors }: CustomMapProps) {
const companies = dataGripStore.dataGrip.company.statistic;
const companyOptions = useMemo(() => getOptions(companies), companies);
const [company, setCompany] = useState<string>('');
const [isStaff, setIsStaff] = useState<boolean>(true);
const [isActive, setIsActive] = useState<boolean>(true);
const [isDismissed, setIsDismissed] = useState<boolean>(true);
const authors = dataGripStore.dataGrip.author.statistic
.filter((author: any) => {
if (company && author.lastCompany !== company) return false;
if (!isStaff && author.isStaff) return false;
if (!isActive && !author.isDismissed && !author.isStaff) return false;
if (!isDismissed && author.isDismissed && !author.isStaff) return false;
return true;
});
return ( return (
<PageWrapper> <PageWrapper>
<Title title="page.team.country.byTimezone"/> <Title title="page.team.country.byTimezone"/>
<TimeZoneMap authors={authors}/> <TimeZoneMap authors={authors}/>
<div className={style.team_country_filter}>
<UiKitCheckbox
title="page.team.country.filters.active"
className={style.team_country_filter_checkbox}
value={isActive}
onChange={() => setIsActive(!isActive)}
/>
<UiKitCheckbox
title="page.team.country.filters.dismissed"
className={style.team_country_filter_checkbox}
value={isDismissed}
onChange={() => setIsDismissed(!isDismissed)}
/>
<UiKitCheckbox
title="page.team.country.filters.staff"
className={style.team_country_filter_checkbox}
value={isStaff}
onChange={() => setIsStaff(!isStaff)}
/>
<SelectWithButtons
title="page.team.tree.filters.author"
className={style.team_country_filter_select}
value={company}
options={companyOptions}
onChange={(id: string) => setCompany(id)}
/>
</div>
</PageWrapper> </PageWrapper>
); );
}); }
export default CustomMap; export default CustomMap;

View file

@ -0,0 +1,48 @@
import { t } from 'ts/helpers/Localization';
import IFilters from '../interfaces/Filters';
export function getOptions(companies: any[]) {
const options = companies.map((item: any) => ({ id: item.company, title: item.company }));
return [
{ id: '', title: t('page.common.filter.allUsers') },
{ id: Math.random(), title: 'Unknown' },
...options,
];
}
export function getDefaultFilters(): IFilters {
return {
hash: Math.random(),
isActive: true,
isDismissed: true,
isStaff: true,
company: '',
};
}
export function getFilterForAuthors(filters: IFilters) {
return (author: any) => {
if (filters.company && author.lastCompany !== filters.company) return false;
if (!filters.isStaff && author.isStaff) return false;
if (!filters.isActive && !author.isDismissed && !author.isStaff) return false;
if (!filters.isDismissed && author.isDismissed && !author.isStaff) return false;
return true;
};
}
export function getCountryByAuthors(authors: any[]) {
const isCorrectAuthor = authors.reduce((acc: any, item: any) => {
acc.set(item.author, true);
return acc;
}, new Map());
return (item: any) => {
const employments = item.employments
.filter((name: string) => isCorrectAuthor.has(name));
return employments.length
? ({ ...item, employments })
: null;
};
}

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { useMemo, useState } from 'react';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import ISort from 'ts/interfaces/Sort'; import ISort from 'ts/interfaces/Sort';
@ -15,28 +15,56 @@ import Countries from './components/Countries';
import CountryCharts from './components/Charts'; import CountryCharts from './components/Charts';
import fullScreen from 'ts/store/FullScreen'; import fullScreen from 'ts/store/FullScreen';
import CustomMap from './components/Map'; import IFilters from './interfaces/Filters';
import Filters from './components/Filters';
import Travel from './components/Travel'; import Travel from './components/Travel';
import CustomMap from './components/Map';
import { getCountryByAuthors, getDefaultFilters, getFilterForAuthors } from './helpers';
const Country = observer(({ const Country = observer(({
mode, mode,
}: ICommonPageProps): React.ReactElement | null => { }: ICommonPageProps): React.ReactElement | null => {
const authors = dataGripStore.dataGrip.author.statistic; const [filters, setFilters] = useState<IFilters>(getDefaultFilters());
const countryRows = dataGripStore.dataGrip.country.statistic;
const travel = authors.filter((dot: any) => dot?.country?.length) const dataGripAuthors = dataGripStore.dataGrip.author.statistic;
.sort((a: any, b: any) => b?.country?.length - a?.country?.length); const authors = useMemo(() => (
dataGripAuthors.filter(getFilterForAuthors(filters))
), [dataGripAuthors, filters.hash]);
const dataGripCountries = dataGripStore.dataGrip.country.statistic;
const countries = useMemo(() => (
dataGripCountries.map(getCountryByAuthors(authors)).filter((v: any) => v)
), [dataGripCountries, filters.hash]);
const travel = useMemo(() => (
authors
.filter((dot: any) => dot?.country?.length)
.sort((a: any, b: any) => b?.country?.length - a?.country?.length)
), [authors, filters.hash]);
const canShowByCountries = (!fullScreen.isOpen || fullScreen.mode === 'countries'); const canShowByCountries = (!fullScreen.isOpen || fullScreen.mode === 'countries');
const canShowByTravel = (!fullScreen.isOpen || fullScreen.mode === 'travel') && travel.length; const canShowByTravel = (!fullScreen.isOpen || fullScreen.mode === 'travel') && travel.length;
if (!countryRows?.length) { if (!countries?.length) {
return mode !== 'print' ? (<NothingFound/>) : null; return mode !== 'print' ? (<NothingFound/>) : null;
} }
return ( return (
<> <>
{!fullScreen.isOpen && <CustomMap />} {!fullScreen.isOpen && (
{!fullScreen.isOpen && <CountryCharts />} <>
<Filters
filters={filters}
onChange={setFilters}
/>
<CustomMap authors={authors} />
<CountryCharts
authors={authors}
countries={countries}
/>
</>
)}
{canShowByCountries ? ( {canShowByCountries ? (
<> <>
@ -44,13 +72,13 @@ const Country = observer(({
<DataLoader <DataLoader
to="response" to="response"
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
content: countryRows, pagination, sort, mode, content: countries, pagination, sort, mode,
})} })}
watch={`${mode}${dataGripStore.hash}`} watch={`${mode}${dataGripStore.hash}${filters.hash}`}
> >
<Countries <Countries
mode={mode} mode={mode}
rowsForExcel={countryRows} rowsForExcel={countries}
/> />
<Pagination/> <Pagination/>
</DataLoader> </DataLoader>
@ -65,11 +93,11 @@ const Country = observer(({
loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({ loader={(pagination?: IPaginationRequest, sort?: ISort[]) => getFakeLoader({
content: travel, pagination, sort, mode, content: travel, pagination, sort, mode,
})} })}
watch={`${mode}${dataGripStore.hash}`} watch={`${mode}${dataGripStore.hash}${filters.hash}`}
> >
<Travel <Travel
mode={mode} mode={mode}
rowsForExcel={countryRows} rowsForExcel={countries}
/> />
<Pagination/> <Pagination/>
</DataLoader> </DataLoader>

View file

@ -0,0 +1,10 @@
interface IFilters {
company: string;
isStaff: boolean;
isActive: boolean;
isDismissed: boolean;
hash: number;
}
export default IFilters;

View file

@ -0,0 +1,16 @@
@import 'src/styles/variables';
.team_country_filter {
margin: 0 0 var(--space-xxl);
&_checkbox,
&_select {
display: inline-block;
margin-right: var(--space-xxl);
vertical-align: middle;
}
&_select {
min-width: 350px;
}
}

View file

@ -287,7 +287,7 @@ will be marked as a jump in "deleted" and "added" lines.
§ page.person.week.workDay: weekdays § page.person.week.workDay: weekdays
§ page.person.week.weekends: weekends § page.person.week.weekends: weekends
§ page.sponsor.title: Please, support this project § page.sponsor.title: Please, support this project
§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. § page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Copy the link § page.sponsor.share.button: Copy the link
§ page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project.
§ page.sponsor.money.qr: One-time payment (only Russia) § page.sponsor.money.qr: One-time payment (only Russia)

View file

@ -289,7 +289,7 @@ will be marked as a jump in "deleted" and "added" lines.
§ page.person.week.workDay: weekdays § page.person.week.workDay: weekdays
§ page.person.week.weekends: weekends § page.person.week.weekends: weekends
§ page.sponsor.title: Please, support this project § page.sponsor.title: Please, support this project
§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. § page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Copy the link § page.sponsor.share.button: Copy the link
§ page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project.
§ page.sponsor.money.qr: One-time payment (only Russia) § page.sponsor.money.qr: One-time payment (only Russia)

View file

@ -287,7 +287,7 @@ git puede Mostrar una pequeña cantidad de cambios en las estadísticas, y el re
§ page.person.week.workDay: entresemana § page.person.week.workDay: entresemana
§ page.person.week.weekends: día de descanso § page.person.week.weekends: día de descanso
§ page.sponsor.title: Please, support this project § page.sponsor.title: Please, support this project
§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. § page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Copy the link § page.sponsor.share.button: Copy the link
§ page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project.
§ page.sponsor.money.qr: One-time payment (only Russia) § page.sponsor.money.qr: One-time payment (only Russia)

View file

@ -286,7 +286,7 @@ export default `
§ page.person.week.workDay: jours de semaine § page.person.week.workDay: jours de semaine
§ page.person.week.weekends: congés § page.person.week.weekends: congés
§ page.sponsor.title: Please, support this project § page.sponsor.title: Please, support this project
§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. § page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Copy the link § page.sponsor.share.button: Copy the link
§ page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project.
§ page.sponsor.money.qr: One-time payment (only Russia) § page.sponsor.money.qr: One-time payment (only Russia)

View file

@ -289,7 +289,7 @@ will be marked as a jump in "deleted" and "added" lines.
§ page.person.week.workDay: weekdays § page.person.week.workDay: weekdays
§ page.person.week.weekends: weekends § page.person.week.weekends: weekends
§ page.sponsor.title: Please, support this project § page.sponsor.title: Please, support this project
§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. § page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Copy the link § page.sponsor.share.button: Copy the link
§ page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project.
§ page.sponsor.money.qr: One-time payment (only Russia) § page.sponsor.money.qr: One-time payment (only Russia)

View file

@ -289,7 +289,7 @@ will be marked as a jump in "deleted" and "added" lines.
§ page.person.week.workDay: weekdays § page.person.week.workDay: weekdays
§ page.person.week.weekends: weekends § page.person.week.weekends: weekends
§ page.sponsor.title: Please, support this project § page.sponsor.title: Please, support this project
§ page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or make a video review. § page.sponsor.share.description: Tell about our [project|https://github.com/bakhirev/assayo] on social networks! You can share [article|https://habr.com/ru/articles/763342/], [post|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] or [video|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Copy the link § page.sponsor.share.button: Copy the link
§ page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project. § page.sponsor.money.description: We will be glad if you support us with any amount! All funds will be used for the further development of the project.
§ page.sponsor.money.qr: One-time payment (only Russia) § page.sponsor.money.qr: One-time payment (only Russia)

View file

@ -289,7 +289,7 @@ git может показать малое количество изменени
§ page.person.week.workDay: будни § page.person.week.workDay: будни
§ page.person.week.weekends: выходные § page.person.week.weekends: выходные
§ page.sponsor.title: Поддержите проект § page.sponsor.title: Поддержите проект
§ page.sponsor.share.description: Расскажите о нашем [проекте|https://github.com/bakhirev/assayo] в соцсетях! Можно поделиться [статьей|https://habr.com/ru/articles/763342/], [постом|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] или сделать видео-обзор. § page.sponsor.share.description: Расскажите о нашем [проекте|https://github.com/bakhirev/assayo] в соцсетях! Можно поделиться [статьей|https://habr.com/ru/articles/763342/], [постом|https://www.reddit.com/r/ITManagers/comments/1e5k291/the_visualization_and_analysis_of_git_commit/] или [видео|https://www.youtube.com/watch?v=jwCp_-bhrCQ].
§ page.sponsor.share.button: Копировать ссылку § page.sponsor.share.button: Копировать ссылку
§ page.sponsor.money.description: Мы будем рады, если вы поддержите нас любой суммой! Все средства пойдут на дальнейшее развитие проекта. § page.sponsor.money.description: Мы будем рады, если вы поддержите нас любой суммой! Все средства пойдут на дальнейшее развитие проекта.
§ page.sponsor.money.qr: Разовый платёж (СБП) § page.sponsor.money.qr: Разовый платёж (СБП)