Prompt users to reload the CC when the extension updates

When the extension updates, it stops working in the Community Console.
Thus, this change adds logic so when the extension detects it has been
recently installed or updated it injects a banner to the top of the CC
with a message which prompts the user to reload the page.

Fixed: twpowertools:82
Change-Id: I0c901c72574c7c64d9ba94f56be96a12f7770049
diff --git a/lit-localize.json b/lit-localize.json
index 1bbc7a7..4a964eb 100644
--- a/lit-localize.json
+++ b/lit-localize.json
@@ -22,6 +22,7 @@
     "src/contentScripts/communityConsole/flattenThreads/components/**/*.js",
     "src/contentScripts/communityConsole/workflows/components/**/*.js",
     "src/contentScripts/communityConsole/threadToolbar/components/**/*.js",
+    "src/contentScripts/communityConsole/updateHandler/banner/components/**/*.js",
     "src/workflows/manager/components/**/*.js"
   ],
   "output": {
diff --git a/package-lock.json b/package-lock.json
index a514099..d8fe494 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
       "license": "MIT",
       "dependencies": {
         "@lit/localize": "^0.11.4",
+        "@material/banner": "^14.0.0",
         "@material/mwc-circular-progress": "^0.27.0",
         "@material/mwc-dialog": "^0.27.0",
         "@material/tooltip": "^12.0.0",
@@ -1207,6 +1208,181 @@
         "tslib": "^2.1.0"
       }
     },
