);
};
const getSortingOrderColumn = (s: SortingOrder): string => {
switch (s) {
case 'name': return 'title';
case 'size': return 'size';
}
};
const getNextSortingOrderType = (s: SortingType): SortingType => {
if (s === 'asc') {
return 'desc';
} else {
return 'asc';
}
};
const defaultMaxResources = 10000;
const searchMaxResources = 1000;
class ResourceScreenComponent extends React.Component {
public constructor(props: Props) {
super(props);
this.state = {
resources: undefined,
filter: '',
sorting: {
type: 'asc',
order: 'name',
},
isLoading: false,
};
}
private get maxResources() {
// Use a smaller maximum when searching for performance -- results update
// when the search input changes.
if (this.state.filter) {
return searchMaxResources;
} else {
return defaultMaxResources;
}
}
private reloadResourcesCounter = 0;
public async reloadResources() {
this.setState({ isLoading: true });
this.reloadResourcesCounter ++;
const currentCounterValue = this.reloadResourcesCounter;
let searchOptions: Partial = {};
if (this.state.filter) {
const search = `%${this.state.filter}%`;
searchOptions = {
where: 'id LIKE ? OR title LIKE ?',
whereParams: [search, search],
};
}
const resources = await Resource.all({
order: [{
by: getSortingOrderColumn(this.state.sorting.order),
dir: this.state.sorting.type,
caseInsensitive: true,
}],
limit: this.maxResources,
fields: ['title', 'id', 'size', 'file_extension'],
...searchOptions,
});
const cancelled = currentCounterValue !== this.reloadResourcesCounter;
if (cancelled) return;
this.setState({ resources, isLoading: false });
}
public componentDidMount() {
void this.reloadResources();
}
public componentDidUpdate(_prevProps: Props, prevState: State) {
if (prevState.sorting !== this.state.sorting || prevState.filter !== this.state.filter) {
void this.reloadResources();
}
}
public onResourceDelete(resource: InnerResource) {
const ok = bridge().showConfirmMessageBox(_('Delete attachment "%s"?', resource.title), {
buttons: [_('Delete'), _('Cancel')],
defaultId: 1,
});
if (!ok) {
return;
}
Resource.delete(resource.id, { sourceDescription: 'ResourceScreen' })
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
.catch((error: Error) => {
console.error(error);
bridge().showErrorMessageBox(error.message);
})
// eslint-disable-next-line promise/prefer-await-to-then -- Old code before rule was applied
.finally(() => {
void this.reloadResources();
});
}
public openResource(resource: InnerResource) {
const resourcePath = Resource.fullPath(resource);
const ok = bridge().openItem(resourcePath);
if (!ok) {
bridge().showErrorMessageBox(`This file could not be opened: ${resourcePath}`);
}
}
public onToggleSortOrder(sortOrder: SortingOrder) {
let newSorting = { ...this.state.sorting };
if (sortOrder === this.state.sorting.order) {
newSorting.type = getNextSortingOrderType(newSorting.type);
} else {
newSorting = {
order: sortOrder,
type: 'desc',
};
}
this.setState({ sorting: newSorting });
}
public onFilterUpdate = (updateEvent: React.ChangeEvent) => {
this.setState({ filter: updateEvent.target.value });
};
public render() {
const style = this.props.style;
const theme = themeStyle(this.props.themeId);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const rootStyle: any = {
...style,
overflowY: 'scroll',
color: theme.color,
padding: 20,
boxSizing: 'border-box',
flex: 1,
};
// rootStyle.height = style.height - 35; // Minus the header height
delete rootStyle.height;
delete rootStyle.width;
const containerHeight = style.height;
return (
{
_('This is an advanced tool to show the attachments that are linked to your notes. Please be careful when deleting one of them as they cannot be restored afterwards.')
}