mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
mdi font icons
This commit is contained in:
parent
ca6d552f5b
commit
00d693e9e4
@ -5,7 +5,6 @@ import theme from './theme';
|
||||
import { DropDownMenuItem, DropDownMenuDivider } from './modals/DropDownMenu';
|
||||
|
||||
import { useOpenedTabs, useSetOpenedTabs, useCurrentDatabase, useSetCurrentDatabase } from './utility/globalState';
|
||||
import { getIconImage } from './icons';
|
||||
import { showMenu } from './modals/DropDownMenu';
|
||||
import { getConnectionInfo } from './utility/metadataLoaders';
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
import _ from 'lodash';
|
||||
import { filterName } from '@dbgate/datalib';
|
||||
import { MacroIcon, StartIcon } from '../icons';
|
||||
|
||||
const macroAppObject = () => ({ name, type, title, group }, { setOpenedTabs }) => {
|
||||
const key = name;
|
||||
const Icon = MacroIcon;
|
||||
const icon = 'mdi mdi-hammer-wrench';
|
||||
const matcher = (filter) => filterName(filter, name, title);
|
||||
const groupTitle = group;
|
||||
|
||||
return { title, key, Icon, groupTitle, matcher };
|
||||
return { title, key, icon, groupTitle, matcher };
|
||||
};
|
||||
|
||||
export default macroAppObject;
|
||||
|
@ -1,16 +1,17 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { DatabaseIcon, getIconImage, ArchiveTableIcon } from '../icons';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
import { openNewTab } from '../utility/common';
|
||||
import { filterName } from '@dbgate/datalib';
|
||||
import axios from '../utility/axios';
|
||||
|
||||
const archiveTableIcon = 'mdi mdi-table color-yellow-icon';
|
||||
|
||||
function openArchive(setOpenedTabs, fileName, folderName) {
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: fileName,
|
||||
icon: 'archtable.svg',
|
||||
icon: archiveTableIcon,
|
||||
tooltip: `${folderName}\n${fileName}`,
|
||||
tabComponent: 'ArchiveFileTab',
|
||||
props: {
|
||||
@ -33,7 +34,7 @@ function Menu({ data, setOpenedTabs }) {
|
||||
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: data.fileName,
|
||||
icon: 'freetable.svg',
|
||||
icon: archiveTableIcon,
|
||||
tabComponent: 'FreeTableTab',
|
||||
props: {
|
||||
initialData: {
|
||||
@ -60,13 +61,13 @@ function Menu({ data, setOpenedTabs }) {
|
||||
|
||||
const archiveFileAppObject = () => ({ fileName, folderName }, { setOpenedTabs }) => {
|
||||
const key = fileName;
|
||||
const Icon = ArchiveTableIcon;
|
||||
const icon = archiveTableIcon;
|
||||
const onClick = () => {
|
||||
openArchive(setOpenedTabs, fileName, folderName);
|
||||
};
|
||||
const matcher = (filter) => filterName(filter, fileName);
|
||||
|
||||
return { title: fileName, key, Icon, Menu, onClick, matcher };
|
||||
return { title: fileName, key, icon, Menu, onClick, matcher };
|
||||
};
|
||||
|
||||
export default archiveFileAppObject;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { LocalDbIcon, getIconImage } from '../icons';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
import axios from '../utility/axios';
|
||||
import { filterName } from '@dbgate/datalib';
|
||||
@ -19,11 +18,11 @@ function Menu({ data, setOpenedTabs }) {
|
||||
|
||||
const archiveFolderAppObject = () => ({ name }, { setOpenedTabs, currentArchive }) => {
|
||||
const key = name;
|
||||
const Icon = LocalDbIcon;
|
||||
const icon = 'mdi mdi-database-outline color-green-icon';
|
||||
const isBold = name == currentArchive;
|
||||
const matcher = (filter) => filterName(filter, name);
|
||||
|
||||
return { title: name, key, Icon, isBold, Menu, matcher };
|
||||
return { title: name, key, icon, isBold, Menu, matcher };
|
||||
};
|
||||
|
||||
export default archiveFolderAppObject;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { getIconImage } from '../icons';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
|
||||
function Menu({ data, setOpenedTabs }) {
|
||||
@ -21,7 +20,6 @@ function Menu({ data, setOpenedTabs }) {
|
||||
|
||||
const closedTabAppObject = () => ({ tabid, props, selected, icon, title, closedTime, busy }, { setOpenedTabs }) => {
|
||||
const key = tabid;
|
||||
const Icon = (props) => getIconImage(icon, props);
|
||||
const isBold = !!selected;
|
||||
|
||||
const onClick = () => {
|
||||
@ -34,7 +32,7 @@ const closedTabAppObject = () => ({ tabid, props, selected, icon, title, closedT
|
||||
);
|
||||
};
|
||||
|
||||
return { title: `${title} ${moment(closedTime).fromNow()}`, key, Icon, isBold, onClick, isBusy: busy, Menu };
|
||||
return { title: `${title} ${moment(closedTime).fromNow()}`, key, icon, isBold, onClick, isBusy: busy, Menu };
|
||||
};
|
||||
|
||||
export default closedTabAppObject;
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { ColumnIcon, SequenceIcon } from '../icons';
|
||||
|
||||
/** @param columnProps {import('@dbgate/types').ColumnInfo} */
|
||||
function getColumnIcon(columnProps) {
|
||||
if (columnProps.autoIncrement) return SequenceIcon;
|
||||
return ColumnIcon;
|
||||
if (columnProps.autoIncrement) return 'mdi mdi-numeric-1-box-multiple-outline';
|
||||
return 'mdi mdi-table-column';
|
||||
}
|
||||
|
||||
/** @param columnProps {import('@dbgate/types').ColumnInfo} */
|
||||
export default function columnAppObject(columnProps, { setOpenedTabs }) {
|
||||
const title = columnProps.columnName;
|
||||
const key = title;
|
||||
const Icon = getColumnIcon(columnProps);
|
||||
const icon = getColumnIcon(columnProps);
|
||||
const isBold = columnProps.notNull;
|
||||
|
||||
return { title, key, Icon, isBold };
|
||||
return { title, key, icon, isBold };
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { PrimaryKeyIcon, ForeignKeyIcon } from '../icons';
|
||||
|
||||
/** @param props {import('@dbgate/types').ConstraintInfo} */
|
||||
function getConstraintIcon(props) {
|
||||
if (props.constraintType == 'primaryKey') return PrimaryKeyIcon;
|
||||
if (props.constraintType == 'foreignKey') return ForeignKeyIcon;
|
||||
if (props.constraintType == 'primaryKey') return 'mdi mdi-key-star color-yellow-icon';
|
||||
if (props.constraintType == 'foreignKey') return 'mdi mdi-key-link';
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -11,7 +9,7 @@ function getConstraintIcon(props) {
|
||||
export default function constraintAppObject(props, { setOpenedTabs }) {
|
||||
const title = props.constraintName;
|
||||
const key = title;
|
||||
const Icon = getConstraintIcon(props);
|
||||
const icon = getConstraintIcon(props);
|
||||
|
||||
return { title, key, Icon };
|
||||
return { title, key, icon };
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { DatabaseIcon } from '../icons';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
import { openNewTab } from '../utility/common';
|
||||
import ImportExportModal from '../modals/ImportExportModal';
|
||||
|
@ -1,6 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import { getIconImage } from '../icons';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
import { openNewTab } from '../utility/common';
|
||||
import { getConnectionInfo } from '../utility/metadataLoaders';
|
||||
@ -102,7 +101,7 @@ export async function openDatabaseObjectDetail(
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: pureName,
|
||||
tooltip,
|
||||
icon: sqlTemplate ? 'sql.svg' : icons[objectTypeField],
|
||||
icon: sqlTemplate ? 'mdi mdi-file' : icons[objectTypeField],
|
||||
tabComponent: sqlTemplate ? 'QueryTab' : tabComponent,
|
||||
props: {
|
||||
schemaName,
|
||||
@ -139,7 +138,7 @@ function Menu({ data, makeAppObj, setOpenedTabs, showModal }) {
|
||||
const coninfo = await getConnectionInfo(data);
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: data.pureName,
|
||||
icon: 'freetable.svg',
|
||||
icon: 'mdi mdi-table color-green-icon',
|
||||
tabComponent: 'FreeTableTab',
|
||||
props: {
|
||||
initialData: {
|
||||
|
@ -1,9 +1,6 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { SqlIcon } from '../icons';
|
||||
import { openNewTab } from '../utility/common';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
import { useSetSavedSqlFiles } from '../utility/globalState';
|
||||
|
||||
function Menu({ data, setSavedSqlFiles }) {
|
||||
const handleDelete = () => {
|
||||
@ -19,7 +16,7 @@ function Menu({ data, setSavedSqlFiles }) {
|
||||
const savedSqlFileAppObject = () => ({ name, storageKey }, { setOpenedTabs, newQuery, openedTabs }) => {
|
||||
const key = storageKey;
|
||||
const title = name;
|
||||
const Icon = SqlIcon;
|
||||
const icon = 'mdi mdi-file';
|
||||
|
||||
const onClick = () => {
|
||||
const existing = openedTabs.find((x) => x.props && x.props.storageKey == storageKey);
|
||||
@ -38,7 +35,7 @@ const savedSqlFileAppObject = () => ({ name, storageKey }, { setOpenedTabs, newQ
|
||||
}
|
||||
};
|
||||
|
||||
return { title, key, Icon, onClick, Menu };
|
||||
return { title, key, icon, onClick, Menu };
|
||||
};
|
||||
|
||||
export default savedSqlFileAppObject;
|
||||
|
@ -321,7 +321,7 @@ export default function DataGridCore(props) {
|
||||
const rows = getSelectedRowData().map((row) => _.pickBy(row, (v, col) => columns.find((x) => x.columnName == col)));
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: 'selection',
|
||||
icon: 'freetable.svg',
|
||||
icon: 'mdi mdi-table color-green-icon',
|
||||
tabComponent: 'FreeTableTab',
|
||||
props: {
|
||||
initialData: {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import ToolbarButton from '../widgets/ToolbarButton';
|
||||
import styled from 'styled-components';
|
||||
import { ReferenceIcon } from '../icons';
|
||||
import theme from '../theme';
|
||||
|
||||
const Container = styled.div`
|
||||
|
@ -83,7 +83,7 @@ export default function SqlDataGridCore(props) {
|
||||
function openQuery() {
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: 'Query',
|
||||
icon: 'sql.svg',
|
||||
icon: 'mdi mdi-file',
|
||||
tabComponent: 'QueryTab',
|
||||
props: {
|
||||
initialScript: display.getExportQuery(),
|
||||
|
@ -1,12 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { filterName } from '@dbgate/datalib';
|
||||
import { ExpandIcon, FontIcon } from '../icons';
|
||||
import InlineButton from '../widgets/InlineButton';
|
||||
import { ManagerInnerContainer } from '../datagrid/ManagerStyles';
|
||||
import SearchInput from '../widgets/SearchInput';
|
||||
import { WidgetTitle } from '../widgets/WidgetStyles';
|
||||
import keycodes from '../utility/keycodes';
|
||||
|
||||
const Row = styled.div`
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import ToolbarButton from '../widgets/ToolbarButton';
|
||||
import styled from 'styled-components';
|
||||
import { MacroIcon } from '../icons';
|
||||
import { TabPage, TabControl } from '../widgets/TabControl';
|
||||
import theme from '../theme';
|
||||
import JavaScriptEditor from '../sqleditor/JavaScriptEditor';
|
||||
@ -63,7 +62,7 @@ function MacroHeader({ selectedMacro, setSelectedMacro, onExecute }) {
|
||||
return (
|
||||
<Container>
|
||||
<Header>
|
||||
<MacroIcon />
|
||||
<span className="mdi mdi-hammer-wrench" />
|
||||
<HeaderText>{selectedMacro.title}</HeaderText>
|
||||
</Header>
|
||||
<Buttons>
|
||||
|
@ -8,7 +8,7 @@ export default function useNewFreeTable() {
|
||||
return ({ title = undefined, ...props } = {}) =>
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: title || 'Table',
|
||||
icon: 'freetable.svg',
|
||||
icon: 'mdi mdi-table color-green-icon',
|
||||
tabComponent: 'FreeTableTab',
|
||||
props,
|
||||
});
|
||||
|
@ -1,48 +1,6 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
export function getIconImage(src, props) {
|
||||
const { size = 16, style = {}, className, title } = props || {};
|
||||
if (!src) return null;
|
||||
|
||||
if (src.startsWith('fas ') || src.startsWith('far ')) {
|
||||
return <i className={src} />;
|
||||
}
|
||||
|
||||
if (src.endsWith('.svg')) {
|
||||
// eslint-disable-next-line
|
||||
src = `${process.env.PUBLIC_URL}/icons/${src}`;
|
||||
}
|
||||
// if (props.alignToLine) {
|
||||
// style["position"] = "relative";
|
||||
// style["top"] = "-2px";
|
||||
// style["marginRight"] = "4px";
|
||||
// }
|
||||
return <img width={size} height={size} src={src} style={style} className={className} title={title} />;
|
||||
}
|
||||
|
||||
export function FontIcon({ icon, ...props }) {
|
||||
let iconClass = icon;
|
||||
if (!iconClass) return null;
|
||||
let parts = iconClass.split(' ');
|
||||
const type = parts[0];
|
||||
const name = parts[1];
|
||||
parts = parts.slice(2);
|
||||
|
||||
let className = props.className || '';
|
||||
|
||||
if (type == 'fas' || type == 'far') className += ` ${type} ${name} ${parts.join(' ')}`;
|
||||
|
||||
const style = { ...props.style };
|
||||
|
||||
const last = parts[parts.length - 1];
|
||||
if (last && last != 'fa-spin') {
|
||||
style['color'] = last;
|
||||
}
|
||||
|
||||
return <i {...props} className={className} style={style} title={props.title} />;
|
||||
}
|
||||
|
||||
export function ExpandIcon({ isBlank = false, isExpanded = false, className = '', ...other }) {
|
||||
if (isBlank) {
|
||||
return <span className={`mdi mdi-minus-box-outline icon-invisible ${className}`} {...other} />;
|
||||
@ -54,75 +12,3 @@ export function ExpandIcon({ isBlank = false, isExpanded = false, className = ''
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const TableIcon = (props) => getIconImage('table2.svg', props);
|
||||
export const FreeTableIcon = (props) => getIconImage('freetable.svg', props);
|
||||
export const ViewIcon = (props) => getIconImage('view2.svg', props);
|
||||
export const ArchiveTableIcon = (props) => getIconImage('archtable.svg', props);
|
||||
export const DatabaseIcon = (props) => getIconImage('database.svg', props);
|
||||
export const ServerIcon = (props) => getIconImage('server.svg', props);
|
||||
export const MacroIcon = (props) => getIconImage('double-wrench.svg', props);
|
||||
|
||||
export const MicrosoftIcon = (props) => getIconImage('microsoft.svg', props);
|
||||
export const MySqlIcon = (props) => getIconImage('mysql.svg', props);
|
||||
export const PostgreSqlIcon = (props) => getIconImage('postgresql.svg', props);
|
||||
export const SqliteIcon = (props) => getIconImage('sqlite.svg', props);
|
||||
|
||||
export const ProcedureIcon = (props) => getIconImage('procedure2.svg', props);
|
||||
export const FunctionIcon = (props) => getIconImage('function.svg', props);
|
||||
export const TriggerIcon = (props) => getIconImage('trigger.svg', props);
|
||||
|
||||
export const HomeIcon = (props) => getIconImage('home.svg', props);
|
||||
export const PrimaryKeyIcon = (props) => getIconImage('primarykey.svg', props);
|
||||
export const ForeignKeyIcon = (props) => getIconImage('foreignkey.svg', props);
|
||||
export const ComplexKeyIcon = (props) => getIconImage('complexkey.svg', props);
|
||||
export const VariableIcon = (props) => getIconImage('variable.svg', props);
|
||||
export const UniqueIcon = (props) => getIconImage('unique.svg', props);
|
||||
export const IndexIcon = (props) => getIconImage('index.svg', props);
|
||||
|
||||
export const StartIcon = (props) => getIconImage('start.svg', props);
|
||||
export const DownCircleIcon = (props) => getIconImage('down_circle.svg', props);
|
||||
|
||||
export const ColumnIcon = (props) => getIconImage('column.svg', props);
|
||||
|
||||
export const SqlIcon = (props) => getIconImage('sql.svg', props);
|
||||
export const ExcelIcon = (props) => getIconImage('excel.svg', props);
|
||||
export const DiagramIcon = (props) => getIconImage('diagram.svg', props);
|
||||
export const QueryDesignIcon = (props) => getIconImage('querydesign.svg', props);
|
||||
export const LocalDbIcon = (props) => getIconImage('localdb.svg', props);
|
||||
export const CsvIcon = (props) => getIconImage('csv.svg', props);
|
||||
export const ChangeSetIcon = (props) => getIconImage('changeset.svg', props);
|
||||
export const BinaryFileIcon = (props) => getIconImage('binaryfile.svg', props);
|
||||
|
||||
export const ReferenceIcon = (props) => getIconImage('reference.svg', props);
|
||||
export const LinkIcon = (props) => getIconImage('link.svg', props);
|
||||
|
||||
export const SequenceIcon = (props) => getIconImage('sequence.svg', props);
|
||||
export const CheckIcon = (props) => getIconImage('check.svg', props);
|
||||
|
||||
export const LinkedServerIcon = (props) => getIconImage('linkedserver.svg', props);
|
||||
|
||||
export const EmptyIcon = (props) => getIconImage('data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=', props);
|
||||
|
||||
export const TimesRedIcon = (props) => <FontIcon name="fas fa-times red" {...props} />;
|
||||
export const TimesGreenCircleIcon = (props) => <FontIcon icon="fas fa-times-circle green" {...props} />;
|
||||
export const GrayFilterIcon = (props) => <FontIcon icon="fas fa-filter lightgray" {...props} />;
|
||||
export const ExclamationTriangleIcon = (props) => <FontIcon icon="fas fa-exclamation-triangle" {...props} />;
|
||||
export const HourGlassIcon = (props) => <FontIcon icon="fas fa-hourglass" {...props} />;
|
||||
export const InfoBlueCircleIcon = (props) => <FontIcon icon="fas fa-info-circle blue" {...props} />;
|
||||
|
||||
export const SpinnerIcon = (props) => <FontIcon icon="fas fa-spinner spin" {...props} />;
|
||||
|
||||
export function getEngineIcon(engine) {
|
||||
switch (engine) {
|
||||
case 'mssql':
|
||||
return MicrosoftIcon;
|
||||
case 'sqlite':
|
||||
return SqliteIcon;
|
||||
case 'postgres':
|
||||
return PostgreSqlIcon;
|
||||
case 'mysql':
|
||||
return MySqlIcon;
|
||||
}
|
||||
return ServerIcon;
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ import React from 'react';
|
||||
import ModalBase from './ModalBase';
|
||||
import FormStyledButton from '../widgets/FormStyledButton';
|
||||
import styled from 'styled-components';
|
||||
import { FontIcon } from '../icons';
|
||||
import { FormButtonRow } from '../utility/forms';
|
||||
import ModalHeader from './ModalHeader';
|
||||
import ModalFooter from './ModalFooter';
|
||||
import ModalContent from './ModalContent';
|
||||
|
@ -2,8 +2,6 @@ import React from 'react';
|
||||
import ModalBase from './ModalBase';
|
||||
import FormStyledButton from '../widgets/FormStyledButton';
|
||||
import styled from 'styled-components';
|
||||
import { FontIcon } from '../icons';
|
||||
import { FormButtonRow, FormSubmit } from '../utility/forms';
|
||||
import ModalHeader from './ModalHeader';
|
||||
import ModalFooter from './ModalFooter';
|
||||
import ModalContent from './ModalContent';
|
||||
|
@ -90,7 +90,7 @@ function GenerateSctriptButton({ modalState }) {
|
||||
const code = await createImpExpScript(values);
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: 'Shell',
|
||||
icon: 'trigger.svg',
|
||||
icon: 'mdi mdi-flash color-blue-icon',
|
||||
tabComponent: 'ShellTab',
|
||||
props: {
|
||||
initialScript: code,
|
||||
|
@ -2,7 +2,6 @@ import React from 'react';
|
||||
import ModalBase from './ModalBase';
|
||||
import FormStyledButton from '../widgets/FormStyledButton';
|
||||
import styled from 'styled-components';
|
||||
import { FontIcon } from '../icons';
|
||||
import { FormButtonRow, FormSubmit, FormSelectFieldRaw, FormRow, FormRadioGroupItem, FormTextFieldRaw } from '../utility/forms';
|
||||
import ModalHeader from './ModalHeader';
|
||||
import ModalFooter from './ModalFooter';
|
||||
|
@ -14,7 +14,7 @@ export default function useNewQuery() {
|
||||
return ({ title = undefined, ...props } = {}) =>
|
||||
openNewTab(setOpenedTabs, {
|
||||
title: title || 'Query',
|
||||
icon: 'sql.svg',
|
||||
icon: 'mdi mdi-file',
|
||||
tooltip,
|
||||
tabComponent: 'QueryTab',
|
||||
props: {
|
||||
|
@ -9,9 +9,11 @@ export default function ThemeHelmet() {
|
||||
.color-green { color: green; }
|
||||
.color-on-statusbar-green { color: lime; }
|
||||
.color-blue { color: blue; }
|
||||
|
||||
.color-blue-icon { color: #05A; }
|
||||
.color-magenta-icon { color: #808 }
|
||||
.color-yellow-icon { color: #880 }
|
||||
.color-green-icon { color: #0A3; }
|
||||
`}</style>
|
||||
</Helmet>
|
||||
);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { FontIcon } from '../icons';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
|
Loading…
Reference in New Issue
Block a user