diff --git a/addon/adapters/file.js b/addon/adapters/file.js
index d8ccd871..60476157 100644
--- a/addon/adapters/file.js
+++ b/addon/adapters/file.js
@@ -25,17 +25,5 @@ export default function (BaseClass) {
return ajaxOptions;
}
-
- // Overwrite and replicate the query function,
- // because ember doesnt pass adapterOptions to urlForQuery
- query(_, type, query, __, options) {
- let url = this.buildURL(type.modelName, null, null, "query", query);
-
- if (options?.adapterOptions?.customEndpoint) {
- url = `${this.buildURL()}/${options.adapterOptions.customEndpoint}`;
- }
-
- return this.ajax(url, "GET", { data: query });
- }
};
}
diff --git a/addon/adapters/search-result.js b/addon/adapters/search-result.js
new file mode 100644
index 00000000..02f492cf
--- /dev/null
+++ b/addon/adapters/search-result.js
@@ -0,0 +1,15 @@
+export default function (BaseClass) {
+ return class SearchResultAdapter extends BaseClass {
+ // Overwrite and replicate the query function,
+ // because ember doesnt pass adapterOptions to urlForQuery
+ query(_, type, query, __, options) {
+ let url = this.buildURL(type.modelName, null, null, "query", query);
+
+ if (options?.adapterOptions?.customEndpoint) {
+ url = `${this.buildURL()}/${options.adapterOptions.customEndpoint}`;
+ }
+
+ return this.ajax(url, "GET", { data: query });
+ }
+ };
+}
diff --git a/addon/components/document-view.hbs b/addon/components/document-view.hbs
index ff9f4293..b5fb5449 100644
--- a/addon/components/document-view.hbs
+++ b/addon/components/document-view.hbs
@@ -42,7 +42,6 @@
>
{{! List & Grid View }}
{{#if this.listView}}
diff --git a/addon/components/document-view.js b/addon/components/document-view.js
index f680f7e0..3be71d2d 100644
--- a/addon/components/document-view.js
+++ b/addon/components/document-view.js
@@ -61,17 +61,44 @@ export default class DocumentViewComponent extends Component {
@task
*fetchDocuments() {
- const documents = yield this.store.query("document", {
- include: "category,files,tags",
- filter: this.args.filters || {},
- sort: this.sort ? `${this.sortDirection}${this.sort}` : "",
- });
+ let documents = [];
+ const filter = this.args.filters || {};
+ if (filter.query) {
+ filter.only_newest = true;
+ const searchResult = yield this.store.query(
+ "search-result",
+ {
+ include: "document,matched_file",
+ filter,
+ page: { number: 1 },
+ },
+ {
+ adapterOptions: {
+ customEndpoint: "search",
+ },
+ },
+ );
+
+ documents = searchResult.reduce((acc, result) => {
+ if (!acc.some((doc) => doc.id === result.document.id)) {
+ acc.push(result.document);
+ }
+ return acc;
+ }, []);
+ } else {
+ documents = yield this.store.query("document", {
+ include: "category,files,tags",
+ filter,
+ sort: this.sort ? `${this.sortDirection}${this.sort}` : "",
+ });
+ }
+
+ this.initialiseDocumentSelection(documents);
return yield this.config.documentsPostProcess(documents);
}
- @task
- *initialiseDocumentSelection() {
+ initialiseDocumentSelection(docs) {
let docIds = [];
if (this.router.externalRouter.currentRoute?.queryParams?.document) {
docIds = decodeURIComponent(
@@ -79,10 +106,6 @@ export default class DocumentViewComponent extends Component {
).split(",");
}
if (docIds.length !== 0) {
- const docs = yield this.store.query("document", {
- filter: this.args.filters || {},
- sort: this.sort ? `${this.sortDirection}${this.sort}` : "",
- });
const selectedDocs = [...docs].filter((doc) => docIds.includes(doc.id));
selectedDocs.forEach((doc) => this.documents.selectDocument(doc));
}
diff --git a/addon/components/file-search.hbs b/addon/components/search-view.hbs
similarity index 100%
rename from addon/components/file-search.hbs
rename to addon/components/search-view.hbs
diff --git a/addon/components/file-search.js b/addon/components/search-view.js
similarity index 81%
rename from addon/components/file-search.js
rename to addon/components/search-view.js
index ea040004..e9020ee6 100644
--- a/addon/components/file-search.js
+++ b/addon/components/search-view.js
@@ -5,7 +5,7 @@ import { tracked } from "@glimmer/tracking";
import { task } from "ember-concurrency";
import { trackedFunction } from "reactiveweb/function";
-export default class DocumentViewComponent extends Component {
+export default class SearchViewComponent extends Component {
@service store;
@service("alexandria-config") config;
@service("alexandria-documents") documents;
@@ -22,10 +22,10 @@ export default class DocumentViewComponent extends Component {
return [];
}
- const files = await this.store.query(
- "file",
+ const search = await this.store.query(
+ "search-result",
{
- include: "document,renderings",
+ include: "document,matched_file",
filter: this.args.filters || {},
page: { number: 1 },
},
@@ -36,14 +36,7 @@ export default class DocumentViewComponent extends Component {
},
);
- const documents = Array.from(
- new Map(
- files.map((file) => [
- file.document.id,
- this.store.peekRecord("document", file.document.id),
- ]),
- ).values(),
- );
+ const documents = search.map((result) => result.document);
return await this.config.documentsPostProcess(documents);
});
diff --git a/addon/components/search.hbs b/addon/components/search.hbs
index 761322ee..c975fbb0 100644
--- a/addon/components/search.hbs
+++ b/addon/components/search.hbs
@@ -3,7 +3,7 @@
class="uk-background-default uk-search uk-search-default uk-width-1"
{{on "submit" this.onSubmit}}
>
-
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/search.js b/addon/components/search.js
index c47cdeda..08d11490 100644
--- a/addon/components/search.js
+++ b/addon/components/search.js
@@ -21,8 +21,16 @@ export default class SearchComponent extends Component {
}
this.router.transitionTo(this.router.currentRouteName, {
- queryParams: { search: search || undefined, category: undefined },
+ queryParams: { search: search || undefined },
});
},
);
+
+ @action
+ resetSearch(event) {
+ event.preventDefault();
+ this.router.transitionTo(this.router.currentRouteName, {
+ queryParams: { search: undefined },
+ });
+ }
}
diff --git a/addon/controllers/index.js b/addon/controllers/index.js
index b391ab28..edf1b0a9 100644
--- a/addon/controllers/index.js
+++ b/addon/controllers/index.js
@@ -25,10 +25,10 @@ export default class IndexController extends Controller {
get documentFilters() {
let filters = {
- category: this.category,
+ categories: this.category,
tags: this.tags.length ? this.tags.join(",") : undefined,
marks: this.marks.length ? this.marks.join(",") : undefined,
- search: this.search,
+ query: this.search,
activeGroup: this.activeGroup,
};
diff --git a/addon/controllers/search.js b/addon/controllers/search.js
index 89de58d9..69db7d44 100644
--- a/addon/controllers/search.js
+++ b/addon/controllers/search.js
@@ -12,6 +12,7 @@ export default class SearchController extends Controller {
get filters() {
const filters = {
+ onlyNewest: true,
query: this.search,
};
diff --git a/addon/models/search-result.js b/addon/models/search-result.js
new file mode 100644
index 00000000..e08aa6ac
--- /dev/null
+++ b/addon/models/search-result.js
@@ -0,0 +1,11 @@
+import Model, { attr, belongsTo } from "@ember-data/model";
+
+export default class SearchResultModel extends Model {
+ @attr searchRank;
+ @attr searchContext;
+ @attr fileName;
+ @attr documentName;
+
+ @belongsTo("document", { inverse: null, async: false }) document;
+ @belongsTo("matched-file", { inverse: null, async: false }) file;
+}
diff --git a/addon/serializers/search-result.js b/addon/serializers/search-result.js
new file mode 100644
index 00000000..fd21b6a8
--- /dev/null
+++ b/addon/serializers/search-result.js
@@ -0,0 +1,3 @@
+import { LocalizedSerializer } from "ember-localized-model";
+
+export default class SearchResultSerializer extends LocalizedSerializer {}
diff --git a/addon/templates/search.hbs b/addon/templates/search.hbs
index 06d9f53c..9d0a61cd 100644
--- a/addon/templates/search.hbs
+++ b/addon/templates/search.hbs
@@ -1,7 +1,7 @@
-
diff --git a/blueprints/ember-alexandria/files/__root__/adapters/search-result.js b/blueprints/ember-alexandria/files/__root__/adapters/search-result.js
new file mode 100644
index 00000000..1529070d
--- /dev/null
+++ b/blueprints/ember-alexandria/files/__root__/adapters/search-result.js
@@ -0,0 +1,5 @@
+import ApplicationAdapter from "./application";
+
+import adapterFactory from "ember-alexandria/adapters/search-result";
+
+export default adapterFactory(ApplicationAdapter);
diff --git a/blueprints/ember-alexandria/files/__root__/models/search-result.js b/blueprints/ember-alexandria/files/__root__/models/search-result.js
new file mode 100644
index 00000000..32f35a44
--- /dev/null
+++ b/blueprints/ember-alexandria/files/__root__/models/search-result.js
@@ -0,0 +1 @@
+export { default } from "ember-alexandria/models/search-result";
diff --git a/blueprints/ember-alexandria/files/__root__/serializers/search-result.js b/blueprints/ember-alexandria/files/__root__/serializers/search-result.js
new file mode 100644
index 00000000..b2c52884
--- /dev/null
+++ b/blueprints/ember-alexandria/files/__root__/serializers/search-result.js
@@ -0,0 +1 @@
+export { default } from "ember-alexandria/serializers/search-result";
diff --git a/tests/dummy/app/adapters/search-result.js b/tests/dummy/app/adapters/search-result.js
new file mode 100644
index 00000000..1529070d
--- /dev/null
+++ b/tests/dummy/app/adapters/search-result.js
@@ -0,0 +1,5 @@
+import ApplicationAdapter from "./application";
+
+import adapterFactory from "ember-alexandria/adapters/search-result";
+
+export default adapterFactory(ApplicationAdapter);
diff --git a/tests/dummy/app/models/search-result.js b/tests/dummy/app/models/search-result.js
new file mode 100644
index 00000000..32f35a44
--- /dev/null
+++ b/tests/dummy/app/models/search-result.js
@@ -0,0 +1 @@
+export { default } from "ember-alexandria/models/search-result";
diff --git a/tests/dummy/app/serializers/search-result.js b/tests/dummy/app/serializers/search-result.js
new file mode 100644
index 00000000..b2c52884
--- /dev/null
+++ b/tests/dummy/app/serializers/search-result.js
@@ -0,0 +1 @@
+export { default } from "ember-alexandria/serializers/search-result";
diff --git a/tests/dummy/mirage/config.js b/tests/dummy/mirage/config.js
index 6050fbfa..4ad6a040 100644
--- a/tests/dummy/mirage/config.js
+++ b/tests/dummy/mirage/config.js
@@ -27,6 +27,15 @@ export default function makeServer(config) {
});
this.get("/files/multi", () => new Response(200, {}, {}));
+
+ this.get("/search", function (schema) {
+ const res = schema.searchResults.create({
+ document: schema.documents.create(),
+ });
+ const serialized = this.serialize(res);
+ serialized.data = [serialized.data];
+ return serialized;
+ });
},
});
}
diff --git a/tests/dummy/mirage/factories/file.js b/tests/dummy/mirage/factories/file.js
index 02d74a21..e44b4624 100644
--- a/tests/dummy/mirage/factories/file.js
+++ b/tests/dummy/mirage/factories/file.js
@@ -8,5 +8,4 @@ export default Factory.extend({
name: () => faker.system.fileName(),
variant: "original",
downloadUrl: () => faker.internet.url(),
- checksum: () => `sha256:${faker.git.commitSha({ length: 64 })}`,
});
diff --git a/tests/dummy/mirage/factories/search-result.js b/tests/dummy/mirage/factories/search-result.js
new file mode 100644
index 00000000..fee68932
--- /dev/null
+++ b/tests/dummy/mirage/factories/search-result.js
@@ -0,0 +1,16 @@
+import { faker } from "@faker-js/faker";
+import { Factory } from "miragejs";
+
+export default Factory.extend({
+ fileName: () => faker.system.fileName(),
+ documentName: () => faker.system.fileName(),
+ searchRank: () => faker.number.int(),
+ searchContext: () => faker.word.adjective(),
+
+ afterCreate(result, server) {
+ result.update({
+ document: server.schema.documents.create(),
+ matchedFile: server.schema.files.create(),
+ });
+ },
+});
diff --git a/tests/dummy/mirage/models/search-result.js b/tests/dummy/mirage/models/search-result.js
new file mode 100644
index 00000000..ed0327a9
--- /dev/null
+++ b/tests/dummy/mirage/models/search-result.js
@@ -0,0 +1,6 @@
+import { Model, belongsTo } from "miragejs";
+
+export default Model.extend({
+ document: belongsTo(),
+ matchedFile: belongsTo(),
+});
diff --git a/tests/integration/components/search-test.js b/tests/integration/components/search-test.js
index 2d2a810d..5dda657c 100644
--- a/tests/integration/components/search-test.js
+++ b/tests/integration/components/search-test.js
@@ -1,4 +1,4 @@
-import { render, fillIn } from "@ember/test-helpers";
+import { render, fillIn, click } from "@ember/test-helpers";
import { setupRenderingTest } from "dummy/tests/helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
@@ -7,7 +7,7 @@ import { fake, stub } from "sinon";
module("Integration | Component | search", function (hooks) {
setupRenderingTest(hooks);
- test("it renders", async function (assert) {
+ test("it searches", async function (assert) {
const router = this.engine.lookup("service:router");
stub(router, "currentRouteName").get(() => null);
@@ -25,7 +25,32 @@ module("Integration | Component | search", function (hooks) {
[
null,
{
- queryParams: { search: "new search", category: undefined },
+ queryParams: { search: "new search" },
+ },
+ ],
+ "transitionTo was called with the correct arguments",
+ );
+ });
+
+ test("it clears search", async function (assert) {
+ const router = this.engine.lookup("service:router");
+
+ stub(router, "currentRouteName").get(() => null);
+ router.transitionTo = fake();
+
+ await render(hbs``, { owner: this.engine });
+
+ assert.dom("[data-test-search-input]").hasValue("test");
+
+ await click("[data-test-search-clear]");
+
+ assert.ok(router.transitionTo.called, "transitionTo was called");
+ assert.deepEqual(
+ router.transitionTo.firstCall.args,
+ [
+ null,
+ {
+ queryParams: { search: undefined },
},
],
"transitionTo was called with the correct arguments",
diff --git a/tests/unit/controllers/application-test.js b/tests/unit/controllers/application-test.js
index 64ceb86c..94fdccf3 100644
--- a/tests/unit/controllers/application-test.js
+++ b/tests/unit/controllers/application-test.js
@@ -17,9 +17,9 @@ module("Unit | Controller | index", function (hooks) {
assert.deepEqual(controller.documentFilters, {
activeGroup: "group",
- category: 1,
+ categories: 1,
metainfo: JSON.stringify([{ key: "instance_id", value: "1" }]),
- search: "test",
+ query: "test",
tags: undefined,
marks: undefined,
});
diff --git a/translations/de.yaml b/translations/de.yaml
index 00ec24b5..0530c80c 100644
--- a/translations/de.yaml
+++ b/translations/de.yaml
@@ -1,6 +1,7 @@
alexandria:
loading: "Lädt..."
search: "Suchen..."
+ search-clear: "Suche löschen"
nothing-found: "Wir haben nichts gefunden..."
delete: "Löschen"
upload-file: "Datei hochladen"
diff --git a/translations/en.yaml b/translations/en.yaml
index a20f19d5..5237663b 100644
--- a/translations/en.yaml
+++ b/translations/en.yaml
@@ -1,6 +1,7 @@
alexandria:
loading: "Loading..."
search: "Search..."
+ search-clear: "Clear search"
nothing-found: "We found nothing..."
delete: "Delete"
upload-file: "Upload file"
diff --git a/translations/it.yaml b/translations/it.yaml
index 9f5ddf5a..ae7bff82 100644
--- a/translations/it.yaml
+++ b/translations/it.yaml
@@ -1,6 +1,7 @@
alexandria:
loading: "Sto caricando i risultati..."
search: "Cerca..."
+ search-clear: "Ricerca chiara"
nothing-found: "Nessun risultato trovato..."
delete: "Elimina"
upload-file: "Carica file"