mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Using placeholder in SortableTable while data is loading.
This commit is contained in:
parent
095634a4ea
commit
12850bdb8b
5 changed files with 33 additions and 35 deletions
|
|
@ -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() {
|
|||
<Divider/>
|
||||
|
||||
<SortableTable
|
||||
tableProps={{unstackable: true}}
|
||||
data={tags}
|
||||
rowFunc={(i, sortData) => <EditTagRow key={i['name']} tag={i} onDelete={localDeleteTag}
|
||||
onEdit={localEditTag}/>}
|
||||
|
|
|
|||
|
|
@ -561,23 +561,6 @@ export function ChannelsPages() {
|
|||
<Message.Content><Link to='/videos/channel/new'>Create one.</Link></Message.Content>
|
||||
</Message>
|
||||
</>
|
||||
} else if (channels === null) {
|
||||
// Placeholders while fetching
|
||||
return <>
|
||||
{header}
|
||||
<Table compact striped basic sortable size='large'>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{headers.map(i => <TableHeaderCell key={i['key']}>{i['text']}</TableHeaderCell>)}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={5}><ChannelPlaceholder/></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</>
|
||||
} 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}
|
||||
|
|
|
|||
|
|
@ -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 => <React.Fragment key={i[rowKey]}>{rowFunc(i, this.sortData)}</React.Fragment>);
|
||||
// Use placeholder while data is null.
|
||||
let rows = <TableRow><TableCell colSpan={tableHeaders.length}><TextPlaceholder/></TableCell></TableRow>;
|
||||
if (data !== null) {
|
||||
rows = data.map(i => <React.Fragment key={i[rowKey]}>{rowFunc(i, this.sortData)}</React.Fragment>);
|
||||
}
|
||||
|
||||
return <Table sortable {...this.props.tableProps}>
|
||||
<TableHeader>
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue