diff --git a/.gitignore b/.gitignore index bff24a87..2ec771ff 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ node_modules .pnp.loader.mjs static/dist .env +.wrangler/ cypress/screenshots cypress/videos diff --git a/src/home/fetch-github/fetch-and-display-previews.ts b/src/home/fetch-github/fetch-and-display-previews.ts index 2d37ab12..3d407ed2 100644 --- a/src/home/fetch-github/fetch-and-display-previews.ts +++ b/src/home/fetch-github/fetch-and-display-previews.ts @@ -45,6 +45,29 @@ function getProposalsOnlyFilter(getProposals: boolean) { }; } +function filterIssuesByOrganization(issues: GitHubIssue[]): GitHubIssue[] { + // get organization name from first thing after / in URL + const pathSegments = window.location.pathname.split("/").filter(Boolean); + const urlOrgName = pathSegments.length > 0 ? pathSegments[0] : null; + + // if there is no organization name in the URL, return all issues + if (!urlOrgName) return issues; + + // filter issues by matching the URL organization name with the issue's organization name + const filteredIssues = issues.filter((issue) => { + const [issueOrgName] = issue.repository_url.split("/").slice(-2); + return issueOrgName === urlOrgName; + }); + + // if no issues match the organization, redirect to home + if (filteredIssues.length === 0) { + console.log(`No issues found for organization "${urlOrgName}". Redirecting to the home page.`); + window.location.href = "/"; + } + + return filteredIssues; +} + // checks the cache's integrity, sorts issues, checks Directory/Proposals toggle, renders them and applies avatars export async function displayGitHubIssues({ sorting, @@ -58,7 +81,8 @@ export async function displayGitHubIssues({ await checkCacheIntegrityAndSyncTasks(); const cachedTasks = taskManager.getTasks(); const sortedIssues = sortIssuesController(cachedTasks, sorting, options); - const sortedAndFiltered = sortedIssues.filter(getProposalsOnlyFilter(isProposalOnlyViewer)); + let sortedAndFiltered = sortedIssues.filter(getProposalsOnlyFilter(isProposalOnlyViewer)); + sortedAndFiltered = filterIssuesByOrganization(sortedAndFiltered); renderGitHubIssues(sortedAndFiltered, skipAnimation); applyAvatarsToIssues(); } diff --git a/static/progressive-web-app.js b/static/progressive-web-app.js index 631bf0d5..8c07aadd 100644 --- a/static/progressive-web-app.js +++ b/static/progressive-web-app.js @@ -14,75 +14,87 @@ const urlsToCache = [ // Install event (caches all necessary files) self.addEventListener("install", (event) => { event.waitUntil( - caches - .open(cacheName) - .then((cache) => { - return cache.addAll(urlsToCache); - }) - .catch((error) => console.error("[Service Worker] Cache failed:", error)) + (async () => { + try { + const cache = await caches.open(cacheName); + await cache.addAll(urlsToCache); + console.log("[Service Worker] Files cached successfully"); + } catch (error) { + console.error("[Service Worker] Cache failed:", error); + } + self.skipWaiting(); // Activate the new worker immediately + })() ); - self.skipWaiting(); // activate the new worker immediately }); // Activate event (deletes old caches when updated) self.addEventListener("activate", (event) => { event.waitUntil( - caches - .keys() - .then((cacheNames) => { - return Promise.all( + (async () => { + try { + const cacheNames = await caches.keys(); + await Promise.all( cacheNames.map((name) => { if (name !== cacheName) { return caches.delete(name); } }) ); - }) - .catch((error) => console.error("[Service Worker] Error during activation:", error)) + console.log("[Service Worker] Old caches removed"); + } catch (error) { + console.error("[Service Worker] Error during activation:", error); + } + self.clients.claim(); // Take control of all pages immediately + })() ); - self.clients.claim(); // Take control of all pages immediately }); -// Fetch event: Cache first approach but update cache anyways +// Fetch event: Cache first approach but update cache anyway self.addEventListener("fetch", (event) => { const url = new URL(event.request.url); // Ignore non-HTTP(S) requests (like 'chrome-extension://') - if (url.protocol !== "http:" && url.protocol !== "https:") { - return; - } + if (url.protocol !== "http:" && url.protocol !== "https:") return; // If the request has query parameters, bypass the cache - if (url.search) { + if (url.search) { event.respondWith(fetch(event.request)); return; } event.respondWith( - caches.match(event.request).then((cachedResponse) => { - const fetchPromise = fetch(event.request) - .then((networkResponse) => { - // Clone the network response to avoid using the body twice - const responseClone = networkResponse.clone(); + (async () => { + try { + const cachedResponse = await caches.match(event.request); - // If the network response is valid, update the cache - if (networkResponse.ok) { - caches.open(cacheName).then((cache) => - cache.put(event.request, responseClone) + const fetchPromise = fetch(event.request) + .then(async (networkResponse) => { + if (networkResponse.ok) { + const responseClone = networkResponse.clone(); + const cache = await caches.open(cacheName); + await cache.put(event.request, responseClone); + } + return networkResponse; + }) + .catch((error) => { + console.error("[Service Worker] Network request failed:", error); + return ( + cachedResponse || + new Response("Offline content unavailable", { + status: 503, + statusText: "Service Unavailable", + }) ); - } - return networkResponse; - }) - .catch((error) => { - console.error("[Service Worker] Network request failed:", error); - return cachedResponse || new Response("Offline content unavailable", { - status: 503, - statusText: "Service Unavailable", }); - }); - // Serve from cache first, but update the cache in the background - return cachedResponse || fetchPromise; - }) + return cachedResponse || (await fetchPromise); + } catch (error) { + console.error("[Service Worker] Error handling fetch:", error); + return new Response("An error occurred", { + status: 500, + statusText: "Internal Server Error", + }); + } + })() ); }); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 638aab39..5c4e69bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -232,9 +232,9 @@ "@jridgewell/trace-mapping" "0.3.9" "@cypress/request@^3.0.0": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.5.tgz#d893a6e68ce2636c085fcd8d7283c3186499ba63" - integrity sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.6.tgz#f5580add6acee0e183b4d4e07eff4f31327ae12b" + integrity sha512-fi0eVdCOtKu5Ed6+E8mYxUF6ZTFJDZvHogCBelM0xVXmrDEkyM22gRArQzq1YcHPm1V47Vf/iAD+WgVdUlJCGg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -251,7 +251,7 @@ performance-now "^2.1.0" qs "6.13.0" safe-buffer "^5.1.2" - tough-cookie "^4.1.3" + tough-cookie "^5.0.0" tunnel-agent "^0.6.0" uuid "^8.3.2" @@ -654,9 +654,9 @@ eslint-visitor-keys "^3.4.3" "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.11.2" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.2.tgz#dc6925ab4ea52d3b9d6da204a3f0dd9c3852e3ad" - integrity sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA== + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== "@eslint/eslintrc@^2.1.4": version "2.1.4" @@ -1082,10 +1082,10 @@ dependencies: whatwg-url "^5.0.0" -"@supabase/postgrest-js@1.16.3": - version "1.16.3" - resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.16.3.tgz#d8e009e63b9152e46715982a6d706f1450c0af0d" - integrity sha512-HI6dsbW68AKlOPofUjDTaosiDBCtW4XAm0D18pPwxoW3zKOE2Ru13Z69Wuys9fd6iTpfDViNco5sgrtnP0666A== +"@supabase/postgrest-js@1.17.0": + version "1.17.0" + resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.17.0.tgz#4ca4169f802101fb0c5d1c536cbe43a7f3b999ee" + integrity sha512-vbtb72VpyCkDjcD95SAW4C+3B6NNEICNlEN9H6LcSfIxk5qPImwZ9hVYLa20i+P8GXmKWDoSjjJEK2j6qlR1qQ== dependencies: "@supabase/node-fetch" "^2.6.14" @@ -1107,14 +1107,14 @@ "@supabase/node-fetch" "^2.6.14" "@supabase/supabase-js@^2.39.0": - version "2.45.6" - resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.45.6.tgz#5b74abb58bba7c99ee141706e1609f794f5417c8" - integrity sha512-qVXSSUhhIqdFnF2VUGgeecPvw1cDW6+avcTbRgur4LaGnzrJCbM3Rx7g81/SSZjjeqYOtmHuKWhiHzV/EN8Ktw== + version "2.46.0" + resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.46.0.tgz#bb23c78298ab029f1b332df217a6e8b237202a39" + integrity sha512-Zxr0VjfRvyh+FiQ/KXbuYugfo3MNwsmydYp0wb+mrs8FD92AnRJqDDbnVCPL+dZB9tICFXtwYYoNXrTAnByXBw== dependencies: "@supabase/auth-js" "2.65.1" "@supabase/functions-js" "2.4.3" "@supabase/node-fetch" "2.6.15" - "@supabase/postgrest-js" "1.16.3" + "@supabase/postgrest-js" "1.17.0" "@supabase/realtime-js" "2.10.7" "@supabase/storage-js" "2.7.1" @@ -1155,16 +1155,16 @@ "@types/node" "*" "@types/node@*": - version "22.8.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.8.1.tgz#b39d4b98165e2ae792ce213f610c7c6108ccfa16" - integrity sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg== + version "22.8.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.8.4.tgz#ab754f7ac52e1fe74174f761c5b03acaf06da0dc" + integrity sha512-SpNNxkftTJOPk0oN+y2bIqurEXHTA2AOZ3EJDDKeJ5VzkvvORSvmQXGQarcOzWV1ac7DCaPBEdMDxBsM+d8jWw== dependencies: undici-types "~6.19.8" "@types/node@^20.10.0": - version "20.17.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.1.tgz#2b968e060dfb04b7f9550fe3db5f552721c14566" - integrity sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q== + version "20.17.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.3.tgz#1ad87177c53fa2b237e79a4929fd37932f779f0c" + integrity sha512-tSQrmKKatLDGnG92h40GD7FzUt0MjahaHwOME4VAFeeA/Xopayq5qLyQRy7Jg/pjgKIFBXuKcGhJo+UdYG55jQ== dependencies: undici-types "~6.19.2" @@ -1343,9 +1343,9 @@ acorn-walk@^8.2.0: acorn "^8.11.0" acorn@^8.11.0, acorn@^8.8.0, acorn@^8.9.0: - version "8.13.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" - integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== aggregate-error@^3.0.0: version "3.1.0" @@ -4558,11 +4558,6 @@ proxy-from-env@1.0.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== -psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - pump@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" @@ -4571,7 +4566,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -4583,11 +4578,6 @@ qs@6.13.0: dependencies: side-channel "^1.0.6" -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -4698,11 +4688,6 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - resolve-from@5.0.0, resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" @@ -5296,6 +5281,18 @@ through2@^4.0.0: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tldts-core@^6.1.57: + version "6.1.57" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.57.tgz#2cc6e6af3d0807ad616900300083930efa81b57d" + integrity sha512-lXnRhuQpx3zU9EONF9F7HfcRLvN1uRYUBIiKL+C/gehC/77XTU+Jye6ui86GA3rU6FjlJ0triD1Tkjt2F/2lEg== + +tldts@^6.1.32: + version "6.1.57" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.57.tgz#5d91d257ac945837358fe3954343fc01122fbad7" + integrity sha512-Oy7yDXK8meJl8vPMOldzA+MtueAJ5BrH4l4HXwZuj2AtfoQbLjmTJmjNWPUcAo+E/ibHn7QlqMS0BOcXJFJyHQ== + dependencies: + tldts-core "^6.1.57" + tmp@~0.2.1: version "0.2.3" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" @@ -5327,15 +5324,12 @@ to-space-case@^1.0.0: dependencies: to-no-case "^1.0.0" -tough-cookie@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" - integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== +tough-cookie@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-5.0.0.tgz#6b6518e2b5c070cf742d872ee0f4f92d69eac1af" + integrity sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q== dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" + tldts "^6.1.32" tr46@~0.0.3: version "0.0.3" @@ -5535,11 +5529,6 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -5557,14 +5546,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"