From 12850bdb8b36d2d48ceddb95aefad732544ad702 Mon Sep 17 00:00:00 2001 From: Roland Date: Tue, 12 Sep 2023 22:03:51 -0600 Subject: [PATCH] Using placeholder in SortableTable while data is loading. --- app/src/Tags.js | 3 ++- app/src/components/Channels.js | 18 +--------------- app/src/components/SortableTable.js | 11 +++++++--- wrolpi/tags.py | 4 +++- wrolpi/test/test_tags.py | 32 +++++++++++++++++------------ 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/app/src/Tags.js b/app/src/Tags.js index acca468d..885ede22 100644 --- a/app/src/Tags.js +++ b/app/src/Tags.js @@ -228,7 +228,7 @@ function EditTagsModal() { {key: 'delete', text: 'Delete', sortBy: null, width: 2}, {key: 'edit', text: 'Edit', sortBy: null, width: 2}, {key: 'name', text: 'Name', sortBy: 'name', width: 8}, - {key: 'count', text: 'Count', sortBy: 'file_group_count', width: 2}, + {key: 'count', text: 'Count', sortBy: i => i['file_group_count'] + i['zim_entry_count'], width: 2}, ]; return <> @@ -267,6 +267,7 @@ function EditTagsModal() { } diff --git a/app/src/components/Channels.js b/app/src/components/Channels.js index c11080a5..e004d48c 100644 --- a/app/src/components/Channels.js +++ b/app/src/components/Channels.js @@ -561,23 +561,6 @@ export function ChannelsPages() { Create one. - } else if (channels === null) { - // Placeholders while fetching - return <> - {header} - - - - {headers.map(i => {i['text']})} - - - - - - - -
- } else if (channels === undefined) { return <> {header} @@ -590,6 +573,7 @@ export function ChannelsPages() { const re = new RegExp(_.escapeRegExp(searchStr), 'i'); filteredChannels = channels.filter(i => re.test(i['name'])); } + console.log(`filteredChannels=${filteredChannels === null}`); return <> {header} diff --git a/app/src/components/SortableTable.js b/app/src/components/SortableTable.js index b7c29dbe..4757035d 100644 --- a/app/src/components/SortableTable.js +++ b/app/src/components/SortableTable.js @@ -1,7 +1,8 @@ import React from "react"; import _ from "lodash"; -import {TableBody, TableHeader, TableHeaderCell, TableRow} from "semantic-ui-react"; +import {TableBody, TableCell, TableHeader, TableHeaderCell, TableRow} from "semantic-ui-react"; import {Table} from "./Theme"; +import {TextPlaceholder} from "./Placeholder"; export class SortableTable extends React.Component { constructor(props) { @@ -41,7 +42,7 @@ export class SortableTable extends React.Component { let {direction} = this.state; rowKey = rowKey || 'key'; - const data = this.sortData(this.props['data']); + const data = this.props['data'] ? this.sortData(this.props['data']) : null; const tableHeader = (spec) => { const {key, text, sortBy, width} = spec; @@ -59,7 +60,11 @@ export class SortableTable extends React.Component { } } - const rows = data.map(i => {rowFunc(i, this.sortData)}); + // Use placeholder while data is null. + let rows = ; + if (data !== null) { + rows = data.map(i => {rowFunc(i, this.sortData)}); + } return diff --git a/wrolpi/tags.py b/wrolpi/tags.py index 5cecb5f1..f3c8e643 100644 --- a/wrolpi/tags.py +++ b/wrolpi/tags.py @@ -97,7 +97,7 @@ class Tag(ModelHelper, Base): def has_relations(self) -> bool: """Returns True if this Tag has been used with any FileGroups or Zim Entries.""" - return not self.tag_files and not self.tag_zim_entries + return bool(self.tag_files or self.tag_zim_entries) class TagsConfig(ConfigFile): @@ -308,6 +308,7 @@ def import_tags_config(session: Session = None): # Maintainer added a Tag to the config manually, or DB was wiped. tag = Tag(name=name, color=attrs['color']) new_tags.append(tag) + logger.info(f'Creating new {tag}') tag.color = attrs['color'] if new_tags: @@ -391,6 +392,7 @@ def import_tags_config(session: Session = None): elif not tag: logger.warning(f'Cannot find Tag for {repr(str(zim_path))}') + # Delete missing Tags last in case they are used above. if config.tags: config_tag_names = set(config.tags.keys()) for tag in session.query(Tag): diff --git a/wrolpi/test/test_tags.py b/wrolpi/test/test_tags.py index 9c34b344..1374e34e 100644 --- a/wrolpi/test/test_tags.py +++ b/wrolpi/test/test_tags.py @@ -141,7 +141,8 @@ def test_tags_crud(test_session, test_client, example_pdf, assert_tags_config): request, response = test_client.post('/api/tag/1', content=json.dumps(content)) assert response.status_code == HTTPStatus.OK request, response = test_client.get('/api/tag') - assert response.json['tags'] == [dict(name='ガーデン', color='#000000', id=1, file_group_count=1, zim_entry_count=0)] + assert response.json['tags'] == [ + dict(name='ガーデン', color='#000000', id=1, file_group_count=1, zim_entry_count=0)] assert_tags_config(tags={'ガーデン': {'color': '#000000'}}) # Conflicting names return an error. @@ -250,24 +251,29 @@ async def test_import_tags_delete_missing(test_session, test_directory, test_tag assert tag3.name in test_tags_config.read_text() assert tag4.name in test_tags_config.read_text() - # Delete tag1 and tag2 from the config. + # Delete all tags but tag3. config = tags.get_tags_config() config_dict = config.dict() - config_dict['tags'] = {k: v for k, v in config.tags.items() if k not in [tag1.name, tag2.name, tag4.name]} + config_dict['tags'] = {k: v for k, v in config.tags.items() if k == tag3.name} config.update(config_dict) + config.initialize() + # Tag Files and Tag Zims are untouched. Only tag3 is left. + assert len(config.tag_files) == 1 + assert len(config.tag_zims) == 1 + assert len(config.tags) == 1 # Import the config. Only unused Tags not in the config are deleted. tags.import_tags_config() - assert { - tag1.name, # tag1 is used by FileGroup. - # tag2.name, tag2 is unused, and deleted. - tag3.name, # tag3 was not deleted. - tag4.name, # tag4 is used by ZimEntry. - } == {i.name for i in test_session.query(tags.Tag)} + assert {i.name for i in test_session.query(tags.Tag)} == { + tag1.name, # tag1 is used by FileGroup. + # tag2.name, tag2 is unused, and deleted. + tag3.name, # tag3 was not deleted. + tag4.name, # tag4 is used by ZimEntry. + } # DB is written to config with only those Tags left. tags.schedule_save() - assert f'{tag1.name}:' in test_tags_config.read_text() - assert f'{tag2.name}:' not in test_tags_config.read_text() - assert f'{tag3.name}:' in test_tags_config.read_text() - assert f'{tag4.name}:' in test_tags_config.read_text() + # Tags that are used are restored. + assert len(config.tag_files) == 1 + assert len(config.tag_zims) == 1 + assert len(config.tags) == 3