diff --git a/package-lock.json b/package-lock.json index 649481cb..c683ea1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "lato-font": "^3.0.0", "less": "^4.2.0", "less-loader": "^11.1.3", + "lit": "^3.1.2", "matchdep": "~2.0.0", "mini-css-extract-plugin": "^2.7.6", "prettier": "^3.0.3", @@ -1954,18 +1955,18 @@ "dev": true }, "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", - "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", + "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==", "dev": true }, "node_modules/@lit/reactive-element": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.2.tgz", - "integrity": "sha512-SVOwLAWUQg3Ji1egtOt1UiFe4zdDpnWHyc5qctSceJ5XIu0Uc76YmGpIjZgx9YJ0XtdW0Jm507sDvjOu+HnB8w==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz", + "integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==", "dev": true, "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.1.2" + "@lit-labs/ssr-dom-shim": "^1.2.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -8124,31 +8125,31 @@ } }, "node_modules/lit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.2.tgz", + "integrity": "sha512-VZx5iAyMtX7CV4K8iTLdCkMaYZ7ipjJZ0JcSdJ0zIdGxxyurjIn7yuuSxNBD7QmjvcNJwr0JS4cAdAtsy7gZ6w==", "dev": true, "dependencies": { - "@lit/reactive-element": "^2.0.0", - "lit-element": "^4.0.0", - "lit-html": "^3.1.0" + "@lit/reactive-element": "^2.0.4", + "lit-element": "^4.0.4", + "lit-html": "^3.1.2" } }, "node_modules/lit-element": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.2.tgz", - "integrity": "sha512-/W6WQZUa5VEXwC7H9tbtDMdSs9aWil3Ou8hU6z2cOKWbsm/tXPAcsoaHVEtrDo0zcOIE5GF6QgU55tlGL2Nihg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.4.tgz", + "integrity": "sha512-98CvgulX6eCPs6TyAIQoJZBCQPo80rgXR+dVBs61cstJXqtI+USQZAbA4gFHh6L/mxBx9MrgPLHLsUgDUHAcCQ==", "dev": true, "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.1.2", - "@lit/reactive-element": "^2.0.0", - "lit-html": "^3.1.0" + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.0.4", + "lit-html": "^3.1.2" } }, "node_modules/lit-html": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.0.tgz", - "integrity": "sha512-FwAjq3iNsaO6SOZXEIpeROlJLUlrbyMkn4iuv4f4u1H40Jw8wkeR/OUXZUHUoiYabGk8Y4Y0F/rgq+R4MrOLmA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.2.tgz", + "integrity": "sha512-3OBZSUrPnAHoKJ9AMjRL/m01YJxQMf+TMHanNtTHG68ubjnZxK0RFl102DPzsw4mWnHibfZIBJm3LWCZ/LmMvg==", "dev": true, "dependencies": { "@types/trusted-types": "^2.0.2" @@ -14241,18 +14242,18 @@ "dev": true }, "@lit-labs/ssr-dom-shim": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", - "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", + "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==", "dev": true }, "@lit/reactive-element": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.2.tgz", - "integrity": "sha512-SVOwLAWUQg3Ji1egtOt1UiFe4zdDpnWHyc5qctSceJ5XIu0Uc76YmGpIjZgx9YJ0XtdW0Jm507sDvjOu+HnB8w==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz", + "integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==", "dev": true, "requires": { - "@lit-labs/ssr-dom-shim": "^1.1.2" + "@lit-labs/ssr-dom-shim": "^1.2.0" } }, "@nodelib/fs.scandir": { @@ -19026,31 +19027,31 @@ } }, "lit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.2.tgz", + "integrity": "sha512-VZx5iAyMtX7CV4K8iTLdCkMaYZ7ipjJZ0JcSdJ0zIdGxxyurjIn7yuuSxNBD7QmjvcNJwr0JS4cAdAtsy7gZ6w==", "dev": true, "requires": { - "@lit/reactive-element": "^2.0.0", - "lit-element": "^4.0.0", - "lit-html": "^3.1.0" + "@lit/reactive-element": "^2.0.4", + "lit-element": "^4.0.4", + "lit-html": "^3.1.2" } }, "lit-element": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.2.tgz", - "integrity": "sha512-/W6WQZUa5VEXwC7H9tbtDMdSs9aWil3Ou8hU6z2cOKWbsm/tXPAcsoaHVEtrDo0zcOIE5GF6QgU55tlGL2Nihg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.4.tgz", + "integrity": "sha512-98CvgulX6eCPs6TyAIQoJZBCQPo80rgXR+dVBs61cstJXqtI+USQZAbA4gFHh6L/mxBx9MrgPLHLsUgDUHAcCQ==", "dev": true, "requires": { - "@lit-labs/ssr-dom-shim": "^1.1.2", - "@lit/reactive-element": "^2.0.0", - "lit-html": "^3.1.0" + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.0.4", + "lit-html": "^3.1.2" } }, "lit-html": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.0.tgz", - "integrity": "sha512-FwAjq3iNsaO6SOZXEIpeROlJLUlrbyMkn4iuv4f4u1H40Jw8wkeR/OUXZUHUoiYabGk8Y4Y0F/rgq+R4MrOLmA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.2.tgz", + "integrity": "sha512-3OBZSUrPnAHoKJ9AMjRL/m01YJxQMf+TMHanNtTHG68ubjnZxK0RFl102DPzsw4mWnHibfZIBJm3LWCZ/LmMvg==", "dev": true, "requires": { "@types/trusted-types": "^2.0.2" diff --git a/package.json b/package.json index 6cec9a6f..790b8e49 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "lato-font": "^3.0.0", "less": "^4.2.0", "less-loader": "^11.1.3", + "lit": "^3.1.2", "matchdep": "~2.0.0", "mini-css-extract-plugin": "^2.7.6", "prettier": "^3.0.3", diff --git a/readthedocsext/theme/templates/includes/utils/messages.html b/readthedocsext/theme/templates/includes/utils/messages.html index 7fb3b5ca..75ceec88 100644 --- a/readthedocsext/theme/templates/includes/utils/messages.html +++ b/readthedocsext/theme/templates/includes/utils/messages.html @@ -7,22 +7,10 @@ page content pane. {% endcomment %} -{% comment %} -``user_notifications`` comes from a Context Processor. -We need to use a CustomUser to have access to "user.notifications" -See https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-AUTH_USER_MODEL -{% endcomment %} -{% if user_notifications %} - {% for notification in user_notifications %} -
- {% comment %} - Add this Xmark here once we implement dismissing notifications. - - {% endcomment %} - {{ notification.get_message.get_rendered_body|safe }} -
- {% endfor %} -{% endif %} + + {% if messages %} {% for message in messages %} diff --git a/src/js/modules/index.js b/src/js/modules/index.js index cb6e7e93..36674e53 100644 --- a/src/js/modules/index.js +++ b/src/js/modules/index.js @@ -1,5 +1,6 @@ import * as popupcards from "./popupcards"; import * as header from "./header"; import * as filter from "./filter"; +import * as notifications from "./notifications"; -export { popupcards, header, filter }; +export { popupcards, header, filter, notifications }; diff --git a/src/js/modules/notifications.js b/src/js/modules/notifications.js new file mode 100644 index 00000000..9d1fbc04 --- /dev/null +++ b/src/js/modules/notifications.js @@ -0,0 +1,92 @@ +import { LitElement, css, html, nothing } from "lit"; +import {repeat} from 'lit/directives/repeat.js'; +import {when} from 'lit/directives/when.js'; +import {classMap} from 'lit/directives/class-map.js'; +import {unsafeHTML} from 'lit/directives/unsafe-html.js'; + +export class NotificationList extends LitElement { + static properties = { + url: {type: String}, + csrfToken: {type: String, attribute: "csrf-token"}, + notifications: {state: true}, + finished: {state: true, type: Boolean}, + }; + + // Use light DOM with inherited styles instead of shadow DOM + createRenderRoot() { + return this; + } + + fetchNotifications() { + if (!this.url || this.finished) { + return; + } + fetch(this.url).then((response) => { + response.json().then((data) => { + if (data.results) { + this.notifications = data.results; + } + }); + this.finished = true; + }); + } + + render() { + // Trigger async notification fetch + this.fetchNotifications(); + + if (this.notifications && this.notifications.length > 0) { + return html` +
+ ${repeat( + this.notifications, + (notification) => notification.id, + (notification, index) => { + return this.renderNotification(notification); + } + )} +
+ `; + } else { + return nothing; + } + } + + renderNotification(notification) { + return html` +
+ ${when(notification.dismissable, () => html` + this.dismissNotification(notification), once: true}}> + `)} +
+ + ${unsafeHTML(notification.message.header)} +
+ ${unsafeHTML(notification.message.body)} +
+ ` + } + + dismissNotification(notification) { + console.debug("Dismissing notification:", notification.id); + const options = { + method: "PATCH", + headers: { + "Content-Type": "application/json", + "X-CSRFToken": this.csrfToken, + }, + body: { + state: "dismissed", + }, + }; + fetch(notification._links._self, options).then((response) => { + console.log(response); + // TODO error catch response + response.json().then((data) => { + console.log(data); + }); + }); + } +} + +customElements.define("rtd-notification-list", NotificationList);