Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GN-4693: Insert LPDC #429

Merged
merged 6 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hungry-badgers-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@lblod/ember-rdfa-editor-lblod-plugins": minor
---

GN-4693: Insert LPDC
19 changes: 19 additions & 0 deletions addon/components/lpdc-plugin/lpdc-insert.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{! @glint-nocheck: not typesafe yet }}
<li class='au-c-list__item'>
<AuButton
@icon={{this.AddIcon}}
@iconAlignment='left'
@skin='link'
{{on 'click' this.openModal}}
@disabled={{this.isButtonDisabled}}
>
{{t 'lpdc-plugin.insert.title'}}
</AuButton>
</li>

<LpdcPlugin::LpdcModal
@open={{this.showModal}}
@closeModal={{this.closeModal}}
@config={{@config}}
@onLpdcInsert={{this.onLpdcInsert}}
/>
93 changes: 93 additions & 0 deletions addon/components/lpdc-plugin/lpdc-insert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { AddIcon } from '@appuniversum/ember-appuniversum/components/icons/add';

import { SayController } from '@lblod/ember-rdfa-editor';
import { sayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
import { addProperty } from '@lblod/ember-rdfa-editor/commands';
import {
LPDC,
type LpdcPluginConfig,
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/lpdc-plugin';
import { v4 as uuidv4 } from 'uuid';
import { getCurrentBesluitRange } from '../../plugins/besluit-topic-plugin/utils/helpers';
import { SRO } from '../../utils/constants';

interface Args {
controller: SayController;
config: LpdcPluginConfig;
}

export default class LpdcPluginsInsertComponent extends Component<Args> {
AddIcon = AddIcon;

@tracked showModal = false;

get controller() {
return this.args.controller;
}

@action
openModal() {
this.controller.focus();
this.showModal = true;
}

@action
closeModal() {
this.showModal = false;
}

get isButtonDisabled() {
return !getCurrentBesluitRange(this.controller);
}

@action
onLpdcInsert(lpdc: LPDC) {
const currentBesluitRange = getCurrentBesluitRange(this.controller);

const resource =
(currentBesluitRange &&
'node' in currentBesluitRange &&
(currentBesluitRange.node.attrs.subject as string)) ||
undefined;

if (!resource) {
throw new Error('No besluit found in selection');
}

const rdfaId = uuidv4();
const uri = lpdc.uri;
const name = lpdc.name;

this.controller.withTransaction(
(tr) => {
const node = this.controller.schema.node(
'inline_rdfa',
{
rdfaNodeType: 'resource',
__rdfaId: rdfaId,
subject: uri,
},
[this.controller.schema.text(name)],
);

return tr.replaceSelectionWith(node);
},
{ view: this.controller.mainEditorView },
);

this.controller.doCommand(
addProperty({
resource,
property: {
predicate: SRO('bekrachtigt').full,
object: sayDataFactory.resourceNode(uri),
},
}),
);

this.closeModal();
}
}
44 changes: 44 additions & 0 deletions addon/components/lpdc-plugin/lpdc-modal.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{{! @glint-nocheck: not typesafe yet }}
<AuModal
@modalOpen={{@open}}
@closeModal={{this.closeModal}}
@title={{t 'lpdc-plugin.modal.title'}}
@size='large'
@padding='none'
as |modal|
>
<modal.Body>
<AuMainContainer class='snippet-modal--main-container' as |mc|>
<mc.content @scroll={{true}}>
<div class='snippet-modal--list-container'>
{{#if this.error}}
<Common::Search::AlertLoadError
@error={{this.error}}
class='au-u-margin-top-none'
/>
{{else}}
<LpdcPlugin::LpdcTableView
@lpdc={{this.lpdcResource.value}}
@isLoading={{this.lpdcResource.isRunning}}
@onLpdcInsert={{@onLpdcInsert}}
@nameFilter={{this.searchText}}
@pageNumber={{this.pageNumber}}
/>
{{/if}}
</div>
<AuToolbar
@border='top'
@size='large'
@nowrap={{true}}
@reverse={{true}}
>
<AuButtonGroup>
<AuButton @skin='secondary' {{on 'click' this.closeModal}}>
{{t 'lpdc-plugin.modal.close'}}
</AuButton>
</AuButtonGroup>
</AuToolbar>
</mc.content>
</AuMainContainer>
</modal.Body>
</AuModal>
79 changes: 79 additions & 0 deletions addon/components/lpdc-plugin/lpdc-modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { restartableTask, timeout } from 'ember-concurrency';
import { task as trackedTask } from 'ember-resources/util/ember-concurrency';

import { tracked } from '@glimmer/tracking';

import {
fetchLpdcs,
LPDC,
type LpdcPluginConfig,
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/lpdc-plugin';
import { trackedReset } from 'tracked-toolbox';

interface Signature {
Args: {
config: LpdcPluginConfig;
onLpdcInsert: (lpdc: LPDC) => void;
closeModal: () => void;
open: boolean;
};
}

export default class LpdcPluginModalComponent extends Component<Signature> {
// Filtering
@tracked searchText: string | null = null;

// Display
@tracked error: unknown;

/**
* Paginating the search results
*/
@trackedReset('searchText')
pageNumber = 0;

get config() {
return this.args.config;
}

@action
closeModal() {
this.args.closeModal();
}

lpdcSearch = restartableTask(async () => {
await timeout(100);
this.error = null;
const abortController = new AbortController();
try {
const results = await fetchLpdcs({
filter: {
name: this.searchText ?? undefined,
},
pageNumber: this.pageNumber,
config: this.args.config,
});

return Object.assign(results.lpdc, {
meta: results.meta,
});
} catch (error) {
this.error = error;
return [];
} finally {
//Abort all requests now that this task has either successfully finished or has been cancelled
abortController.abort();
}
});

lpdcResource = trackedTask(this, this.lpdcSearch, () => [
this.searchText,
this.pageNumber,
]);

@action onSearchTextChange(event: InputEvent): void {
this.searchText = (event.target as HTMLInputElement).value;
}
}
53 changes: 53 additions & 0 deletions addon/components/lpdc-plugin/lpdc-table-view.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{{! @glint-nocheck: not typesafe yet }}
<div class='say-snippet-lists-table'>
{{#let
(t 'lpdc-plugin.table.header.name')
(t 'lpdc-plugin.search.placeholder')
(t 'lpdc-plugin.modal.insert')
as |name search insert|
}}
<AuDataTable
@content={{this.lpdc}}
@isLoading={{@isLoading}}
@noDataMessage={{t 'common.search.no-results'}}
@sort={{@sort}}
@page={{@pageNumber}}
@size={{25}}
as |t|
>
<t.menu as |menu|>
<menu.general>
<AuToolbar class='au-o-box' as |Group|>
<Group />
<Group class='au-c-toolbar__group--center'>
<AuDataTableTextSearch
@wait={{500}}
@filter={{@nameFilter}}
@placeholder={{search}}
/>
</Group>
</AuToolbar>
</menu.general>
</t.menu>
<t.content as |c|>
<c.header>
<AuDataTableThSortable
@field='name'
@label={{name}}
@currentSorting={{@sort}}
@class='data-table__header-title'
/>
<th class='snippet-list-table-select-column'>{{insert}}</th>
</c.header>
<c.body as |row|>
<td>{{row.name}}</td>
<td class='snippet-list-table-select-column'>
<AuButton {{on 'click' (fn @onLpdcInsert row)}}>
{{insert}}
</AuButton>
</td>
</c.body>
</t.content>
</AuDataTable>
{{/let}}
</div>
23 changes: 23 additions & 0 deletions addon/components/lpdc-plugin/lpdc-table-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Component from '@glimmer/component';
import { LPDC } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/lpdc-plugin';

interface Args {
lpdc: LPDC[] & {
meta: {
count: number;
pagination: { first: { number: number }; last: { number: number } };
};
};
isLoading: boolean;
onLpdcInsert: (lpdc: LPDC) => void;
// Filtering
nameFilter: string | null;
// Pagination
pageNumber: number;
}

export default class LpdcTableViewComponent extends Component<Args> {
get lpdc() {
return this.args.lpdc;
}
}
Loading