diff --git a/package-lock.json b/package-lock.json
index c2ba278cb..06a53db40 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -47,6 +47,7 @@
},
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
@@ -745,6 +746,7 @@
},
"node_modules/@babel/compat-data": {
"version": "7.23.5",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -752,6 +754,7 @@
},
"node_modules/@babel/core": {
"version": "7.23.9",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
@@ -814,6 +817,7 @@
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.23.6",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.23.5",
@@ -828,6 +832,7 @@
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
+ "dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
@@ -835,6 +840,7 @@
},
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1",
+ "dev": true,
"license": "ISC"
},
"node_modules/@babel/helper-create-class-features-plugin": {
@@ -941,6 +947,7 @@
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.23.3",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
@@ -1008,6 +1015,7 @@
},
"node_modules/@babel/helper-simple-access": {
"version": "7.22.5",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.22.5"
@@ -1053,6 +1061,7 @@
},
"node_modules/@babel/helper-validator-option": {
"version": "7.23.5",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -1073,6 +1082,7 @@
},
"node_modules/@babel/helpers": {
"version": "7.23.9",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.23.9",
@@ -4205,23 +4215,6 @@
"node": ">=12"
}
},
- "node_modules/@n8n/vm2": {
- "version": "3.9.23",
- "resolved": "https://registry.npmjs.org/@n8n/vm2/-/vm2-3.9.23.tgz",
- "integrity": "sha512-yu+It+L89uljQsCJ2e9cQaXzoXJe9bU69QQIoWUOcUw0u5Zon37DuB7bdNNsjKS1ZdFD+fBWCQpq/FkqHsSjXQ==",
- "peer": true,
- "dependencies": {
- "acorn": "^8.7.0",
- "acorn-walk": "^8.2.0"
- },
- "bin": {
- "vm2": "bin/vm2"
- },
- "engines": {
- "node": ">=18.10",
- "pnpm": ">=8.6.12"
- }
- },
"node_modules/@next/env": {
"version": "12.3.3",
"license": "MIT"
@@ -6715,6 +6708,7 @@
},
"node_modules/browserslist": {
"version": "4.22.3",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -7652,6 +7646,7 @@
},
"node_modules/convert-source-map": {
"version": "2.0.0",
+ "dev": true,
"license": "MIT"
},
"node_modules/cookie": {
@@ -8809,6 +8804,7 @@
},
"node_modules/electron-to-chromium": {
"version": "1.4.667",
+ "dev": true,
"license": "ISC"
},
"node_modules/electron-util": {
@@ -9812,6 +9808,7 @@
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -13434,6 +13431,7 @@
},
"node_modules/node-releases": {
"version": "2.0.14",
+ "dev": true,
"license": "MIT"
},
"node_modules/node-vault": {
@@ -16387,6 +16385,7 @@
},
"node_modules/semver": {
"version": "6.3.1",
+ "devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -17995,6 +17994,7 @@
},
"node_modules/update-browserslist-db": {
"version": "1.0.13",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -19009,6 +19009,7 @@
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"inquirer": "^9.1.4",
+ "json-bigint": "^1.0.0",
"lodash": "^4.17.21",
"mustache": "^4.2.0",
"qs": "^6.11.0",
@@ -19252,6 +19253,7 @@
},
"@ampproject/remapping": {
"version": "2.2.1",
+ "dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
@@ -19805,10 +19807,12 @@
}
},
"@babel/compat-data": {
- "version": "7.23.5"
+ "version": "7.23.5",
+ "dev": true
},
"@babel/core": {
"version": "7.23.9",
+ "dev": true,
"requires": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.23.5",
@@ -19851,6 +19855,7 @@
},
"@babel/helper-compilation-targets": {
"version": "7.23.6",
+ "dev": true,
"requires": {
"@babel/compat-data": "^7.23.5",
"@babel/helper-validator-option": "^7.23.5",
@@ -19861,12 +19866,14 @@
"dependencies": {
"lru-cache": {
"version": "5.1.1",
+ "dev": true,
"requires": {
"yallist": "^3.0.2"
}
},
"yallist": {
- "version": "3.1.1"
+ "version": "3.1.1",
+ "dev": true
}
}
},
@@ -19936,6 +19943,7 @@
},
"@babel/helper-module-transforms": {
"version": "7.23.3",
+ "dev": true,
"requires": {
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-module-imports": "^7.22.15",
@@ -19974,6 +19982,7 @@
},
"@babel/helper-simple-access": {
"version": "7.22.5",
+ "dev": true,
"requires": {
"@babel/types": "^7.22.5"
}
@@ -19998,7 +20007,8 @@
"version": "7.22.20"
},
"@babel/helper-validator-option": {
- "version": "7.23.5"
+ "version": "7.23.5",
+ "dev": true
},
"@babel/helper-wrap-function": {
"version": "7.22.20",
@@ -20011,6 +20021,7 @@
},
"@babel/helpers": {
"version": "7.23.9",
+ "dev": true,
"requires": {
"@babel/template": "^7.23.9",
"@babel/traverse": "^7.23.9",
@@ -20088,8 +20099,7 @@
},
"@babel/plugin-proposal-private-property-in-object": {
"version": "7.21.0-placeholder-for-preset-env.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
@@ -21102,8 +21112,7 @@
"version": "3.0.4"
},
"ws": {
- "version": "8.13.0",
- "requires": {}
+ "version": "8.13.0"
}
}
},
@@ -21131,8 +21140,7 @@
},
"dependencies": {
"ws": {
- "version": "8.13.0",
- "requires": {}
+ "version": "8.13.0"
}
}
},
@@ -21256,8 +21264,7 @@
}
},
"@graphql-typed-document-node/core": {
- "version": "3.2.0",
- "requires": {}
+ "version": "3.2.0"
},
"@iarna/toml": {
"version": "2.2.5"
@@ -22016,16 +22023,6 @@
"@n1ru4l/push-pull-async-iterable-iterator": {
"version": "3.2.0"
},
- "@n8n/vm2": {
- "version": "3.9.23",
- "resolved": "https://registry.npmjs.org/@n8n/vm2/-/vm2-3.9.23.tgz",
- "integrity": "sha512-yu+It+L89uljQsCJ2e9cQaXzoXJe9bU69QQIoWUOcUw0u5Zon37DuB7bdNNsjKS1ZdFD+fBWCQpq/FkqHsSjXQ==",
- "peer": true,
- "requires": {
- "acorn": "^8.7.0",
- "acorn-walk": "^8.2.0"
- }
- },
"@next/env": {
"version": "12.3.3"
},
@@ -22597,8 +22594,7 @@
}
},
"@tabler/icons": {
- "version": "1.119.0",
- "requires": {}
+ "version": "1.119.0"
},
"@tippyjs/react": {
"version": "4.2.6",
@@ -23026,6 +23022,7 @@
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"inquirer": "^9.1.4",
+ "json-bigint": "^1.0.0",
"lodash": "^4.17.21",
"mustache": "^4.2.0",
"qs": "^6.11.0",
@@ -23138,8 +23135,7 @@
}
},
"@usebruno/schema": {
- "version": "file:packages/bruno-schema",
- "requires": {}
+ "version": "file:packages/bruno-schema"
},
"@usebruno/tests": {
"version": "file:packages/bruno-tests",
@@ -23283,8 +23279,7 @@
},
"@webpack-cli/configtest": {
"version": "1.2.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"@webpack-cli/info": {
"version": "1.5.0",
@@ -23295,8 +23290,7 @@
},
"@webpack-cli/serve": {
"version": "1.7.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"@whatwg-node/events": {
"version": "0.0.3"
@@ -23356,8 +23350,7 @@
},
"acorn-import-assertions": {
"version": "1.9.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"acorn-walk": {
"version": "8.3.2"
@@ -23399,8 +23392,7 @@
},
"ajv-keywords": {
"version": "3.5.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"amdefine": {
"version": "0.0.8"
@@ -24005,6 +23997,7 @@
},
"browserslist": {
"version": "4.22.3",
+ "dev": true,
"requires": {
"caniuse-lite": "^1.0.30001580",
"electron-to-chromium": "^1.4.648",
@@ -24043,7 +24036,7 @@
"https-proxy-agent": "^7.0.2",
"is-valid-path": "^0.1.1",
"js-yaml": "^4.1.0",
- "json-bigint": "*",
+ "json-bigint": "^1.0.0",
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
"mustache": "^4.2.0",
@@ -24297,8 +24290,7 @@
}
},
"chai-string": {
- "version": "1.5.0",
- "requires": {}
+ "version": "1.5.0"
},
"chalk": {
"version": "3.0.0",
@@ -24641,7 +24633,8 @@
"version": "1.0.5"
},
"convert-source-map": {
- "version": "2.0.0"
+ "version": "2.0.0",
+ "dev": true
},
"cookie": {
"version": "0.6.0"
@@ -24759,8 +24752,7 @@
},
"css-declaration-sorter": {
"version": "6.4.1",
- "dev": true,
- "requires": {}
+ "dev": true
},
"css-loader": {
"version": "6.10.0",
@@ -24897,8 +24889,7 @@
},
"cssnano-utils": {
"version": "3.1.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"csso": {
"version": "4.2.0",
@@ -24956,8 +24947,7 @@
},
"dedent": {
"version": "1.5.1",
- "dev": true,
- "requires": {}
+ "dev": true
},
"deep-eql": {
"version": "4.1.3",
@@ -25390,7 +25380,8 @@
}
},
"electron-to-chromium": {
- "version": "1.4.667"
+ "version": "1.4.667",
+ "dev": true
},
"electron-util": {
"version": "0.17.2",
@@ -26021,7 +26012,8 @@
}
},
"gensync": {
- "version": "1.0.0-beta.2"
+ "version": "1.0.0-beta.2",
+ "dev": true
},
"get-caller-file": {
"version": "2.0.5"
@@ -26178,8 +26170,7 @@
}
},
"goober": {
- "version": "2.1.14",
- "requires": {}
+ "version": "2.1.14"
},
"gopd": {
"version": "1.0.1",
@@ -26347,8 +26338,7 @@
}
},
"graphql-ws": {
- "version": "5.12.1",
- "requires": {}
+ "version": "5.12.1"
},
"handlebars": {
"version": "4.7.8",
@@ -26620,8 +26610,7 @@
},
"icss-utils": {
"version": "5.1.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"idb": {
"version": "7.1.1"
@@ -26924,8 +26913,7 @@
"version": "3.0.1"
},
"isomorphic-ws": {
- "version": "5.0.0",
- "requires": {}
+ "version": "5.0.0"
},
"isstream": {
"version": "0.1.2"
@@ -27298,8 +27286,7 @@
},
"jest-pnp-resolver": {
"version": "1.2.3",
- "dev": true,
- "requires": {}
+ "dev": true
},
"jest-regex-util": {
"version": "29.6.3",
@@ -28038,8 +28025,7 @@
"version": "1.0.1"
},
"merge-refs": {
- "version": "1.2.2",
- "requires": {}
+ "version": "1.2.2"
},
"merge-stream": {
"version": "2.0.0",
@@ -28049,8 +28035,7 @@
"version": "1.4.1"
},
"meros": {
- "version": "1.3.0",
- "requires": {}
+ "version": "1.3.0"
},
"methods": {
"version": "1.1.2"
@@ -28297,7 +28282,8 @@
"version": "1.1.12"
},
"node-releases": {
- "version": "2.0.14"
+ "version": "2.0.14",
+ "dev": true
},
"node-vault": {
"version": "0.10.2",
@@ -28910,23 +28896,19 @@
},
"postcss-discard-comments": {
"version": "5.1.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-discard-duplicates": {
"version": "5.1.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-discard-empty": {
"version": "5.1.1",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-discard-overridden": {
"version": "5.1.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-import": {
"version": "15.1.0",
@@ -29011,8 +28993,7 @@
},
"postcss-modules-extract-imports": {
"version": "3.0.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-modules-local-by-default": {
"version": "4.0.4",
@@ -29039,8 +29020,7 @@
},
"postcss-normalize-charset": {
"version": "5.1.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-normalize-display-values": {
"version": "5.1.0",
@@ -29479,8 +29459,7 @@
}
},
"react-inspector": {
- "version": "6.0.2",
- "requires": {}
+ "version": "6.0.2"
},
"react-is": {
"version": "16.13.1"
@@ -29630,8 +29609,7 @@
}
},
"redux-thunk": {
- "version": "2.4.2",
- "requires": {}
+ "version": "2.4.2"
},
"regenerate": {
"version": "1.4.2",
@@ -29950,8 +29928,7 @@
},
"rollup-plugin-peer-deps-external": {
"version": "2.2.4",
- "dev": true,
- "requires": {}
+ "dev": true
},
"rollup-plugin-postcss": {
"version": "4.0.2",
@@ -30093,7 +30070,8 @@
}
},
"semver": {
- "version": "6.3.1"
+ "version": "6.3.1",
+ "devOptional": true
},
"semver-compare": {
"version": "1.0.0",
@@ -30509,8 +30487,7 @@
},
"style-loader": {
"version": "3.3.4",
- "dev": true,
- "requires": {}
+ "dev": true
},
"style-mod": {
"version": "4.1.0"
@@ -30542,8 +30519,7 @@
}
},
"styled-jsx": {
- "version": "5.0.7",
- "requires": {}
+ "version": "5.0.7"
},
"stylehacks": {
"version": "5.1.1",
@@ -31094,6 +31070,7 @@
},
"update-browserslist-db": {
"version": "1.0.13",
+ "dev": true,
"requires": {
"escalade": "^3.1.1",
"picocolors": "^1.0.0"
@@ -31183,8 +31160,7 @@
"version": "8.0.2"
},
"use-sync-external-store": {
- "version": "1.2.0",
- "requires": {}
+ "version": "1.2.0"
},
"utf8-byte-length": {
"version": "1.0.4",
@@ -31465,8 +31441,7 @@
}
},
"ws": {
- "version": "8.16.0",
- "requires": {}
+ "version": "8.16.0"
},
"xdg-basedir": {
"version": "4.0.0",
diff --git a/packages/bruno-app/.env.production b/packages/bruno-app/.env.production
index 9b58ad903..93106b822 100644
--- a/packages/bruno-app/.env.production
+++ b/packages/bruno-app/.env.production
@@ -1,5 +1,3 @@
ENV=production
-NEXT_PUBLIC_ENV=prod
-
-NEXT_PUBLIC_BRUNO_SERVER_API=https://ada.grafnode.com/api
\ No newline at end of file
+NEXT_PUBLIC_ENV=prod
\ No newline at end of file
diff --git a/packages/bruno-app/src/components/Modal/index.js b/packages/bruno-app/src/components/Modal/index.js
index 9ad452fd8..49fcccf02 100644
--- a/packages/bruno-app/src/components/Modal/index.js
+++ b/packages/bruno-app/src/components/Modal/index.js
@@ -1,13 +1,9 @@
import React, { useEffect, useState } from 'react';
import StyledWrapper from './StyledWrapper';
-const ModalHeader = ({ title, handleCancel, headerContentComponent }) => (
+const ModalHeader = ({ title, handleCancel, customHeader }) => (
- {headerContentComponent ? (
- headerContentComponent
- ) : (
- <>{title ?
{title}
: null}>
- )}
+ {customHeader ? customHeader : <>{title ?
{title}
: null}>}
{handleCancel ? (
handleCancel() : null}>
×
@@ -58,7 +54,7 @@ const ModalFooter = ({
const Modal = ({
size,
title,
- headerContentComponent,
+ customHeader,
confirmText,
cancelText,
handleCancel,
@@ -104,11 +100,7 @@ const Modal = ({
return (
onClick(e) : null}>
-
closeModal({ type: 'icon' })}
- headerContentComponent={headerContentComponent}
- />
+ closeModal({ type: 'icon' })} customHeader={customHeader} />
{children}
props.theme.notifications.settings.bg};
+ background-color: ${(props) => props.theme.notifications.bg};
}
.notification-count {
- position: absolute;
- right: -10px;
- top: -15px;
- z-index: 10;
- margin-right: 0.5rem;
- background-color: ${(props) => props.theme.notifications.bell.count};
- border-radius: 50%;
- padding: 2px 1px;
- min-width: 20px;
display: flex;
+ color: white;
+ position: absolute;
+ top: -0.625rem;
+ right: -0.5rem;
+ margin-right: 0.5rem;
justify-content: center;
- font-size: 10px;
+ font-size: 0.625rem;
+ border-radius: 50%;
+ background-color: ${(props) => props.theme.colors.text.yellow};
+ border: solid 2px ${(props) => props.theme.sidebar.bg};
+ min-width: 1.25rem;
}
- .bell {
- animation: fade-and-pulse 1s ease-in-out 1s forwards;
+ button.mark-as-read {
+ font-weight: 400 !important;
}
- ul {
- background-color: ${(props) => props.theme.notifications.settings.sidebar.bg};
- border-right: solid 1px ${(props) => props.theme.notifications.settings.sidebar.borderRight};
+ ul.notifications {
+ background-color: ${(props) => props.theme.notifications.list.bg};
+ border-right: solid 1px ${(props) => props.theme.notifications.list.borderRight};
min-height: 400px;
height: 100%;
max-height: 85vh;
overflow-y: auto;
- }
- li {
- min-width: 150px;
- min-height: 5rem;
- display: block;
- position: relative;
- cursor: pointer;
- padding: 8px 10px;
- border-left: solid 2px transparent;
- border-bottom: solid 1px ${(props) => props.theme.notifications.settings.item.borderBottom};
- font-weight: 600;
- &:hover {
- background-color: ${(props) => props.theme.notifications.settings.item.hoverBg};
- }
- }
+ li {
+ min-width: 150px;
+ cursor: pointer;
+ padding: 0.5rem 0.625rem;
+ border-left: solid 2px transparent;
+ color: ${(props) => props.theme.textLink};
+ border-bottom: solid 1px ${(props) => props.theme.notifications.list.borderBottom};
+ &:hover {
+ background-color: ${(props) => props.theme.notifications.list.hoverBg};
+ }
- .active {
- font-weight: normal;
- background-color: ${(props) => props.theme.notifications.settings.item.active.bg} !important;
- border-left: solid 2px ${(props) => props.theme.notifications.settings.item.border};
- &:hover {
- background-color: ${(props) => props.theme.notifications.settings.item.active.hoverBg} !important;
- }
- }
+ &.active {
+ color: ${(props) => props.theme.text} !important;
+ background-color: ${(props) => props.theme.notifications.list.active.bg} !important;
+ border-left: solid 2px ${(props) => props.theme.notifications.list.active.border};
+ &:hover {
+ background-color: ${(props) => props.theme.notifications.list.active.hoverBg} !important;
+ }
+ }
- .read {
- opacity: 0.7;
- font-weight: normal;
- background-color: ${(props) => props.theme.notifications.settings.item.read.bg} !important;
- &:hover {
- background-color: ${(props) => props.theme.notifications.settings.item.read.hoverBg} !important;
+ &.read {
+ color: ${(props) => props.theme.text} !important;
+ }
+
+ .notification-date {
+ font-size: 0.6875rem;
+ }
}
}
.notification-title {
- // text ellipses 2 lines
- // white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
@@ -79,12 +73,12 @@ const StyledWrapper = styled.div`
}
.notification-date {
- color: ${(props) => props.theme.notifications.settings.item.date.color} !important;
+ color: ${(props) => props.theme.colors.text.muted};
}
.pagination {
- background-color: ${(props) => props.theme.notifications.settings.sidebar.bg};
- border-right: solid 1px ${(props) => props.theme.notifications.settings.sidebar.borderRight};
+ background-color: ${(props) => props.theme.notifications.list.bg};
+ border-right: solid 1px ${(props) => props.theme.notifications.list.borderRight};
}
`;
diff --git a/packages/bruno-app/src/components/Notifications/index.js b/packages/bruno-app/src/components/Notifications/index.js
index 6c6216f09..bb7df5b2f 100644
--- a/packages/bruno-app/src/components/Notifications/index.js
+++ b/packages/bruno-app/src/components/Notifications/index.js
@@ -5,25 +5,26 @@ import Modal from 'components/Modal/index';
import { useEffect } from 'react';
import {
fetchNotifications,
- markMultipleNotificationsAsRead,
+ markAllNotificationsAsRead,
markNotificationAsRead
-} from 'providers/ReduxStore/slices/app';
+} from 'providers/ReduxStore/slices/notifications';
import { useDispatch, useSelector } from 'react-redux';
-import { humanizeDate, relativeDate } from 'utils/common/index';
+import { humanizeDate, relativeDate } from 'utils/common';
+
+const PAGE_SIZE = 5;
const Notifications = () => {
const dispatch = useDispatch();
- const notificationsById = useSelector((state) => state.app.notifications);
- const notifications = [...notificationsById].reverse();
+ const notifications = useSelector((state) => state.notifications.notifications);
- const [showNotificationsModal, toggleNotificationsModal] = useState(false);
+ const [showNotificationsModal, setShowNotificationsModal] = useState(false);
const [selectedNotification, setSelectedNotification] = useState(null);
- const [pageSize, setPageSize] = useState(5);
const [pageNumber, setPageNumber] = useState(1);
- const notificationsStartIndex = (pageNumber - 1) * pageSize;
- const notificationsEndIndex = pageNumber * pageSize;
- const totalPages = Math.ceil(notifications.length / pageSize);
+ const notificationsStartIndex = (pageNumber - 1) * PAGE_SIZE;
+ const notificationsEndIndex = pageNumber * PAGE_SIZE;
+ const totalPages = Math.ceil(notifications.length / PAGE_SIZE);
+ const unreadNotifications = notifications.filter((notification) => !notification.read);
useEffect(() => {
dispatch(fetchNotifications());
@@ -62,22 +63,17 @@ const Notifications = () => {
dispatch(markNotificationAsRead({ notificationId: notification?.id }));
};
- const unreadNotifications = notifications.filter((notification) => !notification.read);
-
- const modalHeaderContentComponent = (
+ const modalCustomHeader = (
NOTIFICATIONS
{unreadNotifications.length > 0 && (
<>
- {unreadNotifications.length} unread notifications
+ {unreadNotifications.length} unread notifications
@@ -92,7 +88,7 @@ const Notifications = () => {
className="relative"
onClick={() => {
dispatch(fetchNotifications());
- toggleNotificationsModal(true);
+ setShowNotificationsModal(true);
}}
>
{
{unreadNotifications.length}
)}
+
{showNotificationsModal && (
{
- toggleNotificationsModal(false);
+ setShowNotificationsModal(false);
}}
handleCancel={() => {
- toggleNotificationsModal(false);
+ setShowNotificationsModal(false);
}}
hideFooter={true}
- headerContentComponent={modalHeaderContentComponent}
+ customHeader={modalCustomHeader}
+ disableCloseOnOutsideClick={true}
+ disableEscapeKey={true}
>
{notifications?.length > 0 ? (
-
+
Page
@@ -170,9 +167,11 @@ const Notifications = () => {
-
-
{selectedNotification?.title}
-
{humanizeDate(selectedNotification?.date)}
+
+
{selectedNotification?.title}
+
+ {humanizeDate(selectedNotification?.date)}
+
{
@@ -20,7 +21,8 @@ export const store = configureStore({
reducer: {
app: appReducer,
collections: collectionsReducer,
- tabs: tabsReducer
+ tabs: tabsReducer,
+ notifications: notificationsReducer
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(middleware)
});
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/app.js b/packages/bruno-app/src/providers/ReduxStore/slices/app.js
index 6c82690a7..f4dd7393d 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/app.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/app.js
@@ -1,8 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import filter from 'lodash/filter';
import toast from 'react-hot-toast';
-import { getReadNotificationIds, setReadNotificationsIds } from 'utils/common/notifications';
-import { getAppInstallDate } from 'utils/common/platform';
const initialState = {
isDragging: false,
@@ -26,10 +24,7 @@ const initialState = {
}
},
cookies: [],
- taskQueue: [],
- notifications: [],
- fetchingNotifications: false,
- readNotificationIds: getReadNotificationIds() || []
+ taskQueue: []
};
export const appSlice = createSlice({
@@ -74,70 +69,6 @@ export const appSlice = createSlice({
},
removeAllTasksFromQueue: (state) => {
state.taskQueue = [];
- },
- fetchingNotifications: (state, action) => {
- state.fetchingNotifications = action.payload.fetching;
- },
- updateNotifications: (state, action) => {
- let notifications = action.payload.notifications || [];
- let readNotificationIds = state.readNotificationIds;
-
- // App installed date
- let appInstalledOnDate = getAppInstallDate();
-
- // date 5 days before
- let dateFiveDaysBefore = new Date();
- dateFiveDaysBefore.setDate(dateFiveDaysBefore.getDate() - 5);
-
- // check if app was installed in the last 5 days
- if (appInstalledOnDate > dateFiveDaysBefore) {
- // filter out notifications that were sent before the app was installed
- notifications = notifications.filter(
- (notification) => new Date(notification.date) > new Date(appInstalledOnDate)
- );
- } else {
- // filter out notifications that sent within the last 5 days
- notifications = notifications.filter(
- (notification) => new Date(notification.date) > new Date(dateFiveDaysBefore)
- );
- }
-
- state.notifications = notifications.map((notification) => {
- return {
- ...notification,
- read: readNotificationIds.includes(notification.id)
- };
- });
- },
- markNotificationAsRead: (state, action) => {
- let readNotificationIds = state.readNotificationIds;
- readNotificationIds.push(action.payload.notificationId);
- state.readNotificationIds = readNotificationIds;
-
- // set the read notification ids in the localstorage
- setReadNotificationsIds(readNotificationIds);
-
- state.notifications = state.notifications.map((notification) => {
- return {
- ...notification,
- read: readNotificationIds.includes(notification.id)
- };
- });
- },
- markMultipleNotificationsAsRead: (state, action) => {
- let readNotificationIds = state.readNotificationIds;
- readNotificationIds.push(...action.payload.notificationIds);
- state.readNotificationIds = readNotificationIds;
-
- // set the read notification ids in the localstorage
- setReadNotificationsIds(readNotificationIds);
-
- state.notifications = state.notifications.map((notification) => {
- return {
- ...notification,
- read: readNotificationIds.includes(notification.id)
- };
- });
}
}
});
@@ -155,12 +86,7 @@ export const {
updateCookies,
insertTaskIntoQueue,
removeTaskFromQueue,
- removeAllTasksFromQueue,
- updateNotifications,
- fetchingNotifications,
- mergeNotifications,
- markNotificationAsRead,
- markMultipleNotificationsAsRead
+ removeAllTasksFromQueue
} = appSlice.actions;
export const savePreferences = (preferences) => (dispatch, getState) => {
@@ -188,26 +114,6 @@ export const deleteCookiesForDomain = (domain) => (dispatch, getState) => {
});
};
-export const fetchNotifications = () => (dispatch, getState) => {
- return new Promise((resolve, reject) => {
- const { ipcRenderer } = window;
- dispatch(fetchingNotifications({ fetching: true }));
- ipcRenderer
- .invoke('renderer:fetch-notifications')
- .then((notifications) => {
- dispatch(updateNotifications({ notifications }));
- dispatch(fetchingNotifications({ fetching: false }));
- })
- .then(resolve)
- .catch((err) => {
- toast.error('An error occurred while fetching notifications');
- dispatch(fetchingNotifications({ fetching: false }));
- console.error(err);
- resolve();
- });
- });
-};
-
export const completeQuitFlow = () => (dispatch, getState) => {
const { ipcRenderer } = window;
return ipcRenderer.invoke('main:complete-quit-flow');
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/notifications.js b/packages/bruno-app/src/providers/ReduxStore/slices/notifications.js
new file mode 100644
index 000000000..60b4e2df7
--- /dev/null
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/notifications.js
@@ -0,0 +1,106 @@
+import toast from 'react-hot-toast';
+import { createSlice } from '@reduxjs/toolkit';
+import { getAppInstallDate } from 'utils/common/platform';
+
+const getReadNotificationIds = () => {
+ try {
+ let readNotificationIdsString = window.localStorage.getItem('bruno.notifications.read');
+ let readNotificationIds = readNotificationIdsString ? JSON.parse(readNotificationIdsString) : [];
+ return readNotificationIds;
+ } catch (err) {
+ toast.error('An error occurred while fetching read notifications');
+ }
+};
+
+const setReadNotificationsIds = (val) => {
+ try {
+ window.localStorage.setItem('bruno.notifications.read', JSON.stringify(val));
+ } catch (err) {
+ toast.error('An error occurred while setting read notifications');
+ }
+};
+
+const initialState = {
+ loading: false,
+ notifications: [],
+ readNotificationIds: getReadNotificationIds() || []
+};
+
+export const notificationSlice = createSlice({
+ name: 'notifications',
+ initialState,
+ reducers: {
+ setFetchingStatus: (state, action) => {
+ state.loading = action.payload.fetching;
+ },
+ setNotifications: (state, action) => {
+ console.log('notifications', notifications);
+ let notifications = action.payload.notifications || [];
+ let readNotificationIds = state.readNotificationIds;
+
+ // Ignore notifications sent before the app was installed
+ let appInstalledOnDate = getAppInstallDate();
+ notifications = notifications.filter((notification) => {
+ const notificationDate = new Date(notification.date);
+ const appInstalledOn = new Date(appInstalledOnDate);
+
+ notificationDate.setHours(0, 0, 0, 0);
+ appInstalledOn.setHours(0, 0, 0, 0);
+
+ return notificationDate >= appInstalledOn;
+ });
+
+ state.notifications = notifications.map((notification) => {
+ return {
+ ...notification,
+ read: readNotificationIds.includes(notification.id)
+ };
+ });
+ },
+ markNotificationAsRead: (state, action) => {
+ if (state.readNotificationIds.includes(action.payload.notificationId)) return;
+
+ const notification = state.notifications.find(
+ (notification) => notification.id === action.payload.notificationId
+ );
+ if (!notification) return;
+
+ state.readNotificationIds.push(action.payload.notificationId);
+ setReadNotificationsIds(state.readNotificationIds);
+ notification.read = true;
+ },
+ markAllNotificationsAsRead: (state) => {
+ let readNotificationIds = state.notifications.map((notification) => notification.id);
+ state.readNotificationIds = readNotificationIds;
+ setReadNotificationsIds(readNotificationIds);
+
+ state.notifications.forEach((notification) => {
+ notification.read = true;
+ });
+ }
+ }
+});
+
+export const { setNotifications, setFetchingStatus, markNotificationAsRead, markAllNotificationsAsRead } =
+ notificationSlice.actions;
+
+export const fetchNotifications = () => (dispatch, getState) => {
+ return new Promise((resolve) => {
+ const { ipcRenderer } = window;
+ dispatch(setFetchingStatus(true));
+ ipcRenderer
+ .invoke('renderer:fetch-notifications')
+ .then((notifications) => {
+ dispatch(setNotifications({ notifications }));
+ dispatch(setFetchingStatus(false));
+ resolve(notifications);
+ })
+ .catch((err) => {
+ dispatch(setFetchingStatus(false));
+ console.error(err);
+ resolve([]);
+ });
+ });
+};
+
+export default notificationSlice.reducer;
diff --git a/packages/bruno-app/src/themes/dark.js b/packages/bruno-app/src/themes/dark.js
index 26be4e822..bb1001f31 100644
--- a/packages/bruno-app/src/themes/dark.js
+++ b/packages/bruno-app/src/themes/dark.js
@@ -138,32 +138,16 @@ const darkTheme = {
notifications: {
bg: '#3D3D3D',
- settings: {
- bg: '#3D3D3D',
- sidebar: {
- bg: '#3D3D3D',
- borderRight: '#4f4f4f'
- },
- item: {
+ list: {
+ bg: '3D3D3D',
+ borderRight: '#4f4f4f',
+ borderBottom: '#545454',
+ hoverBg: '#434343',
+ active: {
border: '#569cd6',
- hoverBg: 'transparent',
- borderBottom: '#4f4f4f99',
- active: {
- bg: '#4f4f4f',
- hoverBg: '#4f4f4f'
- },
- read: {
- bg: '#4f4f4f55',
- hoverBg: '#4f4f4f'
- },
- date: {
- color: '#ccc9'
- }
- },
- gridBorder: '#4f4f4f'
- },
- bell: {
- count: '#cc7b1b55'
+ bg: '#4f4f4f',
+ hoverBg: '#4f4f4f'
+ }
}
},
diff --git a/packages/bruno-app/src/themes/light.js b/packages/bruno-app/src/themes/light.js
index f4c10b097..f359309ab 100644
--- a/packages/bruno-app/src/themes/light.js
+++ b/packages/bruno-app/src/themes/light.js
@@ -141,36 +141,17 @@ const lightTheme = {
},
notifications: {
- bg: '#efefef',
- settings: {
- bg: 'white',
- sidebar: {
- bg: '#eaeaea',
- borderRight: 'transparent'
- },
- item: {
+ bg: 'white',
+ list: {
+ bg: '#eaeaea',
+ borderRight: 'transparent',
+ borderBottom: '#d3d3d3',
+ hoverBg: '#e4e4e4',
+ active: {
border: '#546de5',
- borderBottom: '#4f4f4f44',
- hoverBg: '#e4e4e4',
- active: {
- bg: '#dcdcdc',
- hoverBg: '#dcdcdc'
- },
- read: {
- bg: '#dcdcdc55',
- hoverBg: '#dcdcdc'
- },
- date: {
- color: '#5f5f5f'
- }
- },
- gridBorder: '#f4f4f4'
- },
- sidebar: {
- bg: '#eaeaea'
- },
- bell: {
- count: '#cc7b1b55'
+ bg: '#dcdcdc',
+ hoverBg: '#dcdcdc'
+ }
}
},
diff --git a/packages/bruno-app/src/utils/common/index.js b/packages/bruno-app/src/utils/common/index.js
index a9471dfd7..f31dd228f 100644
--- a/packages/bruno-app/src/utils/common/index.js
+++ b/packages/bruno-app/src/utils/common/index.js
@@ -153,9 +153,6 @@ export const humanizeDate = (dateString) => {
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric'
+ day: 'numeric'
});
};
diff --git a/packages/bruno-app/src/utils/common/notifications.js b/packages/bruno-app/src/utils/common/notifications.js
deleted file mode 100644
index 602a90558..000000000
--- a/packages/bruno-app/src/utils/common/notifications.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import toast from 'react-hot-toast';
-
-export const getReadNotificationIds = () => {
- try {
- let readNotificationIdsString = window.localStorage.getItem('bruno.notifications.read');
- let readNotificationIds = readNotificationIdsString ? JSON.parse(readNotificationIdsString) : [];
- return readNotificationIds;
- } catch (err) {
- toast.error('An error occurred while fetching read notifications');
- }
-};
-
-export const setReadNotificationsIds = (val) => {
- try {
- window.localStorage.setItem('bruno.notifications.read', JSON.stringify(val));
- } catch (err) {
- toast.error('An error occurred while setting read notifications');
- }
-};
diff --git a/packages/bruno-electron/src/app/menu-template.js b/packages/bruno-electron/src/app/menu-template.js
index 2ac2276cf..798c0db95 100644
--- a/packages/bruno-electron/src/app/menu-template.js
+++ b/packages/bruno-electron/src/app/menu-template.js
@@ -30,7 +30,13 @@ const template = [
}
},
{ type: 'separator' },
- { role: 'quit' }
+ { role: 'quit' },
+ {
+ label: 'Force Quit',
+ click() {
+ process.exit();
+ }
+ }
]
},
{