Skip to content

Commit

Permalink
adding search feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Juraci committed Jul 22, 2024
1 parent 538a813 commit d0aa5c4
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 17 deletions.
45 changes: 32 additions & 13 deletions cypress/e2e/nodes_spec.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ describe('Solution Navigator', () => {
const initialState = {
nodes: [
{
uuid: '860639dd-92ab-4220-9513-4488329db5dd',
uuid: leafNodeUuid,
title: 'my child node level 1',
content: '',
content: 'my content level 1',
resolved: false,
childNodes: [],
parentNode: 'd1d551f6-ff27-4bf5-86be-cc2fb5ca6caf',
Expand All @@ -19,14 +19,14 @@ describe('Solution Navigator', () => {
title: 'my child node',
content: '',
resolved: false,
childNodes: ['860639dd-92ab-4220-9513-4488329db5dd'],
parentNode: '5b2fa173-b6d4-4e91-8c16-9c5ab76397b8',
childNodes: [leafNodeUuid],
parentNode: rootNodeUuid,
pomodoroCount: 0,
createdAt: '2024-06-23T20:41:19.297Z',
updatedAt: '2024-06-23T20:41:32.314Z',
},
{
uuid: '5b2fa173-b6d4-4e91-8c16-9c5ab76397b8',
uuid: rootNodeUuid,
title: 'my title',
content: 'my content',
resolved: false,
Expand Down Expand Up @@ -144,14 +144,6 @@ describe('Solution Navigator', () => {
cy.get('.side-panel').should('not.be.visible');
});

context('when the node does not exist', () => {
it('displays a not found message', () => {
cy.visit('/nodes/62090d47-3104-4d50-b384-54728a0208dd');

cy.get('[data-test-node-not-found-message]').should('have.text', 'Node not found');
});
});

it('go back to the root node', () => {
cy.visit(`/nodes/${leafNodeUuid}`, {
onBeforeLoad(win) {
Expand All @@ -163,6 +155,33 @@ describe('Solution Navigator', () => {
cy.url().should('include', `/nodes/${rootNodeUuid}`);
});

it('searches for a node', () => {
cy.visit('/', {
onBeforeLoad(win) {
win.localStorage.setItem('NodeStore', JSON.stringify(initialState));
},
});

cy.get('[data-test-search-input]').type('my content');
cy.get('[data-test-node-item]').should('have.length', 2);

cy.get('[data-test-search-input]').clear();

cy.get('[data-test-search-input]').type('my content level 1');
cy.get('[data-test-node-item]').should('have.length', 1);

cy.get('[data-test-node-item]').eq(0).click();
cy.url().should('include', `/nodes/${leafNodeUuid}`);
});

context('when the node does not exist', () => {
it('displays a not found message', () => {
cy.visit('/nodes/62090d47-3104-4d50-b384-54728a0208dd');

cy.get('[data-test-node-not-found-message]').should('have.text', 'Node not found');
});
});

context('when a child node does not exist', () => {
it('removes the reference from the parent node', () => {
const customInitialState = {
Expand Down
39 changes: 38 additions & 1 deletion specs/stores/NodeStore.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('NodeStore', () => {
setActivePinia(
createTestingPinia({
initialState: {
NodeStore: { nodes },
NodeStore: { nodes, searchQuery: '' },
},
createSpy: vi.fn,
stubActions: false,
Expand All @@ -20,6 +20,7 @@ describe('NodeStore', () => {
setupPinia();
const nodeStore = useNodeStore();
expect(nodeStore.nodes.length).toBe(0);
expect(nodeStore.searchQuery).toEqual('');
});

describe('addNode', () => {
Expand Down Expand Up @@ -147,6 +148,42 @@ describe('NodeStore', () => {
expect(nodeStore.nodesList.length).toBe(2);
expect(nodeStore.nodesList.map((node) => node.parentNode)).toEqual([null, null]);
});

it('filters nodes by search query', () => {
const oldNode = '2022-06-16T21:59:54.858Z';
const newNode = '2023-06-16T21:59:54.858Z';

const initialState = [
{
uuid: '2947d509-ba89-4be5-a6c2-4c6cf546f6ed',
title: 'example',
content: 'my content',
resolved: false,
parentNode: null,
childNodes: [],
pomodoroCount: 0,
createdAt: oldNode,
updatedAt: oldNode,
},
{
uuid: '8881bc3f-7497-4440-9f53-7781b7f6bade',
title: 'example 2',
content: 'my content 2',
resolved: false,
parentNode: null,
childNodes: [],
pomodoroCount: 0,
createdAt: newNode,
updatedAt: newNode,
},
];

setupPinia(initialState);
const nodeStore = useNodeStore();
nodeStore.searchQuery = 'my content 2';

expect(nodeStore.nodesList.length).toBe(1);
});
});

describe('findNode', () => {
Expand Down
13 changes: 11 additions & 2 deletions src/stores/NodeStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ export const useNodeStore = defineStore(
() => {
// state
const nodes = ref([]);
const searchQuery = ref('');

// getters
const nodesList = computed(() => {
return nodes.value
.filter((n) => !n.parentNode)
const baseList =
searchQuery.value === '' ? nodes.value.filter((n) => !n.parentNode) : nodes.value;

return baseList
.filter(
(n) =>
n.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
n.content.toLowerCase().includes(searchQuery.value.toLowerCase()),
)
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt));
});

Expand Down Expand Up @@ -110,6 +118,7 @@ export const useNodeStore = defineStore(

return {
nodes,
searchQuery,
nodesList,
addNode,
addChildNode,
Expand Down
17 changes: 16 additions & 1 deletion src/views/HomeIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ref, computed } from 'vue';
import Button from 'primevue/button';
import NodesArbor from '@/components/NodesArbor.vue';
import ConfirmDialog from 'primevue/confirmdialog';
import InputText from 'primevue/inputtext';
import InputGroup from 'primevue/inputgroup';
import { useRouter, useRoute } from 'vue-router';
import { useNodeStore } from '@/stores/NodeStore';
import { useConfirm } from 'primevue/useconfirm';
Expand All @@ -13,7 +15,7 @@ const route = useRoute();
const isSidePanelVisible = ref(true);
const { addNode, deleteNode } = useNodeStore();
const confirm = useConfirm();
const { nodes } = storeToRefs(useNodeStore());
const { nodes, searchQuery } = storeToRefs(useNodeStore());
const handleAddNode = () => {
const uuid = addNode();
Expand Down Expand Up @@ -56,6 +58,16 @@ const downloadNodesLink = computed(() => {
<div class="container" :style="{ 'grid-template-columns': gridTemplateColumns }">
<div v-show="isSidePanelVisible" class="side-panel">
<div class="side-panel-header">
<InputGroup>
<InputText
v-model="searchQuery"
data-test-search-input
class="search-input"
placeholder="Search"
type="text"
/>
<Button icon="pi pi-times" severity="secondary" @click="searchQuery = ''" />
</InputGroup>
<Button
icon="pi pi-save"
aria-label="Save"
Expand Down Expand Up @@ -102,6 +114,9 @@ const downloadNodesLink = computed(() => {
justify-content: flex-end;
gap: 5px;
}
.search-input {
flex-grow: 1;
}
.side-panel-content {
display: flex;
flex-direction: column;
Expand Down

0 comments on commit d0aa5c4

Please sign in to comment.