mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
removed boris reducer
This commit is contained in:
parent
77af1ab05a
commit
120bf8954c
72 changed files with 225 additions and 298 deletions
16
src/api/boris/index.ts
Normal file
16
src/api/boris/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { API } from '~/constants/api';
|
||||||
|
import { api, cleanResult } from '~/utils/api';
|
||||||
|
import { IGetGithubIssuesResult, StatBackend } from '~/types/boris';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export const getBorisBackendStats = () =>
|
||||||
|
api.get<StatBackend>(API.BORIS.GET_BACKEND_STATS).then(cleanResult);
|
||||||
|
|
||||||
|
export const getGithubIssues = () => {
|
||||||
|
return axios
|
||||||
|
.get<IGetGithubIssuesResult>(API.BORIS.GITHUB_ISSUES, {
|
||||||
|
params: { state: 'all', sort: 'created' },
|
||||||
|
})
|
||||||
|
.then(result => result.data)
|
||||||
|
.catch(() => []);
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
import { api, cleanResult } from '~/utils/api';
|
import { api, cleanResult } from '~/utils/api';
|
||||||
import { IComment, INode } from '../types';
|
import { IComment, INode } from '~/redux/types';
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
import { COMMENTS_DISPLAY } from './constants';
|
import { COMMENTS_DISPLAY } from '~/constants/node';
|
||||||
import {
|
import {
|
||||||
ApiDeleteNodeTagsRequest,
|
ApiDeleteNodeTagsRequest,
|
||||||
ApiDeleteNodeTagsResult,
|
ApiDeleteNodeTagsResult,
|
||||||
|
@ -23,7 +23,7 @@ import {
|
||||||
ApiPostNodeTagsResult,
|
ApiPostNodeTagsResult,
|
||||||
GetNodeDiffRequest,
|
GetNodeDiffRequest,
|
||||||
GetNodeDiffResult,
|
GetNodeDiffResult,
|
||||||
} from '~/redux/node/types';
|
} from '~/types/node';
|
||||||
import axios, { AxiosRequestConfig } from 'axios';
|
import axios, { AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
export type ApiPostNodeRequest = { node: INode };
|
export type ApiPostNodeRequest = { node: INode };
|
|
@ -5,16 +5,17 @@ import { BorisContacts } from '~/components/boris/BorisContacts';
|
||||||
import { BorisStats } from '~/components/boris/BorisStats';
|
import { BorisStats } from '~/components/boris/BorisStats';
|
||||||
import { Group } from '~/components/containers/Group';
|
import { Group } from '~/components/containers/Group';
|
||||||
import { IUser } from '~/redux/auth/types';
|
import { IUser } from '~/redux/auth/types';
|
||||||
import { BorisUsageStats } from '~/redux/boris/reducer';
|
import { BorisUsageStats } from '~/types/boris';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: IUser;
|
user: IUser;
|
||||||
isTester: boolean;
|
isTester: boolean;
|
||||||
stats: BorisUsageStats;
|
stats: BorisUsageStats;
|
||||||
setBetaTester: (val: boolean) => void;
|
setBetaTester: (val: boolean) => void;
|
||||||
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BorisSidebar: FC<Props> = ({ user, stats, isTester, setBetaTester }) => (
|
const BorisSidebar: FC<Props> = ({ user, stats, isLoading, isTester, setBetaTester }) => (
|
||||||
<Group className={styles.stats__container}>
|
<Group className={styles.stats__container}>
|
||||||
<div className={styles.super_powers}>
|
<div className={styles.super_powers}>
|
||||||
{user.is_user && <BorisSuperpowers active={isTester} onChange={setBetaTester} />}
|
{user.is_user && <BorisSuperpowers active={isTester} onChange={setBetaTester} />}
|
||||||
|
@ -23,7 +24,7 @@ const BorisSidebar: FC<Props> = ({ user, stats, isTester, setBetaTester }) => (
|
||||||
<BorisContacts />
|
<BorisContacts />
|
||||||
|
|
||||||
<div className={styles.stats__wrap}>
|
<div className={styles.stats__wrap}>
|
||||||
<BorisStats stats={stats} />
|
<BorisStats stats={stats} isLoading={isLoading} />
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { BorisUsageStats } from '~/redux/boris/reducer';
|
import { BorisUsageStats } from '~/types/boris';
|
||||||
import { BorisStatsGit } from '../BorisStatsGit';
|
import { BorisStatsGit } from '../BorisStatsGit';
|
||||||
import { BorisStatsBackend } from '../BorisStatsBackend';
|
import { BorisStatsBackend } from '../BorisStatsBackend';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
stats: BorisUsageStats;
|
stats: BorisUsageStats;
|
||||||
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BorisStats: FC<IProps> = ({ stats }) => {
|
const BorisStats: FC<IProps> = ({ stats, isLoading }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BorisStatsBackend stats={stats} />
|
<BorisStatsBackend stats={stats.backend} isLoading={isLoading} />
|
||||||
<BorisStatsGit stats={stats} />
|
<BorisStatsGit issues={stats.issues} isLoading={isLoading} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,72 +1,73 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { IBorisState } from '~/redux/boris/reducer';
|
import { StatBackend } from '~/types/boris';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { sizeOf } from '~/utils/dom';
|
import { sizeOf } from '~/utils/dom';
|
||||||
import { StatsRow } from '~/components/common/StatsRow';
|
import { StatsRow } from '~/components/common/StatsRow';
|
||||||
import { SubTitle } from '~/components/common/SubTitle';
|
import { SubTitle } from '~/components/common/SubTitle';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
stats: IBorisState['stats'];
|
stats: StatBackend;
|
||||||
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BorisStatsBackend: FC<IProps> = ({ stats: { is_loading, backend } }) => {
|
const BorisStatsBackend: FC<IProps> = ({ isLoading, stats }) => {
|
||||||
if (!backend && !is_loading) {
|
if (!stats && !isLoading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrap}>
|
<div className={styles.wrap}>
|
||||||
<SubTitle isLoading={is_loading} className={styles.title}>
|
<SubTitle isLoading={isLoading} className={styles.title}>
|
||||||
Юнитс
|
Юнитс
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<StatsRow isLoading={is_loading} label="В сознании">
|
<StatsRow isLoading={isLoading} label="В сознании">
|
||||||
{backend.users.alive}
|
{stats.users.alive}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
|
||||||
<StatsRow isLoading={is_loading} label="Криокамера">
|
<StatsRow isLoading={isLoading} label="Криокамера">
|
||||||
{backend.users.total - backend.users.alive}
|
{stats.users.total - stats.users.alive}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<SubTitle isLoading={is_loading} className={styles.title}>
|
<SubTitle isLoading={isLoading} className={styles.title}>
|
||||||
Контент
|
Контент
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<StatsRow isLoading={is_loading} label="Фотографии">
|
<StatsRow isLoading={isLoading} label="Фотографии">
|
||||||
{backend.nodes.images}
|
{stats.nodes.images}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
|
||||||
<StatsRow isLoading={is_loading} label="Письма">
|
<StatsRow isLoading={isLoading} label="Письма">
|
||||||
{backend.nodes.texts}
|
{stats.nodes.texts}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
|
||||||
<StatsRow isLoading={is_loading} label="Видеозаписи">
|
<StatsRow isLoading={isLoading} label="Видеозаписи">
|
||||||
{backend.nodes.videos}
|
{stats.nodes.videos}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
|
||||||
<StatsRow isLoading={is_loading} label="Аудиозаписи">
|
<StatsRow isLoading={isLoading} label="Аудиозаписи">
|
||||||
{backend.nodes.audios}
|
{stats.nodes.audios}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
|
||||||
<StatsRow isLoading={is_loading} label="Комментарии">
|
<StatsRow isLoading={isLoading} label="Комментарии">
|
||||||
{backend.comments.total}
|
{stats.comments.total}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<SubTitle isLoading={is_loading} className={styles.title}>
|
<SubTitle isLoading={isLoading} className={styles.title}>
|
||||||
Сторедж
|
Сторедж
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<StatsRow isLoading={is_loading} label="Файлы">
|
<StatsRow isLoading={isLoading} label="Файлы">
|
||||||
{backend.files.count}
|
{stats.files.count}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
|
|
||||||
<StatsRow isLoading={is_loading} label="На диске">
|
<StatsRow isLoading={isLoading} label="На диске">
|
||||||
{sizeOf(backend.files.size)}
|
{sizeOf(stats.files.size)}
|
||||||
</StatsRow>
|
</StatsRow>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
import React, { FC, useMemo } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
import { IBorisState } from '~/redux/boris/reducer';
|
import { GithubIssue } from '~/types/boris';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||||
import { BorisStatsGitCard } from '../BorisStatsGitCard';
|
import { BorisStatsGitCard } from '../BorisStatsGitCard';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
stats: IBorisState['stats'];
|
issues: GithubIssue[];
|
||||||
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BorisStatsGit: FC<IProps> = ({ stats }) => {
|
const BorisStatsGit: FC<IProps> = ({ issues, isLoading }) => {
|
||||||
const open = useMemo(
|
const open = useMemo(
|
||||||
() => stats.issues.filter(el => !el.pull_request && el.state === 'open').slice(0, 5),
|
() => issues.filter(el => !el.pull_request && el.state === 'open').slice(0, 5),
|
||||||
[stats.issues]
|
[issues]
|
||||||
);
|
);
|
||||||
|
|
||||||
const closed = useMemo(
|
const closed = useMemo(
|
||||||
() => stats.issues.filter(el => !el.pull_request && el.state === 'closed').slice(0, 5),
|
() => issues.filter(el => !el.pull_request && el.state === 'closed').slice(0, 5),
|
||||||
[stats.issues]
|
[issues]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!stats.issues.length) return null;
|
if (!issues.length) return null;
|
||||||
|
|
||||||
if (stats.is_loading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.stats__title}>
|
<div className={styles.stats__title}>
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import React, { FC, useMemo } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { getPrettyDate } from '~/utils/dom';
|
import { getPrettyDate } from '~/utils/dom';
|
||||||
import { IGithubIssue } from '~/redux/boris/types';
|
import { GithubIssue } from '~/types/boris';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
data: IGithubIssue;
|
data: GithubIssue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateLabels: Record<IGithubIssue['state'], string> = {
|
const stateLabels: Record<GithubIssue['state'], string> = {
|
||||||
open: 'Ожидает',
|
open: 'Ожидает',
|
||||||
closed: 'Сделано',
|
closed: 'Сделано',
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { CommentFormFormatButtons } from '~/components/comment/CommentFormFormat
|
||||||
import { CommentFormAttaches } from '~/components/comment/CommentFormAttaches';
|
import { CommentFormAttaches } from '~/components/comment/CommentFormAttaches';
|
||||||
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
||||||
import { IComment, INode } from '~/redux/types';
|
import { IComment, INode } from '~/redux/types';
|
||||||
import { EMPTY_COMMENT } from '~/redux/node/constants';
|
import { EMPTY_COMMENT } from '~/constants/node';
|
||||||
import { UploadDropzone } from '~/components/upload/UploadDropzone';
|
import { UploadDropzone } from '~/components/upload/UploadDropzone';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { ERROR_LITERAL } from '~/constants/errors';
|
import { ERROR_LITERAL } from '~/constants/errors';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
||||||
import { ImageGrid } from '../ImageGrid';
|
import { ImageGrid } from '../ImageGrid';
|
||||||
import { AudioGrid } from '../AudioGrid';
|
import { AudioGrid } from '../AudioGrid';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { NodeEditorProps } from '~/redux/node/types';
|
import { NodeEditorProps } from '~/types/node';
|
||||||
import { useNodeImages } from '~/hooks/node/useNodeImages';
|
import { useNodeImages } from '~/hooks/node/useNodeImages';
|
||||||
import { useNodeAudios } from '~/hooks/node/useNodeAudios';
|
import { useNodeAudios } from '~/hooks/node/useNodeAudios';
|
||||||
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { createElement, FC } from 'react';
|
import React, { createElement, FC } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { NODE_PANEL_COMPONENTS } from '~/redux/node/constants';
|
import { NODE_PANEL_COMPONENTS } from '~/constants/node';
|
||||||
import { has } from 'ramda';
|
import { has } from 'ramda';
|
||||||
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { EditorUploadButton } from '~/components/editors/EditorUploadButton';
|
import { EditorUploadButton } from '~/components/editors/EditorUploadButton';
|
||||||
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
||||||
import { IEditorComponentProps } from '~/redux/node/types';
|
import { IEditorComponentProps } from '~/types/node';
|
||||||
|
|
||||||
type IProps = IEditorComponentProps & {};
|
type IProps = IEditorComponentProps & {};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { Filler } from '~/components/containers/Filler';
|
import { Filler } from '~/components/containers/Filler';
|
||||||
import { IEditorComponentProps } from '~/redux/node/types';
|
import { IEditorComponentProps } from '~/types/node';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
type IProps = IEditorComponentProps & {};
|
type IProps = IEditorComponentProps & {};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { EditorUploadButton } from '~/components/editors/EditorUploadButton';
|
import { EditorUploadButton } from '~/components/editors/EditorUploadButton';
|
||||||
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
||||||
import { IEditorComponentProps } from '~/redux/node/types';
|
import { IEditorComponentProps } from '~/types/node';
|
||||||
|
|
||||||
type IProps = IEditorComponentProps & {};
|
type IProps = IEditorComponentProps & {};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC, useCallback } from 'react';
|
import React, { FC, useCallback } from 'react';
|
||||||
import { IEditorComponentProps } from '~/redux/node/types';
|
import { IEditorComponentProps } from '~/types/node';
|
||||||
import { Button } from '~/components/input/Button';
|
import { Button } from '~/components/input/Button';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { ChangeEvent, FC, useCallback } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
||||||
import { IEditorComponentProps } from '~/redux/node/types';
|
import { IEditorComponentProps } from '~/types/node';
|
||||||
import { useFileUploaderContext } from '~/hooks/data/useFileUploader';
|
import { useFileUploaderContext } from '~/hooks/data/useFileUploader';
|
||||||
import { getFileType } from '~/utils/uploader';
|
import { getFileType } from '~/utils/uploader';
|
||||||
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { path } from 'ramda';
|
||||||
import { getURL } from '~/utils/dom';
|
import { getURL } from '~/utils/dom';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
import { PRESETS } from '~/constants/urls';
|
import { PRESETS } from '~/constants/urls';
|
||||||
import { IEditorComponentProps } from '~/redux/node/types';
|
import { IEditorComponentProps } from '~/types/node';
|
||||||
import { useFileUploader } from '~/hooks/data/useFileUploader';
|
import { useFileUploader } from '~/hooks/data/useFileUploader';
|
||||||
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
||||||
import { getFileType } from '~/utils/uploader';
|
import { getFileType } from '~/utils/uploader';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { ImageGrid } from '~/components/editors/ImageGrid';
|
import { ImageGrid } from '~/components/editors/ImageGrid';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { NodeEditorProps } from '~/redux/node/types';
|
import { NodeEditorProps } from '~/types/node';
|
||||||
import { useFileUploaderContext } from '~/hooks/data/useFileUploader';
|
import { useFileUploaderContext } from '~/hooks/data/useFileUploader';
|
||||||
import { UploadDropzone } from '~/components/upload/UploadDropzone';
|
import { UploadDropzone } from '~/components/upload/UploadDropzone';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { FC, useCallback } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { Textarea } from '~/components/input/Textarea';
|
import { Textarea } from '~/components/input/Textarea';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import { NodeEditorProps } from '~/redux/node/types';
|
import { NodeEditorProps } from '~/types/node';
|
||||||
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
||||||
|
|
||||||
type IProps = NodeEditorProps & {};
|
type IProps = NodeEditorProps & {};
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { path } from 'ramda';
|
||||||
import { InputText } from '~/components/input/InputText';
|
import { InputText } from '~/components/input/InputText';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { getYoutubeThumb } from '~/utils/dom';
|
import { getYoutubeThumb } from '~/utils/dom';
|
||||||
import { NodeEditorProps } from '~/redux/node/types';
|
import { NodeEditorProps } from '~/types/node';
|
||||||
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
import { useNodeFormContext } from '~/hooks/node/useNodeFormFormik';
|
||||||
|
|
||||||
type IProps = NodeEditorProps & {};
|
type IProps = NodeEditorProps & {};
|
||||||
|
|
|
@ -7,7 +7,7 @@ import styles from './styles.module.scss';
|
||||||
import markdown from '~/styles/common/markdown.module.scss';
|
import markdown from '~/styles/common/markdown.module.scss';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
import { PRESETS } from '~/constants/urls';
|
import { PRESETS } from '~/constants/urls';
|
||||||
import { NODE_TYPES } from '~/redux/node/constants';
|
import { NODE_TYPES } from '~/constants/node';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { CellShade } from '~/components/flow/CellShade';
|
import { CellShade } from '~/components/flow/CellShade';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||||
import { NodeAudioBlock } from '~/components/node/NodeAudioBlock';
|
import { NodeAudioBlock } from '~/components/node/NodeAudioBlock';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { Markdown } from '~/components/containers/Markdown';
|
import { Markdown } from '~/components/containers/Markdown';
|
||||||
import { formatText } from '~/utils/dom';
|
import { formatText } from '~/utils/dom';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import SwiperCore, { A11y, Navigation, Pagination, SwiperOptions } from 'swiper';
|
import SwiperCore, { A11y, Navigation, Pagination, SwiperOptions } from 'swiper';
|
||||||
|
|
||||||
import 'swiper/swiper.scss';
|
import 'swiper/swiper.scss';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { useColorGradientFromString } from '~/hooks/color/useColorGradientFromString';
|
import { useColorGradientFromString } from '~/hooks/color/useColorGradientFromString';
|
||||||
|
|
||||||
interface Props extends INodeComponentProps {}
|
interface Props extends INodeComponentProps {}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Group } from '~/components/containers/Group';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
import Tippy from '@tippy.js/react';
|
import Tippy from '@tippy.js/react';
|
||||||
import { useGotoNode } from '~/hooks/node/useGotoNode';
|
import { useGotoNode } from '~/hooks/node/useGotoNode';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||||
|
|
||||||
const LabNodeTitle: FC<INodeComponentProps> = ({ node, isLoading }) => {
|
const LabNodeTitle: FC<INodeComponentProps> = ({ node, isLoading }) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { useGotoNode } from '~/hooks/node/useGotoNode';
|
import { useGotoNode } from '~/hooks/node/useGotoNode';
|
||||||
|
|
||||||
const LabPad: FC<INodeComponentProps> = ({ node }) => {
|
const LabPad: FC<INodeComponentProps> = ({ node }) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC, useMemo } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
import { Markdown } from '~/components/containers/Markdown';
|
import { Markdown } from '~/components/containers/Markdown';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { formatTextParagraphs } from '~/utils/dom';
|
import { formatTextParagraphs } from '~/utils/dom';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { NodeVideoBlock } from '~/components/node/NodeVideoBlock';
|
import { NodeVideoBlock } from '~/components/node/NodeVideoBlock';
|
||||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { useNodeAudios } from '~/hooks/node/useNodeAudios';
|
import { useNodeAudios } from '~/hooks/node/useNodeAudios';
|
||||||
|
|
||||||
interface IProps extends INodeComponentProps {}
|
interface IProps extends INodeComponentProps {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import styles from './styles.module.scss';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import { getURL } from '~/utils/dom';
|
import { getURL } from '~/utils/dom';
|
||||||
import { PRESETS } from '~/constants/urls';
|
import { PRESETS } from '~/constants/urls';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { useNodeImages } from '~/hooks/node/useNodeImages';
|
import { useNodeImages } from '~/hooks/node/useNodeImages';
|
||||||
|
|
||||||
interface IProps extends INodeComponentProps {}
|
interface IProps extends INodeComponentProps {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC, useCallback, useState } from 'react';
|
import React, { FC, useCallback, useState } from 'react';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||||
|
|
||||||
import 'swiper/swiper.scss';
|
import 'swiper/swiper.scss';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholde
|
||||||
import { NodeRelated } from '~/components/node/NodeRelated';
|
import { NodeRelated } from '~/components/node/NodeRelated';
|
||||||
import { URLS } from '~/constants/urls';
|
import { URLS } from '~/constants/urls';
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import { INodeRelated } from '~/redux/node/types';
|
import { INodeRelated } from '~/types/node';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC, useMemo } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import { formatTextParagraphs } from '~/utils/dom';
|
import { formatTextParagraphs } from '~/utils/dom';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import markdown from '~/styles/common/markdown.module.scss';
|
import markdown from '~/styles/common/markdown.module.scss';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC, useMemo } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
import { INodeComponentProps } from '~/constants/node';
|
||||||
|
|
||||||
interface IProps extends INodeComponentProps {}
|
interface IProps extends INodeComponentProps {}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ export const API = {
|
||||||
},
|
},
|
||||||
BORIS: {
|
BORIS: {
|
||||||
GET_BACKEND_STATS: '/stats/',
|
GET_BACKEND_STATS: '/stats/',
|
||||||
|
GITHUB_ISSUES: 'https://api.github.com/repos/muerwre/vault-frontend/issues',
|
||||||
},
|
},
|
||||||
TAG: {
|
TAG: {
|
||||||
NODES: `/tag/nodes`,
|
NODES: `/tag/nodes`,
|
||||||
|
|
22
src/constants/boris/constants.ts
Normal file
22
src/constants/boris/constants.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { StatBackend } from '~/types/boris';
|
||||||
|
|
||||||
|
export const initialBackendStats: StatBackend = {
|
||||||
|
users: {
|
||||||
|
total: 0,
|
||||||
|
alive: 0,
|
||||||
|
},
|
||||||
|
nodes: {
|
||||||
|
images: 0,
|
||||||
|
audios: 0,
|
||||||
|
videos: 0,
|
||||||
|
texts: 0,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
comments: {
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
files: {
|
||||||
|
count: 0,
|
||||||
|
size: 0,
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
import { NODE_TYPES } from '~/redux/node/constants';
|
import { NODE_TYPES } from '~/constants/node';
|
||||||
import { LoginDialog } from '~/containers/dialogs/LoginDialog';
|
import { LoginDialog } from '~/containers/dialogs/LoginDialog';
|
||||||
import { LoadingDialog } from '~/containers/dialogs/LoadingDialog';
|
import { LoadingDialog } from '~/containers/dialogs/LoadingDialog';
|
||||||
import { TestDialog } from '~/containers/dialogs/TestDialog';
|
import { TestDialog } from '~/containers/dialogs/TestDialog';
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export const DEFAULT_DOMINANT_COLOR = '#000000';
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { IComment, INode, ValueOf } from '../types';
|
import { IComment, INode, ValueOf } from 'src/redux/types';
|
||||||
import { NodeTextBlock } from '~/components/node/NodeTextBlock';
|
import { NodeTextBlock } from '~/components/node/NodeTextBlock';
|
||||||
import { NodeAudioBlock } from '~/components/node/NodeAudioBlock';
|
import { NodeAudioBlock } from '~/components/node/NodeAudioBlock';
|
||||||
import { NodeVideoBlock } from '~/components/node/NodeVideoBlock';
|
import { NodeVideoBlock } from '~/components/node/NodeVideoBlock';
|
||||||
|
@ -11,7 +11,7 @@ import { AudioEditor } from '~/components/editors/AudioEditor';
|
||||||
import { EditorImageUploadButton } from '~/components/editors/EditorImageUploadButton';
|
import { EditorImageUploadButton } from '~/components/editors/EditorImageUploadButton';
|
||||||
import { EditorAudioUploadButton } from '~/components/editors/EditorAudioUploadButton';
|
import { EditorAudioUploadButton } from '~/components/editors/EditorAudioUploadButton';
|
||||||
import { EditorUploadCoverButton } from '~/components/editors/EditorUploadCoverButton';
|
import { EditorUploadCoverButton } from '~/components/editors/EditorUploadCoverButton';
|
||||||
import { IEditorComponentProps, NodeEditorProps } from '~/redux/node/types';
|
import { IEditorComponentProps, NodeEditorProps } from '~/types/node';
|
||||||
import { EditorFiller } from '~/components/editors/EditorFiller';
|
import { EditorFiller } from '~/components/editors/EditorFiller';
|
||||||
import { EditorPublicSwitch } from '~/components/editors/EditorPublicSwitch';
|
import { EditorPublicSwitch } from '~/components/editors/EditorPublicSwitch';
|
||||||
import { NodeImageSwiperBlock } from '~/components/node/NodeImageSwiperBlock';
|
import { NodeImageSwiperBlock } from '~/components/node/NodeImageSwiperBlock';
|
||||||
|
@ -127,4 +127,6 @@ export const NODE_SETTINGS = {
|
||||||
MAX_IMAGE_ASPECT: 1.2,
|
MAX_IMAGE_ASPECT: 1.2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_DOMINANT_COLOR = '#000000';
|
||||||
|
|
||||||
export const COMMENTS_DISPLAY = 25;
|
export const COMMENTS_DISPLAY = 25;
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC, useCallback, useMemo, useRef } from 'react';
|
import React, { FC, useCallback, useMemo, useRef } from 'react';
|
||||||
import { EMPTY_NODE, NODE_TYPES } from '~/redux/node/constants';
|
import { EMPTY_NODE, NODE_TYPES } from '~/constants/node';
|
||||||
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
|
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
|
||||||
import { useHistory, useRouteMatch } from 'react-router';
|
import { useHistory, useRouteMatch } from 'react-router';
|
||||||
import { values } from 'ramda';
|
import { values } from 'ramda';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { createElement, FC, useCallback, useMemo, useState } from 'react';
|
import React, { createElement, FC, useCallback, useMemo, useState } from 'react';
|
||||||
import { IDialogProps } from '~/redux/modal/constants';
|
import { IDialogProps } from '~/redux/modal/constants';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { NODE_EDITORS } from '~/redux/node/constants';
|
import { NODE_EDITORS } from '~/constants/node';
|
||||||
import { BetterScrollDialog } from '../BetterScrollDialog';
|
import { BetterScrollDialog } from '../BetterScrollDialog';
|
||||||
import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
|
import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
|
||||||
import { prop } from 'ramda';
|
import { prop } from 'ramda';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { FC, useMemo } from 'react';
|
||||||
import Masonry from 'react-masonry-css';
|
import Masonry from 'react-masonry-css';
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
import { LabNode } from '~/components/lab/LabNode';
|
import { LabNode } from '~/components/lab/LabNode';
|
||||||
import { EMPTY_NODE, NODE_TYPES } from '~/redux/node/constants';
|
import { EMPTY_NODE, NODE_TYPES } from '~/constants/node';
|
||||||
import { values } from 'ramda';
|
import { values } from 'ramda';
|
||||||
import { useLabPagination } from '~/hooks/lab/useLabPagination';
|
import { useLabPagination } from '~/hooks/lab/useLabPagination';
|
||||||
import { useLabContext } from '~/utils/context/LabContextProvider';
|
import { useLabContext } from '~/utils/context/LabContextProvider';
|
||||||
|
|
|
@ -2,13 +2,12 @@ import { useDispatch } from 'react-redux';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import isBefore from 'date-fns/isBefore';
|
import isBefore from 'date-fns/isBefore';
|
||||||
import { authSetState, authSetUser } from '~/redux/auth/actions';
|
import { authSetState, authSetUser } from '~/redux/auth/actions';
|
||||||
import { borisLoadStats } from '~/redux/boris/actions';
|
|
||||||
import { useUser } from '~/hooks/user/userUser';
|
import { useUser } from '~/hooks/user/userUser';
|
||||||
import { IComment } from '~/redux/types';
|
import { IComment } from '~/redux/types';
|
||||||
import { useShallowSelect } from '~/hooks/data/useShallowSelect';
|
import { useShallowSelect } from '~/hooks/data/useShallowSelect';
|
||||||
import { selectAuthIsTester } from '~/redux/auth/selectors';
|
import { selectAuthIsTester } from '~/redux/auth/selectors';
|
||||||
import { selectBorisStats } from '~/redux/boris/selectors';
|
|
||||||
import { useRandomPhrase } from '~/constants/phrases';
|
import { useRandomPhrase } from '~/constants/phrases';
|
||||||
|
import { useBorisStats } from '~/hooks/boris/useBorisStats';
|
||||||
|
|
||||||
export const useBoris = (comments: IComment[]) => {
|
export const useBoris = (comments: IComment[]) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -29,9 +28,7 @@ export const useBoris = (comments: IComment[]) => {
|
||||||
dispatch(authSetUser({ last_seen_boris: last_comment.created_at }));
|
dispatch(authSetUser({ last_seen_boris: last_comment.created_at }));
|
||||||
}, [user.last_seen_boris, dispatch, comments]);
|
}, [user.last_seen_boris, dispatch, comments]);
|
||||||
|
|
||||||
useEffect(() => {
|
const { stats, isLoading: isLoadingStats } = useBorisStats();
|
||||||
dispatch(borisLoadStats());
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const setIsBetaTester = useCallback(
|
const setIsBetaTester = useCallback(
|
||||||
(is_tester: boolean) => {
|
(is_tester: boolean) => {
|
||||||
|
@ -41,8 +38,7 @@ export const useBoris = (comments: IComment[]) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const isTester = useShallowSelect(selectAuthIsTester);
|
const isTester = useShallowSelect(selectAuthIsTester);
|
||||||
const stats = useShallowSelect(selectBorisStats);
|
|
||||||
const title = useRandomPhrase('BORIS_TITLE');
|
const title = useRandomPhrase('BORIS_TITLE');
|
||||||
|
|
||||||
return { setIsBetaTester, isTester, stats, title };
|
return { setIsBetaTester, isTester, stats, title, isLoadingStats };
|
||||||
};
|
};
|
||||||
|
|
25
src/hooks/boris/useBorisStats.ts
Normal file
25
src/hooks/boris/useBorisStats.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { API } from '~/constants/api';
|
||||||
|
import { getBorisBackendStats, getGithubIssues } from '~/api/boris';
|
||||||
|
import { BorisUsageStats } from '~/types/boris';
|
||||||
|
import { initialBackendStats } from '~/constants/boris/constants';
|
||||||
|
|
||||||
|
export const useBorisStats = () => {
|
||||||
|
const { data: backend = initialBackendStats, isValidating: isValidatingBackend } = useSWR(
|
||||||
|
API.BORIS.GET_BACKEND_STATS,
|
||||||
|
() => getBorisBackendStats()
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: issues = [], isValidating: isValidatingGit } = useSWR(API.BORIS.GITHUB_ISSUES, () =>
|
||||||
|
getGithubIssues()
|
||||||
|
);
|
||||||
|
|
||||||
|
const stats: BorisUsageStats = {
|
||||||
|
backend,
|
||||||
|
issues,
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLoading = !backend && isValidatingBackend;
|
||||||
|
|
||||||
|
return { stats, isLoading };
|
||||||
|
};
|
|
@ -3,8 +3,8 @@ import { IComment } from '~/redux/types';
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
import { flatten, isNil } from 'ramda';
|
import { flatten, isNil } from 'ramda';
|
||||||
import useSWRInfinite from 'swr/infinite';
|
import useSWRInfinite from 'swr/infinite';
|
||||||
import { apiGetNodeComments } from '~/redux/node/api';
|
import { apiGetNodeComments } from '~/api/node';
|
||||||
import { COMMENTS_DISPLAY } from '~/redux/node/constants';
|
import { COMMENTS_DISPLAY } from '~/constants/node';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
const getKey: (nodeId: number) => KeyLoader<IComment[]> = (nodeId: number) => (
|
const getKey: (nodeId: number) => KeyLoader<IComment[]> = (nodeId: number) => (
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { IComment } from '~/redux/types';
|
import { IComment } from '~/redux/types';
|
||||||
import { useGetComments } from '~/hooks/comments/useGetComments';
|
import { useGetComments } from '~/hooks/comments/useGetComments';
|
||||||
import { apiLockComment, apiPostComment } from '~/redux/node/api';
|
import { apiLockComment, apiPostComment } from '~/api/node';
|
||||||
import { showErrorToast } from '~/utils/errors/showToast';
|
import { showErrorToast } from '~/utils/errors/showToast';
|
||||||
|
|
||||||
export const useNodeComments = (nodeId: number) => {
|
export const useNodeComments = (nodeId: number) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import { apiPostNode } from '~/redux/node/api';
|
import { apiPostNode } from '~/api/node';
|
||||||
import { selectFlowNodes } from '~/redux/flow/selectors';
|
import { selectFlowNodes } from '~/redux/flow/selectors';
|
||||||
import { flowSetNodes } from '~/redux/flow/actions';
|
import { flowSetNodes } from '~/redux/flow/actions';
|
||||||
import { selectLabListNodes } from '~/redux/lab/selectors';
|
import { selectLabListNodes } from '~/redux/lab/selectors';
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { ApiGetNodeRelatedResult } from '~/redux/node/types';
|
import { ApiGetNodeRelatedResult } from '~/types/node';
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { apiGetNodeRelated } from '~/redux/node/api';
|
import { apiGetNodeRelated } from '~/api/node';
|
||||||
|
|
||||||
export const useGetNodeRelated = (id?: INode['id']) => {
|
export const useGetNodeRelated = (id?: INode['id']) => {
|
||||||
const { data, isValidating, mutate } = useSWR<ApiGetNodeRelatedResult>(API.NODE.RELATED(id), () =>
|
const { data, isValidating, mutate } = useSWR<ApiGetNodeRelatedResult>(API.NODE.RELATED(id), () =>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { ApiGetNodeResponse } from '~/redux/node/types';
|
import { ApiGetNodeResponse } from '~/types/node';
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
import { useOnNodeSeen } from '~/hooks/node/useOnNodeSeen';
|
import { useOnNodeSeen } from '~/hooks/node/useOnNodeSeen';
|
||||||
import { apiGetNode } from '~/redux/node/api';
|
import { apiGetNode } from '~/api/node';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import { EMPTY_NODE } from '~/redux/node/constants';
|
import { EMPTY_NODE } from '~/constants/node';
|
||||||
|
|
||||||
export const useLoadNode = (id: number) => {
|
export const useLoadNode = (id: number) => {
|
||||||
const { data, isValidating, mutate } = useSWR<ApiGetNodeResponse>(API.NODE.GET_NODE(id), () =>
|
const { data, isValidating, mutate } = useSWR<ApiGetNodeResponse>(API.NODE.GET_NODE(id), () =>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useCallback } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { modalShowDialog } from '~/redux/modal/actions';
|
import { modalShowDialog } from '~/redux/modal/actions';
|
||||||
import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs';
|
import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs';
|
||||||
import { apiLockNode, apiPostNodeHeroic, apiPostNodeLike } from '~/redux/node/api';
|
import { apiLockNode, apiPostNodeHeroic, apiPostNodeLike } from '~/api/node';
|
||||||
import { showErrorToast } from '~/utils/errors/showToast';
|
import { showErrorToast } from '~/utils/errors/showToast';
|
||||||
|
|
||||||
export const useNodeActions = (node: INode, update: (node: Partial<INode>) => Promise<unknown>) => {
|
export const useNodeActions = (node: INode, update: (node: Partial<INode>) => Promise<unknown>) => {
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import { createElement, FC, useCallback, useMemo } from 'react';
|
import { createElement, FC, useCallback, useMemo } from 'react';
|
||||||
import { isNil, prop } from 'ramda';
|
import { isNil, prop } from 'ramda';
|
||||||
import {
|
import { INodeComponentProps, LAB_PREVIEW_LAYOUT, NODE_COMPONENTS, NODE_HEADS, NODE_INLINES, } from '~/constants/node';
|
||||||
INodeComponentProps,
|
|
||||||
LAB_PREVIEW_LAYOUT,
|
|
||||||
NODE_COMPONENTS,
|
|
||||||
NODE_HEADS,
|
|
||||||
NODE_INLINES,
|
|
||||||
} from '~/redux/node/constants';
|
|
||||||
|
|
||||||
// useNodeBlocks returns head, block and inline blocks of node
|
// useNodeBlocks returns head, block and inline blocks of node
|
||||||
export const useNodeBlocks = (node: INode, isLoading: boolean) => {
|
export const useNodeBlocks = (node: INode, isLoading: boolean) => {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useCallback } from 'react';
|
||||||
import { ITag } from '~/redux/types';
|
import { ITag } from '~/redux/types';
|
||||||
import { URLS } from '~/constants/urls';
|
import { URLS } from '~/constants/urls';
|
||||||
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
||||||
import { apiDeleteNodeTag, apiPostNodeTags } from '~/redux/node/api';
|
import { apiDeleteNodeTag, apiPostNodeTags } from '~/api/node';
|
||||||
|
|
||||||
export const useNodeTags = (id: number) => {
|
export const useNodeTags = (id: number) => {
|
||||||
const { update } = useLoadNode(id);
|
const { update } = useLoadNode(id);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import { apiPostNode } from '~/redux/node/api';
|
import { apiPostNode } from '~/api/node';
|
||||||
import { selectFlowNodes } from '~/redux/flow/selectors';
|
import { selectFlowNodes } from '~/redux/flow/selectors';
|
||||||
import { flowSetNodes } from '~/redux/flow/actions';
|
import { flowSetNodes } from '~/redux/flow/actions';
|
||||||
import { selectLabListNodes } from '~/redux/lab/selectors';
|
import { selectLabListNodes } from '~/redux/lab/selectors';
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Card } from '~/components/containers/Card';
|
||||||
import { SidebarRouter } from '~/containers/main/SidebarRouter';
|
import { SidebarRouter } from '~/containers/main/SidebarRouter';
|
||||||
import { BorisSidebar } from '~/components/boris/BorisSidebar';
|
import { BorisSidebar } from '~/components/boris/BorisSidebar';
|
||||||
import { useUserContext } from '~/utils/context/UserContextProvider';
|
import { useUserContext } from '~/utils/context/UserContextProvider';
|
||||||
import { BorisUsageStats } from '~/redux/boris/reducer';
|
import { BorisUsageStats } from '~/types/boris';
|
||||||
import { Tabs } from '~/components/dialogs/Tabs';
|
import { Tabs } from '~/components/dialogs/Tabs';
|
||||||
import { Superpower } from '~/components/boris/Superpower';
|
import { Superpower } from '~/components/boris/Superpower';
|
||||||
import { BorisUIDemo } from '~/components/boris/BorisUIDemo';
|
import { BorisUIDemo } from '~/components/boris/BorisUIDemo';
|
||||||
|
@ -19,9 +19,10 @@ type IProps = {
|
||||||
setIsBetaTester: (val: boolean) => void;
|
setIsBetaTester: (val: boolean) => void;
|
||||||
isTester: boolean;
|
isTester: boolean;
|
||||||
stats: BorisUsageStats;
|
stats: BorisUsageStats;
|
||||||
|
isLoadingStats: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BorisLayout: FC<IProps> = ({ title, setIsBetaTester, isTester, stats }) => {
|
const BorisLayout: FC<IProps> = ({ title, setIsBetaTester, isTester, stats, isLoadingStats }) => {
|
||||||
const user = useUserContext();
|
const user = useUserContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -60,6 +61,7 @@ const BorisLayout: FC<IProps> = ({ title, setIsBetaTester, isTester, stats }) =>
|
||||||
stats={stats}
|
stats={stats}
|
||||||
setBetaTester={setIsBetaTester}
|
setBetaTester={setIsBetaTester}
|
||||||
user={user}
|
user={user}
|
||||||
|
isLoading={isLoadingStats}
|
||||||
/>
|
/>
|
||||||
</StickyBox>
|
</StickyBox>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
|
@ -19,7 +19,7 @@ const BorisPage: VFC = () => {
|
||||||
hasMore,
|
hasMore,
|
||||||
isLoading: isLoadingComments,
|
isLoading: isLoadingComments,
|
||||||
} = useNodeComments(696);
|
} = useNodeComments(696);
|
||||||
const { title, setIsBetaTester, isTester, stats } = useBoris(comments);
|
const { title, setIsBetaTester, isTester, stats, isLoadingStats } = useBoris(comments);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeContextProvider node={node} isLoading={isLoading} update={update}>
|
<NodeContextProvider node={node} isLoading={isLoading} update={update}>
|
||||||
|
@ -37,6 +37,7 @@ const BorisPage: VFC = () => {
|
||||||
setIsBetaTester={setIsBetaTester}
|
setIsBetaTester={setIsBetaTester}
|
||||||
isTester={isTester}
|
isTester={isTester}
|
||||||
stats={stats}
|
stats={stats}
|
||||||
|
isLoadingStats={isLoadingStats}
|
||||||
/>
|
/>
|
||||||
</CommentContextProvider>
|
</CommentContextProvider>
|
||||||
</NodeContextProvider>
|
</NodeContextProvider>
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { IBorisState } from './reducer';
|
|
||||||
import { BORIS_ACTIONS } from './constants';
|
|
||||||
|
|
||||||
export const borisSet = (state: Partial<IBorisState>) => ({
|
|
||||||
type: BORIS_ACTIONS.SET_BORIS,
|
|
||||||
state,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const borisSetStats = (stats: Partial<IBorisState['stats']>) => ({
|
|
||||||
type: BORIS_ACTIONS.SET_STATS,
|
|
||||||
stats,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const borisLoadStats = () => ({
|
|
||||||
type: BORIS_ACTIONS.LOAD_STATS,
|
|
||||||
});
|
|
|
@ -1,20 +0,0 @@
|
||||||
import git from '~/stats/git.json';
|
|
||||||
import { API } from '~/constants/api';
|
|
||||||
import { api, cleanResult } from '~/utils/api';
|
|
||||||
import { IBorisState, IStatBackend } from './reducer';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { IGetGithubIssuesResult } from '~/redux/boris/types';
|
|
||||||
|
|
||||||
export const getBorisGitStats = () => Promise.resolve<IBorisState['stats']['git']>(git);
|
|
||||||
|
|
||||||
export const getBorisBackendStats = () =>
|
|
||||||
api.get<IStatBackend>(API.BORIS.GET_BACKEND_STATS).then(cleanResult);
|
|
||||||
|
|
||||||
export const getGithubIssues = () => {
|
|
||||||
return axios
|
|
||||||
.get<IGetGithubIssuesResult>('https://api.github.com/repos/muerwre/vault-frontend/issues', {
|
|
||||||
params: { state: 'all', sort: 'created' },
|
|
||||||
})
|
|
||||||
.then(result => result.data)
|
|
||||||
.catch(() => []);
|
|
||||||
};
|
|
|
@ -1,8 +0,0 @@
|
||||||
const prefix = `BORIS.`;
|
|
||||||
|
|
||||||
export const BORIS_ACTIONS = {
|
|
||||||
SET_BORIS: `${prefix}SET_BORIS`,
|
|
||||||
SET_STATS: `${prefix}SET_STATS`,
|
|
||||||
|
|
||||||
LOAD_STATS: `${prefix}LOAD_STATS`,
|
|
||||||
};
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { IBorisState } from './reducer';
|
|
||||||
import { BORIS_ACTIONS } from './constants';
|
|
||||||
|
|
||||||
const borisSet = (current: IBorisState, { state }: ReturnType<typeof borisSet>) => ({
|
|
||||||
...current,
|
|
||||||
...state,
|
|
||||||
});
|
|
||||||
|
|
||||||
const borisSetStats = (state: IBorisState, { stats }: ReturnType<typeof borisSetStats>) => ({
|
|
||||||
...state,
|
|
||||||
stats: {
|
|
||||||
...state.stats,
|
|
||||||
...stats,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const BORIS_HANDLERS = {
|
|
||||||
[BORIS_ACTIONS.SET_BORIS]: borisSet,
|
|
||||||
[BORIS_ACTIONS.SET_STATS]: borisSetStats,
|
|
||||||
};
|
|
|
@ -1,72 +0,0 @@
|
||||||
import { createReducer } from '~/utils/reducer';
|
|
||||||
import { BORIS_HANDLERS } from './handlers';
|
|
||||||
import { IGithubIssue } from '~/redux/boris/types';
|
|
||||||
|
|
||||||
export type IStatGitRow = {
|
|
||||||
commit: string;
|
|
||||||
subject: string;
|
|
||||||
timestamp: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type IStatBackend = {
|
|
||||||
users: {
|
|
||||||
total: number;
|
|
||||||
alive: number;
|
|
||||||
};
|
|
||||||
nodes: {
|
|
||||||
images: number;
|
|
||||||
audios: number;
|
|
||||||
videos: number;
|
|
||||||
texts: number;
|
|
||||||
total: number;
|
|
||||||
};
|
|
||||||
comments: {
|
|
||||||
total: number;
|
|
||||||
};
|
|
||||||
files: {
|
|
||||||
count: number;
|
|
||||||
size: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface BorisUsageStats {
|
|
||||||
git: Partial<IStatGitRow>[];
|
|
||||||
issues: IGithubIssue[];
|
|
||||||
backend: IStatBackend;
|
|
||||||
is_loading: boolean;
|
|
||||||
}
|
|
||||||
export type IBorisState = Readonly<{
|
|
||||||
stats: BorisUsageStats;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
const initialBackendStats: IStatBackend = {
|
|
||||||
users: {
|
|
||||||
total: 0,
|
|
||||||
alive: 0,
|
|
||||||
},
|
|
||||||
nodes: {
|
|
||||||
images: 0,
|
|
||||||
audios: 0,
|
|
||||||
videos: 0,
|
|
||||||
texts: 0,
|
|
||||||
total: 0,
|
|
||||||
},
|
|
||||||
comments: {
|
|
||||||
total: 0,
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
count: 0,
|
|
||||||
size: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const BORIS_INITIAL_STATE: IBorisState = {
|
|
||||||
stats: {
|
|
||||||
git: [],
|
|
||||||
issues: [],
|
|
||||||
backend: initialBackendStats,
|
|
||||||
is_loading: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default createReducer(BORIS_INITIAL_STATE, BORIS_HANDLERS);
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { call, put, takeLatest } from 'redux-saga/effects';
|
|
||||||
import { BORIS_ACTIONS } from './constants';
|
|
||||||
import { borisSetStats } from './actions';
|
|
||||||
import { getBorisBackendStats, getGithubIssues } from './api';
|
|
||||||
import { Unwrap } from '../types';
|
|
||||||
|
|
||||||
function* loadStats() {
|
|
||||||
try {
|
|
||||||
yield put(borisSetStats({ is_loading: true }));
|
|
||||||
|
|
||||||
const backend: Unwrap<typeof getBorisBackendStats> = yield call(getBorisBackendStats);
|
|
||||||
const issues: Unwrap<typeof getGithubIssues> = yield call(getGithubIssues);
|
|
||||||
|
|
||||||
yield put(borisSetStats({ issues, backend }));
|
|
||||||
} catch (e) {
|
|
||||||
yield put(borisSetStats({ git: [], backend: undefined }));
|
|
||||||
} finally {
|
|
||||||
yield put(borisSetStats({ is_loading: false }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function* borisSaga() {
|
|
||||||
yield takeLatest(BORIS_ACTIONS.LOAD_STATS, loadStats);
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
import { IState } from '../store';
|
|
||||||
|
|
||||||
export const selectBoris = (state: IState) => state.boris;
|
|
||||||
export const selectBorisStats = (state: IState) => state.boris.stats;
|
|
|
@ -1,12 +0,0 @@
|
||||||
export interface IGithubIssue {
|
|
||||||
id: string;
|
|
||||||
url: string;
|
|
||||||
html_url: string;
|
|
||||||
body: string;
|
|
||||||
title: string;
|
|
||||||
state: 'open' | 'closed';
|
|
||||||
created_at: string;
|
|
||||||
pull_request?: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type IGetGithubIssuesResult = IGithubIssue[];
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { api, cleanResult, configWithToken } from '~/utils/api';
|
import { api, cleanResult, configWithToken } from '~/utils/api';
|
||||||
import { INode, IResultWithStatus } from '../types';
|
import { INode, IResultWithStatus } from '../types';
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
import { PostCellViewRequest, PostCellViewResult } from '~/redux/node/types';
|
import { PostCellViewRequest, PostCellViewResult } from '~/types/node';
|
||||||
import { GetSearchResultsRequest, GetSearchResultsResult } from '~/redux/flow/types';
|
import { GetSearchResultsRequest, GetSearchResultsResult } from '~/redux/flow/types';
|
||||||
|
|
||||||
export const postNode = ({
|
export const postNode = ({
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { call, delay, put, race, select, take, takeLatest, takeLeading } from 'redux-saga/effects';
|
import { call, delay, put, race, select, take, takeLatest, takeLeading } from 'redux-saga/effects';
|
||||||
import { REHYDRATE } from 'redux-persist';
|
import { REHYDRATE } from 'redux-persist';
|
||||||
import { FLOW_ACTIONS } from './constants';
|
import { FLOW_ACTIONS } from './constants';
|
||||||
import { getNodeDiff } from '../node/api';
|
import { getNodeDiff } from '~/api/node';
|
||||||
import {
|
import {
|
||||||
flowChangeSearch,
|
flowChangeSearch,
|
||||||
flowSetCellView,
|
flowSetCellView,
|
||||||
|
|
|
@ -29,9 +29,6 @@ import { modalSaga } from './modal/sagas';
|
||||||
|
|
||||||
import { authLogout, authOpenProfile, gotAuthPostMessage } from './auth/actions';
|
import { authLogout, authOpenProfile, gotAuthPostMessage } from './auth/actions';
|
||||||
|
|
||||||
import boris, { IBorisState } from './boris/reducer';
|
|
||||||
import borisSaga from './boris/sagas';
|
|
||||||
|
|
||||||
import messages, { IMessagesState } from './messages';
|
import messages, { IMessagesState } from './messages';
|
||||||
import messagesSaga from './messages/sagas';
|
import messagesSaga from './messages/sagas';
|
||||||
|
|
||||||
|
@ -66,7 +63,6 @@ export interface IState {
|
||||||
uploads: IUploadState;
|
uploads: IUploadState;
|
||||||
flow: IFlowState;
|
flow: IFlowState;
|
||||||
player: IPlayerState;
|
player: IPlayerState;
|
||||||
boris: IBorisState;
|
|
||||||
messages: IMessagesState;
|
messages: IMessagesState;
|
||||||
tag: ITagState;
|
tag: ITagState;
|
||||||
lab: ILabState;
|
lab: ILabState;
|
||||||
|
@ -86,7 +82,6 @@ export const store = createStore(
|
||||||
combineReducers<IState>({
|
combineReducers<IState>({
|
||||||
auth: persistReducer(authPersistConfig, auth),
|
auth: persistReducer(authPersistConfig, auth),
|
||||||
modal,
|
modal,
|
||||||
boris,
|
|
||||||
router: connectRouter(history),
|
router: connectRouter(history),
|
||||||
uploads,
|
uploads,
|
||||||
flow: persistReducer(flowPersistConfig, flow),
|
flow: persistReducer(flowPersistConfig, flow),
|
||||||
|
@ -107,7 +102,6 @@ export function configureStore(): {
|
||||||
sagaMiddleware.run(flowSaga);
|
sagaMiddleware.run(flowSaga);
|
||||||
sagaMiddleware.run(playerSaga);
|
sagaMiddleware.run(playerSaga);
|
||||||
sagaMiddleware.run(modalSaga);
|
sagaMiddleware.run(modalSaga);
|
||||||
sagaMiddleware.run(borisSaga);
|
|
||||||
sagaMiddleware.run(messagesSaga);
|
sagaMiddleware.run(messagesSaga);
|
||||||
sagaMiddleware.run(tagSaga);
|
sagaMiddleware.run(tagSaga);
|
||||||
sagaMiddleware.run(labSaga);
|
sagaMiddleware.run(labSaga);
|
||||||
|
|
47
src/types/boris/index.ts
Normal file
47
src/types/boris/index.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
export interface GithubIssue {
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
html_url: string;
|
||||||
|
body: string;
|
||||||
|
title: string;
|
||||||
|
state: 'open' | 'closed';
|
||||||
|
created_at: string;
|
||||||
|
pull_request?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IGetGithubIssuesResult = GithubIssue[];
|
||||||
|
|
||||||
|
export type IStatGitRow = {
|
||||||
|
commit: string;
|
||||||
|
subject: string;
|
||||||
|
timestamp: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StatBackend = {
|
||||||
|
users: {
|
||||||
|
total: number;
|
||||||
|
alive: number;
|
||||||
|
};
|
||||||
|
nodes: {
|
||||||
|
images: number;
|
||||||
|
audios: number;
|
||||||
|
videos: number;
|
||||||
|
texts: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
comments: {
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
files: {
|
||||||
|
count: number;
|
||||||
|
size: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface BorisUsageStats {
|
||||||
|
issues: GithubIssue[];
|
||||||
|
backend: StatBackend;
|
||||||
|
}
|
||||||
|
export type IBorisState = Readonly<{
|
||||||
|
stats: BorisUsageStats;
|
||||||
|
}>;
|
|
@ -1,5 +1,5 @@
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
import { EMPTY_NODE } from '~/redux/node/constants';
|
import { EMPTY_NODE } from '~/constants/node';
|
||||||
import React, { createContext, FC, useContext } from 'react';
|
import React, { createContext, FC, useContext } from 'react';
|
||||||
|
|
||||||
export interface NodeContextProps {
|
export interface NodeContextProps {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { INodeRelated } from '~/redux/node/types';
|
import { INodeRelated } from '~/types/node';
|
||||||
import React, { createContext, FC, useContext } from 'react';
|
import React, { createContext, FC, useContext } from 'react';
|
||||||
|
|
||||||
interface NodeRelatedProviderProps {
|
interface NodeRelatedProviderProps {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { USER_ROLES } from '~/redux/auth/constants';
|
||||||
import { ICommentGroup, INode } from '~/redux/types';
|
import { ICommentGroup, INode } from '~/redux/types';
|
||||||
import { IUser } from '~/redux/auth/types';
|
import { IUser } from '~/redux/auth/types';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import { NODE_TYPES } from '~/redux/node/constants';
|
import { NODE_TYPES } from '~/constants/node';
|
||||||
|
|
||||||
export const canEditNode = (node?: Partial<INode>, user?: Partial<IUser>): boolean =>
|
export const canEditNode = (node?: Partial<INode>, user?: Partial<IUser>): boolean =>
|
||||||
path(['role'], user) === USER_ROLES.ADMIN ||
|
path(['role'], user) === USER_ROLES.ADMIN ||
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC, useEffect } from 'react';
|
import React, { FC, useEffect } from 'react';
|
||||||
import { INode, ITag } from '~/redux/types';
|
import { INode, ITag } from '~/redux/types';
|
||||||
import { NodeRelatedContextProvider } from '~/utils/context/NodeRelatedContextProvider';
|
import { NodeRelatedContextProvider } from '~/utils/context/NodeRelatedContextProvider';
|
||||||
import { INodeRelated } from '~/redux/node/types';
|
import { INodeRelated } from '~/types/node';
|
||||||
import { useGetNodeRelated } from '~/hooks/node/useGetNodeRelated';
|
import { useGetNodeRelated } from '~/hooks/node/useGetNodeRelated';
|
||||||
|
|
||||||
interface NodeRelatedProviderProps {
|
interface NodeRelatedProviderProps {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue