Removed references to tags cards

This commit is contained in:
Alejandro Celaya
2022-12-17 19:56:58 +01:00
parent 0312a0911c
commit 37caa1ad19
12 changed files with 15 additions and 381 deletions

View File

@@ -1,10 +1,7 @@
import { FC } from 'react';
import { SimpleCard } from '../utils/SimpleCard';
import { TagsModeDropdown } from '../tags/TagsModeDropdown';
import { capitalize } from '../utils/utils';
import { OrderingDropdown } from '../utils/OrderingDropdown';
import { TAGS_ORDERABLE_FIELDS } from '../tags/data/TagsListChildrenProps';
import { FormText } from '../utils/forms/FormText';
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
import { Settings, TagsSettings as TagsSettingsOptions } from './reducers/settings';
@@ -15,14 +12,6 @@ interface TagsProps {
export const TagsSettings: FC<TagsProps> = ({ settings: { tags }, setTagsSettings }) => (
<SimpleCard title="Tags" className="h-100">
<LabeledFormGroup label="Default display mode when managing tags:">
<TagsModeDropdown
mode={tags?.defaultMode ?? 'cards'}
renderTitle={(tagsMode) => capitalize(tagsMode)}
onChange={(defaultMode) => setTagsSettings({ ...tags, defaultMode })}
/>
<FormText>Tags will be displayed as <b>{tags?.defaultMode ?? 'cards'}</b>.</FormText>
</LabeledFormGroup>
<LabeledFormGroup noMargin label="Default ordering for tags list:">
<OrderingDropdown
items={TAGS_ORDERABLE_FIELDS}

View File

@@ -1,38 +0,0 @@
@import '../utils/base';
.tag-card.tag-card {
margin-bottom: .5rem;
}
.tag-card__header.tag-card__header,
.tag-card__body.tag-card__body {
padding: .75rem;
}
.tag-card__tag-title {
margin: 0;
line-height: 31px;
padding-right: 5px;
}
.tag-card__btn {
float: right;
}
.tag-card__btn--last {
margin-left: 3px;
}
.tag-card__table-cell.tag-card__table-cell {
border: none;
}
.tag-card__tag-name {
color: $mainColor;
cursor: pointer;
}
.tag-card__tag-name:hover {
color: darken($mainColor, 15%);
text-decoration: underline;
}

View File

@@ -1,89 +0,0 @@
import { Card, CardHeader, CardBody, Button, Collapse } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTrash as deleteIcon, faPencilAlt as editIcon, faLink, faEye } from '@fortawesome/free-solid-svg-icons';
import { FC, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import { prettify } from '../utils/helpers/numbers';
import { useToggle } from '../utils/helpers/hooks';
import { ColorGenerator } from '../utils/services/ColorGenerator';
import { getServerId, SelectedServer } from '../servers/data';
import { TagBullet } from './helpers/TagBullet';
import { NormalizedTag, TagModalProps } from './data';
import './TagCard.scss';
import { mutableRefToElementRef } from '../utils/helpers/components';
export interface TagCardProps {
tag: NormalizedTag;
selectedServer: SelectedServer;
displayed: boolean;
toggle: () => void;
}
const isTruncated = (el: HTMLElement | undefined): boolean => !!el && el.scrollWidth > el.clientWidth;
export const TagCard = (
DeleteTagConfirmModal: FC<TagModalProps>,
EditTagModal: FC<TagModalProps>,
colorGenerator: ColorGenerator,
) => ({ tag, selectedServer, displayed, toggle }: TagCardProps) => {
const [isDeleteModalOpen, toggleDelete] = useToggle();
const [isEditModalOpen, toggleEdit] = useToggle();
const [hasTitle,, displayTitle] = useToggle();
const titleRef = useRef<HTMLHeadingElement | undefined>();
const serverId = getServerId(selectedServer);
useEffect(() => {
if (isTruncated(titleRef.current)) {
displayTitle();
}
}, [titleRef.current]);
return (
<Card className="tag-card">
<CardHeader className="tag-card__header">
<Button
aria-label="Delete tag"
color="link"
size="sm"
className="tag-card__btn tag-card__btn--last"
onClick={toggleDelete}
>
<FontAwesomeIcon icon={deleteIcon} />
</Button>
<Button aria-label="Edit tag" color="link" size="sm" className="tag-card__btn" onClick={toggleEdit}>
<FontAwesomeIcon icon={editIcon} />
</Button>
<h5
className="tag-card__tag-title text-ellipsis"
title={hasTitle ? tag.tag : undefined}
ref={mutableRefToElementRef(titleRef)}
>
<TagBullet tag={tag.tag} colorGenerator={colorGenerator} />
<span className="tag-card__tag-name" onClick={toggle}>{tag.tag}</span>
</h5>
</CardHeader>
<Collapse isOpen={displayed}>
<CardBody className="tag-card__body">
<Link
to={`/server/${serverId}/list-short-urls/1?tags=${encodeURIComponent(tag.tag)}`}
className="btn btn-outline-secondary btn-block d-flex justify-content-between align-items-center mb-1"
>
<span className="text-ellipsis"><FontAwesomeIcon icon={faLink} className="me-2" />Short URLs</span>
<b>{prettify(tag.shortUrls)}</b>
</Link>
<Link
to={`/server/${serverId}/tag/${tag.tag}/visits`}
className="btn btn-outline-secondary btn-block d-flex justify-content-between align-items-center"
>
<span className="text-ellipsis"><FontAwesomeIcon icon={faEye} className="me-2" />Visits</span>
<b>{prettify(tag.visits)}</b>
</Link>
</CardBody>
</Collapse>
<DeleteTagConfirmModal tag={tag.tag} toggle={toggleDelete} isOpen={isDeleteModalOpen} />
<EditTagModal tag={tag.tag} toggle={toggleEdit} isOpen={isEditModalOpen} />
</Card>
);
};

View File

@@ -1,32 +0,0 @@
import { FC, useState } from 'react';
import { splitEvery } from 'ramda';
import { Row } from 'reactstrap';
import { TagCardProps } from './TagCard';
import { TagsListChildrenProps } from './data/TagsListChildrenProps';
const { ceil } = Math;
const TAGS_GROUPS_AMOUNT = 4;
export const TagsCards = (TagCard: FC<TagCardProps>): FC<TagsListChildrenProps> => ({ sortedTags, selectedServer }) => {
const [displayedTag, setDisplayedTag] = useState<string | undefined>();
const tagsCount = sortedTags.length;
const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), sortedTags);
return (
<Row>
{tagsGroups.map((group, index) => (
<div key={index} className="col-md-6 col-xl-3">
{group.map((tag) => (
<TagCard
key={tag.tag}
tag={tag}
selectedServer={selectedServer}
displayed={displayedTag === tag.tag}
toggle={() => setDisplayedTag(displayedTag !== tag.tag ? tag.tag : undefined)}
/>
))}
</div>
))}
</Row>
);
};

View File

@@ -8,17 +8,11 @@ import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
import { Result } from '../utils/Result';
import { ShlinkApiError } from '../api/ShlinkApiError';
import { Topics } from '../mercure/helpers/Topics';
import { Settings, TagsMode } from '../settings/reducers/settings';
import { Settings } from '../settings/reducers/settings';
import { determineOrderDir, sortList } from '../utils/helpers/ordering';
import { OrderingDropdown } from '../utils/OrderingDropdown';
import { TagsList as TagsListState } from './reducers/tagsList';
import {
TagsOrderableFields,
TAGS_ORDERABLE_FIELDS,
TagsListChildrenProps,
TagsOrder,
} from './data/TagsListChildrenProps';
import { TagsModeDropdown } from './TagsModeDropdown';
import { TagsOrderableFields, TAGS_ORDERABLE_FIELDS, TagsOrder } from './data/TagsListChildrenProps';
import { NormalizedTag } from './data';
import { TagsTableProps } from './TagsTable';
@@ -30,10 +24,9 @@ export interface TagsListProps {
settings: Settings;
}
export const TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsTableProps>) => boundToMercureHub((
export const TagsList = (TagsTable: FC<TagsTableProps>) => boundToMercureHub((
{ filterTags, forceListTags, tagsList, selectedServer, settings }: TagsListProps,
) => {
const [mode, setMode] = useState<TagsMode>(settings.tags?.defaultMode ?? 'cards');
const [order, setOrder] = useState<TagsOrder>(settings.tags?.defaultOrdering ?? {});
const resolveSortedTags = pipe(
() => tagsList.filteredTags.map((tag): NormalizedTag => ({
@@ -73,26 +66,21 @@ export const TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<Tag
const sortedTags = resolveSortedTags();
return mode === 'cards'
? <TagsCards sortedTags={sortedTags} selectedServer={selectedServer} />
: (
<TagsTable
sortedTags={sortedTags}
selectedServer={selectedServer}
currentOrder={order}
orderByColumn={orderByColumn}
/>
);
return (
<TagsTable
sortedTags={sortedTags}
selectedServer={selectedServer}
currentOrder={order}
orderByColumn={orderByColumn}
/>
);
};
return (
<>
<SearchField className="mb-3" onChange={filterTags} />
<Row className="mb-3">
<div className="col-lg-6">
<TagsModeDropdown mode={mode} onChange={setMode} />
</div>
<div className="col-lg-6 mt-3 mt-lg-0">
<div className="col-lg-6 offset-lg-6">
<OrderingDropdown
items={TAGS_ORDERABLE_FIELDS}
order={order}

View File

@@ -1,23 +0,0 @@
import { FC } from 'react';
import { DropdownItem } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBars as listIcon, faThLarge as cardsIcon } from '@fortawesome/free-solid-svg-icons';
import { DropdownBtn } from '../utils/DropdownBtn';
import { TagsMode } from '../settings/reducers/settings';
interface TagsModeDropdownProps {
mode: TagsMode;
onChange: (newMode: TagsMode) => void;
renderTitle?: (mode: TagsMode) => string;
}
export const TagsModeDropdown: FC<TagsModeDropdownProps> = ({ mode, onChange, renderTitle }) => (
<DropdownBtn text={renderTitle?.(mode) ?? `Display mode: ${mode}`}>
<DropdownItem active={mode === 'cards'} onClick={() => onChange('cards')}>
<FontAwesomeIcon icon={cardsIcon} fixedWidth className="me-1" /> Cards
</DropdownItem>
<DropdownItem active={mode === 'list'} onClick={() => onChange('list')}>
<FontAwesomeIcon icon={listIcon} fixedWidth className="me-1" /> List
</DropdownItem>
</DropdownBtn>
);

View File

@@ -1,7 +1,6 @@
import { prop } from 'ramda';
import Bottle, { IContainer } from 'bottlejs';
import { TagsSelector } from '../helpers/TagsSelector';
import { TagCard } from '../TagCard';
import { DeleteTagConfirmModal } from '../helpers/DeleteTagConfirmModal';
import { EditTagModal } from '../helpers/EditTagModal';
import { TagsList } from '../TagsList';
@@ -9,7 +8,6 @@ import { filterTags, listTags, tagsListReducerCreator } from '../reducers/tagsLi
import { tagDeleted, tagDeleteReducerCreator } from '../reducers/tagDelete';
import { editTag, tagEdited, tagEditReducerCreator } from '../reducers/tagEdit';
import { ConnectDecorator } from '../../container/types';
import { TagsCards } from '../TagsCards';
import { TagsTable } from '../TagsTable';
import { TagsTableRow } from '../TagsTableRow';
@@ -18,20 +16,17 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('TagsSelector', TagsSelector, 'ColorGenerator');
bottle.decorator('TagsSelector', connect(['tagsList', 'settings'], ['listTags']));
bottle.serviceFactory('TagCard', TagCard, 'DeleteTagConfirmModal', 'EditTagModal', 'ColorGenerator');
bottle.serviceFactory('DeleteTagConfirmModal', () => DeleteTagConfirmModal);
bottle.decorator('DeleteTagConfirmModal', connect(['tagDelete'], ['deleteTag', 'tagDeleted']));
bottle.serviceFactory('EditTagModal', EditTagModal, 'ColorGenerator');
bottle.decorator('EditTagModal', connect(['tagEdit'], ['editTag', 'tagEdited']));
bottle.serviceFactory('TagsCards', TagsCards, 'TagCard');
bottle.serviceFactory('TagsTableRow', TagsTableRow, 'DeleteTagConfirmModal', 'EditTagModal', 'ColorGenerator');
bottle.serviceFactory('TagsTable', TagsTable, 'TagsTableRow');
bottle.serviceFactory('TagsList', TagsList, 'TagsCards', 'TagsTable');
bottle.serviceFactory('TagsList', TagsList, 'TagsTable');
bottle.decorator('TagsList', connect(
['tagsList', 'selectedServer', 'mercureInfo', 'settings'],
['forceListTags', 'filterTags', 'createNewVisits', 'loadMercureInfo'],