feat: improve markdown rendering and add home filter context
This commit is contained in:
Generated
+294
@@ -26,6 +26,7 @@
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router": "^7.13.0",
|
||||
"react-router-bootstrap": "^0.26.3",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1"
|
||||
},
|
||||
@@ -6649,6 +6650,16 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-table": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
|
||||
"integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -6659,6 +6670,34 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-find-and-replace": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
|
||||
"integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"unist-util-is": "^6.0.0",
|
||||
"unist-util-visit-parents": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
||||
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-from-markdown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
|
||||
@@ -6683,6 +6722,107 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
|
||||
"integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-gfm-autolink-literal": "^2.0.0",
|
||||
"mdast-util-gfm-footnote": "^2.0.0",
|
||||
"mdast-util-gfm-strikethrough": "^2.0.0",
|
||||
"mdast-util-gfm-table": "^2.0.0",
|
||||
"mdast-util-gfm-task-list-item": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-autolink-literal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
|
||||
"integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"ccount": "^2.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"mdast-util-find-and-replace": "^3.0.0",
|
||||
"micromark-util-character": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-footnote": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
|
||||
"integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.1.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0",
|
||||
"micromark-util-normalize-identifier": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-strikethrough": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
|
||||
"integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-table": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
|
||||
"integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"markdown-table": "^3.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-task-list-item": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
|
||||
"integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx-expression": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
|
||||
@@ -6888,6 +7028,127 @@
|
||||
"micromark-util-types": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
|
||||
"integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"micromark-extension-gfm-autolink-literal": "^2.0.0",
|
||||
"micromark-extension-gfm-footnote": "^2.0.0",
|
||||
"micromark-extension-gfm-strikethrough": "^2.0.0",
|
||||
"micromark-extension-gfm-table": "^2.0.0",
|
||||
"micromark-extension-gfm-tagfilter": "^2.0.0",
|
||||
"micromark-extension-gfm-task-list-item": "^2.0.0",
|
||||
"micromark-util-combine-extensions": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-autolink-literal": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
|
||||
"integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-sanitize-uri": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-footnote": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
|
||||
"integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-core-commonmark": "^2.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-normalize-identifier": "^2.0.0",
|
||||
"micromark-util-sanitize-uri": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-strikethrough": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
|
||||
"integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-util-chunked": "^2.0.0",
|
||||
"micromark-util-classify-character": "^2.0.0",
|
||||
"micromark-util-resolve-all": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-table": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
|
||||
"integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-tagfilter": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
|
||||
"integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-task-list-item": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
|
||||
"integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-factory-destination": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
|
||||
@@ -8218,6 +8479,24 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-gfm": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
|
||||
"integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-gfm": "^3.0.0",
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-parse": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
|
||||
@@ -8251,6 +8530,21 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-stringify": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
|
||||
"integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router": "^7.13.0",
|
||||
"react-router-bootstrap": "^0.26.3",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { test, describe, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { render, screen, act, fireEvent, waitFor } from '@testing-library/react';
|
||||
import AuthContext from '../../context/AuthContext';
|
||||
import FilterProvider from '../../context/FilterProvider';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import api from '../../api-service/api';
|
||||
import { TaskResponse } from '../../types/TaskResponse';
|
||||
@@ -140,9 +141,20 @@ const authContextValue = {
|
||||
};
|
||||
|
||||
describe('Home Component', () => {
|
||||
const renderHome = () => render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<FilterProvider>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</FilterProvider>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks and setup default responses
|
||||
vi.clearAllMocks();
|
||||
localStorage.clear();
|
||||
(api.getJSON as any).mockImplementation((url: string) => {
|
||||
if (url.includes('tags')) {
|
||||
return Promise.resolve(mockTags);
|
||||
@@ -169,13 +181,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('renders with initial data', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('content-header')).toBeDefined();
|
||||
@@ -193,13 +199,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('filters tasks and notes when search text is entered', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -224,13 +224,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('filters by radio button selection', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -273,13 +267,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('filters by tag selection', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -314,13 +302,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('marks task as done', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -355,13 +337,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('deletes note', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -397,13 +373,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('opens markdown modal when clicking on note tag', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -431,13 +401,7 @@ describe('Home Component', () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
// Should show error message
|
||||
@@ -447,13 +411,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('keeps filter selection after marking task as done', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -499,13 +457,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('keeps filter selection after deleting a note', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -551,13 +503,7 @@ describe('Home Component', () => {
|
||||
|
||||
test('keeps text search after marking task as done', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -598,13 +544,7 @@ describe('Home Component', () => {
|
||||
/*
|
||||
test('getFirstRows properly formats note preview', async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<BrowserRouter>
|
||||
<Home />
|
||||
</BrowserRouter>
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
renderHome();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Modal from 'react-bootstrap/Modal';
|
||||
import Markdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import './style.css';
|
||||
|
||||
type Props = {
|
||||
@@ -41,7 +42,7 @@ const ModalMarkdown: React.FC<Props> = (props: Props): React.ReactNode => {
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className="markdown-modal">
|
||||
<Markdown>{props.markdownText}</Markdown>
|
||||
<Markdown remarkPlugins={[remarkGfm]}>{props.markdownText}</Markdown>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button variant="outline-secondary" onClick={props.onHide}>
|
||||
|
||||
@@ -1,15 +1,156 @@
|
||||
.markdown-modal {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
padding-bottom: 0.3em;
|
||||
border-bottom: 1px solid var(--bs-border-color);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
padding-bottom: 0.3em;
|
||||
border-bottom: 1px solid var(--bs-border-color);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: 1.25em;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.85em;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--bs-link-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
ul ul,
|
||||
ul ol,
|
||||
ol ul,
|
||||
ol ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Task list checkboxes */
|
||||
li input[type='checkbox'] {
|
||||
margin-right: 0.4em;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
li.task-list-item {
|
||||
list-style: none;
|
||||
margin-left: -1.5em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1em;
|
||||
padding: 0 1em;
|
||||
color: var(--bs-secondary-color);
|
||||
border-left: 4px solid var(--bs-border-color);
|
||||
}
|
||||
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0.2em 0.4em;
|
||||
font-size: 85%;
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
overflow: auto;
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
pre code {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-bottom: 1em;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid var(--bs-border-color);
|
||||
}
|
||||
|
||||
table th {
|
||||
font-weight: 600;
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
}
|
||||
|
||||
table tr:nth-child(even) {
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
margin: 1.5em 0;
|
||||
border: none;
|
||||
background-color: var(--bs-border-color);
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './App';
|
||||
import AuthProvider from './context/AuthProvider';
|
||||
import FilterProvider from './context/FilterProvider';
|
||||
import SidebarProvider from './context/SidebarProvider';
|
||||
import './i18n';
|
||||
|
||||
@@ -14,9 +15,11 @@ const root = createRoot(
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<AuthProvider>
|
||||
<SidebarProvider>
|
||||
<App />
|
||||
</SidebarProvider>
|
||||
<FilterProvider>
|
||||
<SidebarProvider>
|
||||
<App />
|
||||
</SidebarProvider>
|
||||
</FilterProvider>
|
||||
</AuthProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ import ApiConfig from '../../api-service/apiConfig';
|
||||
import { handleDefaultLang } from '../../lang-service/LangHandler';
|
||||
import { translateServerResponse, translateTaskResponse } from '../../utils/TranslatorUtils';
|
||||
import AuthContext from '../../context/AuthContext';
|
||||
import FilterContext from '../../context/FilterContext';
|
||||
import ContentHeader from '../../components/ContentHeader';
|
||||
import AlertError from '../../components/AlertError';
|
||||
import { ThreeDotsVertical } from 'react-bootstrap-icons';
|
||||
@@ -36,6 +37,7 @@ import NoteTitle from '../../components/NoteTitle';
|
||||
*/
|
||||
function Home(): React.ReactNode {
|
||||
const { user } = useContext(AuthContext);
|
||||
const { filterText, selectedOption, setFilterText, setSelectedOption } = useContext(FilterContext);
|
||||
const { i18n, t } = useTranslation();
|
||||
const [errorMessage, setErrorMessage] = useState<string>('');
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
@@ -43,12 +45,10 @@ function Home(): React.ReactNode {
|
||||
const [showMarkdownView, setShowMarkdownView] = useState<boolean>(false);
|
||||
const [modalTitle, setModalTitle] = useState<string>('');
|
||||
const [modalContent, setModalContent] = useState<string>('');
|
||||
const [filterText, setFilterText] = useState<string>('');
|
||||
const [tasks, setTasks] = useState<TaskResponse[]>([]);
|
||||
const [notes, setNotes] = useState<NoteResponse[]>([]);
|
||||
const [savedNotes, setSavedNotes] = useState<NoteResponse[]>([]);
|
||||
const [savedTasks, setSavedTasks] = useState<TaskResponse[]>([]);
|
||||
const [selectedOption, setSelectedOption] = useState<string>('everything');
|
||||
|
||||
/**
|
||||
* Handles the error by setting the error message.
|
||||
@@ -129,7 +129,8 @@ function Home(): React.ReactNode {
|
||||
const anyTitleMatch = note.title.toLowerCase().includes(text.toLowerCase());
|
||||
const anyContentMatch = note.description.toLowerCase().includes(text.toLowerCase());
|
||||
const anyUrlMatch = note.url?.includes(text.toLowerCase());
|
||||
return anyTitleMatch || anyContentMatch || anyUrlMatch;
|
||||
const anyTagMatch = note.tag?.toLowerCase().includes(text.toLowerCase());
|
||||
return anyTitleMatch || anyContentMatch || anyUrlMatch || anyTagMatch;
|
||||
});
|
||||
|
||||
if (tagToFilter === 'untagged') {
|
||||
|
||||
@@ -45,7 +45,7 @@ services:
|
||||
volumes:
|
||||
- "./server:/app"
|
||||
healthcheck:
|
||||
test: curl -f http://localhost:8585/actuator/health | grep '"status":"UP"'
|
||||
test: curl -f http://localhost:8585/health | grep '"status":"UP"'
|
||||
interval: 1m30s
|
||||
timeout: 15s
|
||||
retries: 3
|
||||
|
||||
Reference in New Issue
Block a user