diff --git a/.changeset/small-falcons-march.md b/.changeset/small-falcons-march.md
new file mode 100644
index 00000000..1c6f988c
--- /dev/null
+++ b/.changeset/small-falcons-march.md
@@ -0,0 +1,5 @@
+---
+"frontend-reglementaire-bijlage": minor
+---
+
+Add utility button to quickly connect all articles in a snippet to an imported resource
diff --git a/app/components/connect-articles-to-imported-resource.hbs b/app/components/connect-articles-to-imported-resource.hbs
new file mode 100644
index 00000000..48ba39cb
--- /dev/null
+++ b/app/components/connect-articles-to-imported-resource.hbs
@@ -0,0 +1,29 @@
+
+
+ {{!-- template-lint-disable no-bare-strings --}}
+
+ Connect articles to imported resource
+
+
+
+
+ {{!-- template-lint-disable no-bare-strings --}}
+ {{#if this.docIsConnected}}
+ Connected
+ {{else}}
+ Connect
+ {{/if}}
+
+
+
\ No newline at end of file
diff --git a/app/components/connect-articles-to-imported-resource.js b/app/components/connect-articles-to-imported-resource.js
new file mode 100644
index 00000000..b60eec93
--- /dev/null
+++ b/app/components/connect-articles-to-imported-resource.js
@@ -0,0 +1,66 @@
+import Component from '@glimmer/component';
+import { action } from '@ember/object';
+import { addProperty } from '@lblod/ember-rdfa-editor/commands/rdfa-commands/add-property';
+import { sayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
+import { IMPORTED_RESOURCES_ATTR } from '@lblod/ember-rdfa-editor/plugins/imported-resources';
+
+export default class ConnectArticlesToImportedResourceComponent extends Component {
+ get controller() {
+ return this.args.controller;
+ }
+
+ get importedResource() {
+ return this.args.importedResource;
+ }
+
+ get nonConnectedArticleURIs() {
+ const doc = this.controller.mainEditorState.doc;
+ const articleURIs = new Set();
+ doc.descendants((node) => {
+ if (
+ node.type === this.controller.schema.nodes.structure &&
+ node.attrs.structureType === 'article' &&
+ !this.isConnected(node)
+ ) {
+ articleURIs.add(node.attrs.subject);
+ }
+ });
+ return articleURIs;
+ }
+
+ get docIsConnected() {
+ return this.nonConnectedArticleURIs.size === 0;
+ }
+
+ @action
+ connect() {
+ const articleURIs = this.nonConnectedArticleURIs;
+ for (const uri of articleURIs) {
+ this.controller.doCommand(
+ addProperty({
+ resource: this.importedResource,
+ property: {
+ predicate: 'http://data.europa.eu/eli/ontology#has_part',
+ object: sayDataFactory.resourceNode(uri),
+ },
+ isNewImportedResource: !this.documentImportedResources.includes(
+ this.importedResource,
+ ),
+ }),
+ );
+ }
+ }
+
+ get documentImportedResources() {
+ return this.controller.getDocumentAttribute(IMPORTED_RESOURCES_ATTR) ?? [];
+ }
+
+ isConnected(articleNode) {
+ return Boolean(
+ (articleNode.attrs.backlinks ?? []).some(
+ (backlink) =>
+ backlink.predicate == 'http://data.europa.eu/eli/ontology#has_part',
+ ),
+ );
+ }
+}
diff --git a/app/controllers/snippet-management/edit/edit-snippet.js b/app/controllers/snippet-management/edit/edit-snippet.js
index c3cee1bf..e77d2b12 100644
--- a/app/controllers/snippet-management/edit/edit-snippet.js
+++ b/app/controllers/snippet-management/edit/edit-snippet.js
@@ -417,4 +417,8 @@ export default class SnippetManagementEditSnippetController extends Controller {
);
return saveCollatedImportedResources(list);
});
+
+ get importedDecisionUri() {
+ return `http://example.org/imported-decision-${this.model.snippetList.id}`;
+ }
}
diff --git a/app/templates/snippet-management/edit/edit-snippet.hbs b/app/templates/snippet-management/edit/edit-snippet.hbs
index bd59e13a..471dbb6a 100644
--- a/app/templates/snippet-management/edit/edit-snippet.hbs
+++ b/app/templates/snippet-management/edit/edit-snippet.hbs
@@ -84,6 +84,10 @@
<:aside>
{{#if this.editor}}
+