+    "node_modules/@material/banner": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/banner/-/banner-14.0.0.tgz",
+      "integrity": "sha512-z0WPBVQxbQVcV1km4hFD40xBEeVWYtCzl2jrkHd8xXexP/fMvXkFU1UfwSWvY3jlWx//j4/Xd7VpnRdEXS4RLQ==",
+      "dependencies": {
+        "@material/base": "^14.0.0",
+        "@material/button": "^14.0.0",
+        "@material/dom": "^14.0.0",
+        "@material/elevation": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/ripple": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "@material/shape": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "@material/tokens": "^14.0.0",
+        "@material/typography": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/animation": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/animation/-/animation-14.0.0.tgz",
+      "integrity": "sha512-VlYSfUaIj/BBVtRZI8Gv0VvzikFf+XgK0Zdgsok5c1v5DDnNz5tpB8mnGrveWz0rHbp1X4+CWLKrTwNmjrw3Xw==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/base": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/base/-/base-14.0.0.tgz",
+      "integrity": "sha512-Ou7vS7n1H4Y10MUZyYAbt6H0t67c6urxoCgeVT7M38aQlaNUwFMODp7KT/myjYz2YULfhu3PtfSV3Sltgac9mA==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/button": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/button/-/button-14.0.0.tgz",
+      "integrity": "sha512-dqqHaJq0peyXBZupFzCjmvScrfljyVU66ZCS3oldsaaj5iz8sn33I/45Z4zPzdR5F5z8ExToHkRcXhakj1UEAA==",
+      "dependencies": {
+        "@material/density": "^14.0.0",
+        "@material/dom": "^14.0.0",
+        "@material/elevation": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/focus-ring": "^14.0.0",
+        "@material/ripple": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "@material/shape": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "@material/tokens": "^14.0.0",
+        "@material/touch-target": "^14.0.0",
+        "@material/typography": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/density": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/density/-/density-14.0.0.tgz",
+      "integrity": "sha512-NlxXBV5XjNsKd8UXF4K/+fOXLxoFNecKbsaQO6O2u+iG8QBfFreKRmkhEBb2hPPwC3w8nrODwXX0lHV+toICQw==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/dom": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/dom/-/dom-14.0.0.tgz",
+      "integrity": "sha512-8t88XyacclTj8qsIw9q0vEj4PI2KVncLoIsIMzwuMx49P2FZg6TsLjor262MI3Qs00UWAifuLMrhnOnfyrbe7Q==",
+      "dependencies": {
+        "@material/feature-targeting": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/elevation": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-14.0.0.tgz",
+      "integrity": "sha512-Di3tkxTpXwvf1GJUmaC8rd+zVh5dB2SWMBGagL4+kT8UmjSISif/OPRGuGnXs3QhF6nmEjkdC0ijdZLcYQkepw==",
+      "dependencies": {
+        "@material/animation": "^14.0.0",
+        "@material/base": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/feature-targeting": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-14.0.0.tgz",
+      "integrity": "sha512-a5WGgHEq5lJeeNL5yevtgoZjBjXWy6+klfVWQEh8oyix/rMJygGgO7gEc52uv8fB8uAIoYEB3iBMOv8jRq8FeA==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/focus-ring": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-14.0.0.tgz",
+      "integrity": "sha512-fqqka6iSfQGJG3Le48RxPCtnOiaLGPDPikhktGbxlyW9srBVMgeCiONfHM7IT/1eu80O0Y67Lh/4ohu5+C+VAQ==",
+      "dependencies": {
+        "@material/dom": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/rtl": "^14.0.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/ripple": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-14.0.0.tgz",
+      "integrity": "sha512-9XoGBFd5JhFgELgW7pqtiLy+CnCIcV2s9cQ2BWbOQeA8faX9UZIDUx/g76nHLZ7UzKFtsULJxZTwORmsEt2zvw==",
+      "dependencies": {
+        "@material/animation": "^14.0.0",
+        "@material/base": "^14.0.0",
+        "@material/dom": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/rtl": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-14.0.0.tgz",
+      "integrity": "sha512-xl6OZYyRjuiW2hmbjV2omMV8sQtfmKAjeWnD1RMiAPLCTyOW9Lh/PYYnXjxUrNa0cRwIIbOn5J7OYXokja8puA==",
+      "dependencies": {
+        "@material/theme": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/shape": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/shape/-/shape-14.0.0.tgz",
+      "integrity": "sha512-o0mJB0+feOv473KckI8gFnUo8IQAaEA6ynXzw3VIYFjPi48pJwrxa0mZcJP/OoTXrCbDzDeFJfDPXEmRioBb9A==",
+      "dependencies": {
+        "@material/feature-targeting": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/theme": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/theme/-/theme-14.0.0.tgz",
+      "integrity": "sha512-6/SENWNIFuXzeHMPHrYwbsXKgkvCtWuzzQ3cUu4UEt3KcQ5YpViazIM6h8ByYKZP8A9d8QpkJ0WGX5btGDcVoA==",
+      "dependencies": {
+        "@material/feature-targeting": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/tokens": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-14.0.0.tgz",
+      "integrity": "sha512-SXgB9VwsKW4DFkHmJfDIS0x0cGdMWC1D06m6z/WQQ5P5j6/m0pKrbHVlrLzXcRjau+mFhXGvj/KyPo9Pp/Rc8Q==",
+      "dependencies": {
+        "@material/elevation": "^14.0.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/touch-target": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-14.0.0.tgz",
+      "integrity": "sha512-o3kvxmS4HkmZoQTvtzLJrqSG+ezYXkyINm3Uiwio1PTg67pDgK5FRwInkz0VNaWPcw9+5jqjUQGjuZMtjQMq8w==",
+      "dependencies": {
+        "@material/base": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@material/banner/node_modules/@material/typography": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/typography/-/typography-14.0.0.tgz",
+      "integrity": "sha512-/QtHBYiTR+TPMryM/CT386B2WlAQf/Ae32V324Z7P40gHLKY/YBXx7FDutAWZFeOerq/two4Nd2aAHBcMM2wMw==",
+      "dependencies": {
+        "@material/feature-targeting": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "tslib": "^2.1.0"
+      }
+    },
     "node_modules/@material/base": {
       "version": "12.0.0",
       "resolved": "https://registry.npmjs.org/@material/base/-/base-12.0.0.tgz",
@@ -8124,6 +8300,183 @@
         "tslib": "^2.1.0"
       }
     },
+    "@material/banner": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/@material/banner/-/banner-14.0.0.tgz",
+      "integrity": "sha512-z0WPBVQxbQVcV1km4hFD40xBEeVWYtCzl2jrkHd8xXexP/fMvXkFU1UfwSWvY3jlWx//j4/Xd7VpnRdEXS4RLQ==",
+      "requires": {
+        "@material/base": "^14.0.0",
+        "@material/button": "^14.0.0",
+        "@material/dom": "^14.0.0",
+        "@material/elevation": "^14.0.0",
+        "@material/feature-targeting": "^14.0.0",
+        "@material/ripple": "^14.0.0",
+        "@material/rtl": "^14.0.0",
+        "@material/shape": "^14.0.0",
+        "@material/theme": "^14.0.0",
+        "@material/tokens": "^14.0.0",
+        "@material/typography": "^14.0.0",
+        "tslib": "^2.1.0"
+      },
+      "dependencies": {
+        "@material/animation": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/animation/-/animation-14.0.0.tgz",
+          "integrity": "sha512-VlYSfUaIj/BBVtRZI8Gv0VvzikFf+XgK0Zdgsok5c1v5DDnNz5tpB8mnGrveWz0rHbp1X4+CWLKrTwNmjrw3Xw==",
+          "requires": {
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/base": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/base/-/base-14.0.0.tgz",
+          "integrity": "sha512-Ou7vS7n1H4Y10MUZyYAbt6H0t67c6urxoCgeVT7M38aQlaNUwFMODp7KT/myjYz2YULfhu3PtfSV3Sltgac9mA==",
+          "requires": {
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/button": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/button/-/button-14.0.0.tgz",
+          "integrity": "sha512-dqqHaJq0peyXBZupFzCjmvScrfljyVU66ZCS3oldsaaj5iz8sn33I/45Z4zPzdR5F5z8ExToHkRcXhakj1UEAA==",
+          "requires": {
+            "@material/density": "^14.0.0",
+            "@material/dom": "^14.0.0",
+            "@material/elevation": "^14.0.0",
+            "@material/feature-targeting": "^14.0.0",
+            "@material/focus-ring": "^14.0.0",
+            "@material/ripple": "^14.0.0",
+            "@material/rtl": "^14.0.0",
+            "@material/shape": "^14.0.0",
+            "@material/theme": "^14.0.0",
+            "@material/tokens": "^14.0.0",
+            "@material/touch-target": "^14.0.0",
+            "@material/typography": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/density": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/density/-/density-14.0.0.tgz",
+          "integrity": "sha512-NlxXBV5XjNsKd8UXF4K/+fOXLxoFNecKbsaQO6O2u+iG8QBfFreKRmkhEBb2hPPwC3w8nrODwXX0lHV+toICQw==",
+          "requires": {
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/dom": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/dom/-/dom-14.0.0.tgz",
+          "integrity": "sha512-8t88XyacclTj8qsIw9q0vEj4PI2KVncLoIsIMzwuMx49P2FZg6TsLjor262MI3Qs00UWAifuLMrhnOnfyrbe7Q==",
+          "requires": {
+            "@material/feature-targeting": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/elevation": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-14.0.0.tgz",
+          "integrity": "sha512-Di3tkxTpXwvf1GJUmaC8rd+zVh5dB2SWMBGagL4+kT8UmjSISif/OPRGuGnXs3QhF6nmEjkdC0ijdZLcYQkepw==",
+          "requires": {
+            "@material/animation": "^14.0.0",
+            "@material/base": "^14.0.0",
+            "@material/feature-targeting": "^14.0.0",
+            "@material/rtl": "^14.0.0",
+            "@material/theme": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/feature-targeting": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-14.0.0.tgz",
+          "integrity": "sha512-a5WGgHEq5lJeeNL5yevtgoZjBjXWy6+klfVWQEh8oyix/rMJygGgO7gEc52uv8fB8uAIoYEB3iBMOv8jRq8FeA==",
+          "requires": {
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/focus-ring": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-14.0.0.tgz",
+          "integrity": "sha512-fqqka6iSfQGJG3Le48RxPCtnOiaLGPDPikhktGbxlyW9srBVMgeCiONfHM7IT/1eu80O0Y67Lh/4ohu5+C+VAQ==",
+          "requires": {
+            "@material/dom": "^14.0.0",
+            "@material/feature-targeting": "^14.0.0",
+            "@material/rtl": "^14.0.0"
+          }
+        },
+        "@material/ripple": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-14.0.0.tgz",
+          "integrity": "sha512-9XoGBFd5JhFgELgW7pqtiLy+CnCIcV2s9cQ2BWbOQeA8faX9UZIDUx/g76nHLZ7UzKFtsULJxZTwORmsEt2zvw==",
+          "requires": {
+            "@material/animation": "^14.0.0",
+            "@material/base": "^14.0.0",
+            "@material/dom": "^14.0.0",
+            "@material/feature-targeting": "^14.0.0",
+            "@material/rtl": "^14.0.0",
+            "@material/theme": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/rtl": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-14.0.0.tgz",
+          "integrity": "sha512-xl6OZYyRjuiW2hmbjV2omMV8sQtfmKAjeWnD1RMiAPLCTyOW9Lh/PYYnXjxUrNa0cRwIIbOn5J7OYXokja8puA==",
+          "requires": {
+            "@material/theme": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/shape": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/shape/-/shape-14.0.0.tgz",
+          "integrity": "sha512-o0mJB0+feOv473KckI8gFnUo8IQAaEA6ynXzw3VIYFjPi48pJwrxa0mZcJP/OoTXrCbDzDeFJfDPXEmRioBb9A==",
+          "requires": {
+            "@material/feature-targeting": "^14.0.0",
+            "@material/rtl": "^14.0.0",
+            "@material/theme": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/theme": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/theme/-/theme-14.0.0.tgz",
+          "integrity": "sha512-6/SENWNIFuXzeHMPHrYwbsXKgkvCtWuzzQ3cUu4UEt3KcQ5YpViazIM6h8ByYKZP8A9d8QpkJ0WGX5btGDcVoA==",
+          "requires": {
+            "@material/feature-targeting": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/tokens": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-14.0.0.tgz",
+          "integrity": "sha512-SXgB9VwsKW4DFkHmJfDIS0x0cGdMWC1D06m6z/WQQ5P5j6/m0pKrbHVlrLzXcRjau+mFhXGvj/KyPo9Pp/Rc8Q==",
+          "requires": {
+            "@material/elevation": "^14.0.0"
+          }
+        },
+        "@material/touch-target": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-14.0.0.tgz",
+          "integrity": "sha512-o3kvxmS4HkmZoQTvtzLJrqSG+ezYXkyINm3Uiwio1PTg67pDgK5FRwInkz0VNaWPcw9+5jqjUQGjuZMtjQMq8w==",
+          "requires": {
+            "@material/base": "^14.0.0",
+            "@material/feature-targeting": "^14.0.0",
+            "@material/rtl": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        },
+        "@material/typography": {
+          "version": "14.0.0",
+          "resolved": "https://registry.npmjs.org/@material/typography/-/typography-14.0.0.tgz",
+          "integrity": "sha512-/QtHBYiTR+TPMryM/CT386B2WlAQf/Ae32V324Z7P40gHLKY/YBXx7FDutAWZFeOerq/two4Nd2aAHBcMM2wMw==",
+          "requires": {
+            "@material/feature-targeting": "^14.0.0",
+            "@material/theme": "^14.0.0",
+            "tslib": "^2.1.0"
+          }
+        }
+      }
+    },
     "@material/base": {
       "version": "12.0.0",
       "resolved": "https://registry.npmjs.org/@material/base/-/base-12.0.0.tgz",
diff --git a/package.json b/package.json
index 3583b67..6ed1914 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
   "private": true,
   "dependencies": {
     "@lit/localize": "^0.11.4",
+    "@material/banner": "^14.0.0",
     "@material/mwc-circular-progress": "^0.27.0",
     "@material/mwc-dialog": "^0.27.0",
     "@material/tooltip": "^12.0.0",
diff --git a/src/bg.js b/src/bg.js
index 394f0fd..4c3da6f 100644
--- a/src/bg.js
+++ b/src/bg.js
@@ -7,6 +7,7 @@
 import {cleanUpOptions, disableItemsWithMissingPermissions} from './common/optionsUtils.js';
 import KillSwitchMechanism from './killSwitch/index.js';
 import {handleBgOptionChange, handleBgOptionsOnStart} from './options/bgHandler.js';
+import UpdateNotifier from './updateNotifier/index.js';
 
 // #!if browser_target == 'chromium_mv3'
 // XMLHttpRequest is not present in service workers (MV3) and is required by the
@@ -61,7 +62,8 @@
 });
 
 // When the extension is first installed or gets updated, set new options to
-// their default value and update the kill switch status.
+// their default value, update the kill switch status and prompt the user to
+// refresh the Community Console page.
 chrome.runtime.onInstalled.addListener(details => {
   if (details.reason == 'install' || details.reason == 'update') {
     chrome.storage.sync.get(null, options => {
@@ -69,6 +71,9 @@
     });
 
     killSwitchMechanism.updateKillSwitchStatus();
+
+    const updateNotifier = new UpdateNotifier();
+    updateNotifier.notify(details.reason);
   }
 });
 
diff --git a/src/common/optionsPermissions.js b/src/common/optionsPermissions.js
index 1bfd082..a475ac7 100644
--- a/src/common/optionsPermissions.js
+++ b/src/common/optionsPermissions.js
@@ -12,6 +12,9 @@
     // #!if ['chromium', 'chromium_mv3'].includes(browser_target)
     'declarativeNetRequestWithHostAccess',
     // #!endif
+    // #!if browser_target == 'chromium_mv3'
+    'scripting',
+    // #!endif
   ]),
   origins: new Set([
     // Host permissions:
diff --git a/src/common/styles/md3.js b/src/common/styles/md3.js
index d3b098c..a634fb2 100644
--- a/src/common/styles/md3.js
+++ b/src/common/styles/md3.js
@@ -17,8 +17,10 @@
     --md-icon-button-unselected-hover-icon-color: var(--TWPT-custom-md-icon-color);
     --md-icon-button-unselected-focus-icon-color: var(--TWPT-custom-md-icon-color);
     --md-icon-button-unselected-pressed-icon-color: var(--TWPT-custom-md-icon-color);
-    --mdc-theme-on-surface: var(--TWPT-primary-text, #000);
-    --mdc-dialog-heading-ink-color: var(--TWPT-primary-text);
     --mdc-theme-surface: var(--TWPT-primary-background, #fff);
+    --mdc-theme-on-surface: var(--TWPT-primary-text, #000);
+    --mdc-theme-primary: var(--TWPT-md-sys-color-primary, #6750a4);
+    --mdc-theme-on-primary: var(--TWPT-md-sys-color-on-primary, #fff);
+    --mdc-dialog-heading-ink-color: var(--TWPT-primary-text);
   }
 `;
diff --git a/src/contentScripts/communityConsole/handleInstall.js b/src/contentScripts/communityConsole/handleInstall.js
new file mode 100644
index 0000000..14362c0
--- /dev/null
+++ b/src/contentScripts/communityConsole/handleInstall.js
@@ -0,0 +1,4 @@
+import UpdateHandler from './updateHandler/index.js';
+
+const updateHandler = new UpdateHandler();
+updateHandler.handle('install');
diff --git a/src/contentScripts/communityConsole/handleUpdate.js b/src/contentScripts/communityConsole/handleUpdate.js
new file mode 100644
index 0000000..88c187b
--- /dev/null
+++ b/src/contentScripts/communityConsole/handleUpdate.js
@@ -0,0 +1,4 @@
+import UpdateHandler from './updateHandler/index.js';
+
+const updateHandler = new UpdateHandler();
+updateHandler.handle('update');
diff --git a/src/contentScripts/communityConsole/updateHandler/banner/components/consts.js b/src/contentScripts/communityConsole/updateHandler/banner/components/consts.js
new file mode 100644
index 0000000..d279671
--- /dev/null
+++ b/src/contentScripts/communityConsole/updateHandler/banner/components/consts.js
@@ -0,0 +1 @@
+export const TWPT_UPDATE_BANNER_TAG = 'twpt-update-banner-v1';
diff --git a/src/contentScripts/communityConsole/updateHandler/banner/components/index.js b/src/contentScripts/communityConsole/updateHandler/banner/components/index.js
new file mode 100644
index 0000000..81bd20c
--- /dev/null
+++ b/src/contentScripts/communityConsole/updateHandler/banner/components/index.js
@@ -0,0 +1,122 @@
+import consoleCommonStyles from '!!raw-loader!../../../../../static/css/common/console.css';
+import {msg} from '@lit/localize';
+import {MDCBanner} from '@material/banner';
+import {css, html, unsafeCSS} from 'lit';
+import {createRef, ref} from 'lit/directives/ref.js';
+
+import {I18nLitElement} from '../../../../../common/litI18nUtils.js';
+import {SHARED_MD3_STYLES} from '../../../../../common/styles/md3.js';
+
+import {TWPT_UPDATE_BANNER_TAG} from './consts.js';
+import mdcStyles from './mdcStyles.scss?string';
+
+export default class TwptUpdateBanner extends I18nLitElement {
+  static properties = {
+    isinstall: {type: Boolean},
+  };
+
+  static styles = [
+    css`
+    :host {
+      position: sticky;
+      top: 0;
+      z-index: 97;
+    }
+
+    .mdc-banner {
+      background-color: var(--TWPT-drawer-background, #fff)!important;
+    }
+
+    .mdc-banner__graphic {
+      color: var(--mdc-theme-on-primary)!important;
+      background-color: var(--mdc-theme-primary)!important;
+    }
+
+    .mdc-banner__text {
+      color: var(--TWPT-primary-text, #000)!important;
+    }
+    `,
+    css`${unsafeCSS(consoleCommonStyles)}`,
+    SHARED_MD3_STYLES,
+    css`${unsafeCSS(mdcStyles)}`,
+  ];
+
+  bannerRef = createRef();
+
+  constructor() {
+    super();
+    this.isinstall = false;
+    this.mdcBanner = null;
+  }
+
+  firstUpdated() {
+    this.mdcBanner = new MDCBanner(this.bannerRef.value);
+    this.mdcBanner.open();
+  }
+
+  render() {
+    let descriptionMsg;
+    if (this.isinstall) {
+      descriptionMsg = msg(
+          'The TW Power Tools extension has been installed. Please reload this page so that it is activated.',
+          {
+            desc:
+                'Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.'
+          });
+    } else {
+      descriptionMsg = msg(
+          'The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.',
+          {
+            desc:
+                'Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.'
+          });
+    }
+    const reloadMsg =
+        msg('Reload', {desc: 'Button which reloads the current page.'});
+    return html`
+      <div ${ref(this.bannerRef)}
+          class="mdc-banner mdc-banner--centered mdc-banner--mobile-stacked"
+          role="banner">
+        <div class="mdc-banner__content"
+             role="alertdialog"
+             aria-live="assertive">
+          <div class="mdc-banner__graphic-text-wrapper">
+            <div
+                class="mdc-banner__graphic"
+                role="img"
+                alt="Update">
+              <md-icon class="mdc-banner__icon">update</md-icon>
+            </div>
+            <div class="mdc-banner__text">
+              ${descriptionMsg}
+            </div>
+          </div>
+          <div class="mdc-banner__actions">
+            <md-text-button
+                class="mdc-banner__primary-action"
+                label="${reloadMsg}"
+                @click=${this._reloadPage}>
+            </md-text-button>
+          </div>
+        </div>
+      </div>
+    `;
+  }
+
+  _reloadPage() {
+    location.reload();
+  }
+}
+// This element is injected each time an extension is installed/updated, so it
+// might already be defined. If it isn't, register it. If there are any breaking
+// changes, change TWPT_UPDATE_BANNER_TAG to a higher version.
+if (window.customElements.get(TWPT_UPDATE_BANNER_TAG) === undefined) {
+import(
+      /* webpackMode: "eager" */
+      '@material/web/icon/icon.js');
+import(
+      /* webpackMode: "eager" */
+      '@material/web/button/text-button.js');
+
+  window.customElements.define(TWPT_UPDATE_BANNER_TAG, TwptUpdateBanner);
+}
diff --git a/src/contentScripts/communityConsole/updateHandler/banner/components/mdcStyles.scss b/src/contentScripts/communityConsole/updateHandler/banner/components/mdcStyles.scss
new file mode 100644
index 0000000..1f87a5c
--- /dev/null
+++ b/src/contentScripts/communityConsole/updateHandler/banner/components/mdcStyles.scss
@@ -0,0 +1 @@
+@use "@material/banner/styles";
diff --git a/src/contentScripts/communityConsole/updateHandler/banner/index.js b/src/contentScripts/communityConsole/updateHandler/banner/index.js
new file mode 100644
index 0000000..c2da6b4
--- /dev/null
+++ b/src/contentScripts/communityConsole/updateHandler/banner/index.js
@@ -0,0 +1,14 @@
+import {TWPT_UPDATE_BANNER_TAG} from './components/consts.js';
+
+export default class UpdateBanner {
+  addBanner(reason) {
+    const main = document.querySelector('.scrollable-content > main');
+    if (main === null) {
+      console.error(`[updateHandlerBanner] Couldn't find main element.`);
+      return;
+    }
+    const banner = document.createElement(TWPT_UPDATE_BANNER_TAG);
+    if (reason === 'install') banner.setAttribute('isinstall', '');
+    main.prepend(banner);
+  }
+}
diff --git a/src/contentScripts/communityConsole/updateHandler/index.js b/src/contentScripts/communityConsole/updateHandler/index.js
new file mode 100644
index 0000000..8eaa815
--- /dev/null
+++ b/src/contentScripts/communityConsole/updateHandler/index.js
@@ -0,0 +1,17 @@
+import {injectScript} from '../../../common/contentScriptsUtils.js';
+import MWI18nServer from '../../../common/mainWorldI18n/Server.js';
+
+import UpdateBanner from './banner/index.js';
+
+export default class UpdateHandler {
+  constructor() {
+    new MWI18nServer();
+    injectScript(chrome.runtime.getURL('updateHandlerLitComponents.bundle.js'));
+    this.updateBanner = new UpdateBanner();
+  }
+
+  handle(reason) {
+    console.debug(`Handling extension update (reason: ${reason}).`);
+    this.updateBanner.addBanner(reason);
+  }
+}
diff --git a/src/injections/litComponentsInject.js b/src/injections/litComponentsInject.js
index 9506c8c..09e8ec8 100644
--- a/src/injections/litComponentsInject.js
+++ b/src/injections/litComponentsInject.js
@@ -5,6 +5,7 @@
 import '../contentScripts/communityConsole/workflows/components/index.js';
 import '../contentScripts/communityConsole/threadToolbar/components/index.js';
 import '../contentScripts/communityConsole/flattenThreads/components/index.js';
+import '../contentScripts/communityConsole/updateHandler/banner/components/index.js';
 
 import {injectStylesheet} from '../common/contentScriptsUtils.js';
 
diff --git a/src/injections/updateHandlerLitComponents.js b/src/injections/updateHandlerLitComponents.js
new file mode 100644
index 0000000..9b82ee2
--- /dev/null
+++ b/src/injections/updateHandlerLitComponents.js
@@ -0,0 +1,8 @@
+import '../contentScripts/communityConsole/updateHandler/banner/components/index.js';
+
+import {injectStylesheet} from '../common/contentScriptsUtils.js';
+
+// This is necessary for the MD3 components. It is also done in
+// litComponentsInject.js, but when installing the extension
+// litComponentsInject.js hasn't been injected yet.
+injectStylesheet('https://fonts.googleapis.com/icon?family=Material+Icons');
diff --git a/src/lit-locales/source/ar.xlf b/src/lit-locales/source/ar.xlf
index 893f73a..8597246 100644
--- a/src/lit-locales/source/ar.xlf
+++ b/src/lit-locales/source/ar.xlf
@@ -26,6 +26,18 @@
         <target>عَرض متداخِل</target>
         <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
       </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/lit-locales/source/ca.xlf b/src/lit-locales/source/ca.xlf
index 3553adc..76b8cb4 100644
--- a/src/lit-locales/source/ca.xlf
+++ b/src/lit-locales/source/ca.xlf
@@ -26,6 +26,18 @@
   <target>Vista anidada</target>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/lit-locales/source/de.xlf b/src/lit-locales/source/de.xlf
index 66fbce0..92bfdc0 100644
--- a/src/lit-locales/source/de.xlf
+++ b/src/lit-locales/source/de.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/es.xlf b/src/lit-locales/source/es.xlf
index 3ff72c1..2303137 100644
--- a/src/lit-locales/source/es.xlf
+++ b/src/lit-locales/source/es.xlf
@@ -26,6 +26,18 @@
   <target>Vista anidada</target>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/lit-locales/source/fr.xlf b/src/lit-locales/source/fr.xlf
index 3ee36db..44fab08 100644
--- a/src/lit-locales/source/fr.xlf
+++ b/src/lit-locales/source/fr.xlf
@@ -24,6 +24,18 @@
         <source>Nested view</source>
         <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
       </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/lit-locales/source/id.xlf b/src/lit-locales/source/id.xlf
index 789b10d..c706ab1 100644
--- a/src/lit-locales/source/id.xlf
+++ b/src/lit-locales/source/id.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/it.xlf b/src/lit-locales/source/it.xlf
index 589121b..b52109b 100644
--- a/src/lit-locales/source/it.xlf
+++ b/src/lit-locales/source/it.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/ja.xlf b/src/lit-locales/source/ja.xlf
index 6d3d51b..589042e 100644
--- a/src/lit-locales/source/ja.xlf
+++ b/src/lit-locales/source/ja.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/ko.xlf b/src/lit-locales/source/ko.xlf
index 1c0fec8..918259e 100644
--- a/src/lit-locales/source/ko.xlf
+++ b/src/lit-locales/source/ko.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/pl.xlf b/src/lit-locales/source/pl.xlf
index b12990d..85ff3ea 100644
--- a/src/lit-locales/source/pl.xlf
+++ b/src/lit-locales/source/pl.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/pt_BR.xlf b/src/lit-locales/source/pt_BR.xlf
index 2fa97d2..a69913f 100644
--- a/src/lit-locales/source/pt_BR.xlf
+++ b/src/lit-locales/source/pt_BR.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/ru.xlf b/src/lit-locales/source/ru.xlf
index 85cf100..3f625c1 100644
--- a/src/lit-locales/source/ru.xlf
+++ b/src/lit-locales/source/ru.xlf
@@ -26,6 +26,18 @@
         <target>Вложенный вид</target>
         <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
       </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
     </body>
   </file>
 </xliff>
diff --git a/src/lit-locales/source/th.xlf b/src/lit-locales/source/th.xlf
index 0ea88a7..2db0fdf 100644
--- a/src/lit-locales/source/th.xlf
+++ b/src/lit-locales/source/th.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/tr.xlf b/src/lit-locales/source/tr.xlf
index 4136d7c..63b2570 100644
--- a/src/lit-locales/source/tr.xlf
+++ b/src/lit-locales/source/tr.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/lit-locales/source/vi.xlf b/src/lit-locales/source/vi.xlf
index b9ccf93..b82dae0 100644
--- a/src/lit-locales/source/vi.xlf
+++ b/src/lit-locales/source/vi.xlf
@@ -21,6 +21,18 @@
   <source>Nested view</source>
   <note from="lit-localize">Label for the switch which lets users enable/disable the nested view in a thread.</note>
 </trans-unit>
+<trans-unit id="s0f92c01a67197f53">
+  <source>The TW Power Tools extension has been installed. Please reload this page so that it is activated.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been installed, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sb2c523c904424868">
+  <source>The TW Power Tools extension has been updated. Please reload this page so that it continues to work properly.</source>
+  <note from="lit-localize">Message shown as a banner when the extension has been updated, to let the user know that they should reload the page.</note>
+</trans-unit>
+<trans-unit id="sd5b6130b4937488c">
+  <source>Reload</source>
+  <note from="lit-localize">Button which reloads the current page.</note>
+</trans-unit>
 </body>
 </file>
 </xliff>
diff --git a/src/updateNotifier/index.js b/src/updateNotifier/index.js
new file mode 100644
index 0000000..b4c0bb0
--- /dev/null
+++ b/src/updateNotifier/index.js
@@ -0,0 +1,25 @@
+export default class UpdateNotifier {
+  getCommunityConsoleTabs() {
+    return new Promise(res => {
+      chrome.tabs.query(
+          {url: 'https://support.google.com/s/community*'}, tabs => res(tabs));
+    });
+  }
+
+  notify(reason) {
+    this.getCommunityConsoleTabs().then(tabs => {
+      for (const tab of tabs) {
+        const script = reason === 'install' ? 'handleInstall.bundle.js' :
+                                              'handleUpdate.bundle.js';
+        // #!if browser_target == 'chromium_mv3'
+        chrome.scripting.executeScript({
+          target: {tabId: tab.id},
+          files: [script],
+        });
+        // #!else
+        chrome.tabs.executeScript(tab.id, {file: script});
+        // #!endif
+      }
+    });
+  }
+}
diff --git a/templates/manifest.gjson b/templates/manifest.gjson
index 726c398..cf8260b 100644
--- a/templates/manifest.gjson
+++ b/templates/manifest.gjson
@@ -67,6 +67,9 @@
 #if defined(CHROMIUM || CHROMIUM_MV3)
     "declarativeNetRequestWithHostAccess",
 #endif
+#if defined(CHROMIUM_MV3)
+    "scripting",
+#endif
     "storage",
     "alarms"
   ],
@@ -85,6 +88,7 @@
         "xhrInterceptorInject.bundle.js",
         "extraInfoInject.bundle.js",
         "litComponentsInject.bundle.js",
+        "updateHandlerLitComponents.bundle.js",
 
         "css/profileindicator_inject.css",
         "css/ccdarktheme.css",
diff --git a/webpack.config.js b/webpack.config.js
index 033685f..66d241e 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -48,12 +48,18 @@
     publicProfileStart: './src/contentScripts/publicProfileStart.js',
     profileIndicator: './src/contentScripts/profileIndicator.js',
 
+    // Programatically injected content scripts
+    handleInstall: './src/contentScripts/communityConsole/handleInstall.js',
+    handleUpdate: './src/contentScripts/communityConsole/handleUpdate.js',
+
     // Injected JS
     profileIndicatorInject: './src/injections/profileIndicator.js',
     batchLockInject: './src/injections/batchLock.js',
     xhrInterceptorInject: './src/injections/xhrProxy.js',
     extraInfoInject: './src/injections/extraInfo.js',
     litComponentsInject: './src/injections/litComponentsInject.js',
+    updateHandlerLitComponents:
+        './src/injections/updateHandlerLitComponents.js',
 
     // Options page
     optionsCommon: './src/options/optionsCommon.js',
@@ -144,15 +150,32 @@
         },
         {
           test: /\.s[ac]ss$/i,
-          use: [
-            'style-loader',
-            'css-loader',
+          oneOf: [
             {
-              loader: 'sass-loader',
-              options: {
-                // Prefer `dart-sass`
-                implementation: require('sass'),
-              },
+              resourceQuery: /string/,
+              use: [
+                'css-loader',
+                {
+                  loader: 'sass-loader',
+                  options: {
+                    // Prefer `dart-sass`
+                    implementation: require('sass'),
+                  },
+                },
+              ],
+            },
+            {
+              use: [
+                'style-loader',
+                'css-loader',
+                {
+                  loader: 'sass-loader',
+                  options: {
+                    // Prefer `dart-sass`
+                    implementation: require('sass'),
+                  },
+                },
+              ],
             },
           ],
         },