From faaa9aa7cd2110d27eb3b4fe731e29aaed58b45d Mon Sep 17 00:00:00 2001 From: Akshar Dave <37267046+akshar-dave@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:09:04 +0530 Subject: [PATCH 001/142] Fixed a typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32e78e31..9426642a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ mysql://username:mypassword@localhost:3306/mydb yarn build ``` -The build step will also create tables in your database if you ae installing for the first time. It will also create a login user with username **admin** and password **umami**. +The build step will also create tables in your database if you are installing for the first time. It will also create a login user with username **admin** and password **umami**. ### Start the application From 232b69393280ea2779d23ea128402b05bf55d45f Mon Sep 17 00:00:00 2001 From: Adebayo <54339202+Braggedtooth@users.noreply.github.com> Date: Fri, 22 Dec 2023 03:53:57 +0100 Subject: [PATCH 002/142] Update Swedish translations --- src/lang/sv-SE.json | 202 ++++++++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/src/lang/sv-SE.json b/src/lang/sv-SE.json index 1496594f..f40fead1 100644 --- a/src/lang/sv-SE.json +++ b/src/lang/sv-SE.json @@ -1,36 +1,36 @@ { - "label.access-code": "Access code", + "label.access-code": "Åtkomstkod", "label.actions": "Händelser", "label.activity-log": "Aktivitetslogg", - "label.add": "Add", - "label.add-description": "Add description", - "label.add-website": "Lägg till webbsajt", + "label.add": "Lägg till", + "label.add-description": "Lägg till beskrivning", + "label.add-website": "Lägg till webbplats", "label.admin": "Administratör", - "label.after": "After", + "label.after": "Efter", "label.all": "Alla", "label.all-time": "Sedan början", - "label.analytics": "Analys", - "label.average": "Average", - "label.average-visit-time": "Medelbesökstid", + "label.analytics": "Webbplats Analys", + "label.average": "Genomsnitt", + "label.average-visit-time": "Genomsnittlig besökstid", "label.back": "Tillbaka", - "label.before": "Before", - "label.bounce-rate": "Avvisningfrekvens", - "label.breakdown": "Breakdown", - "label.browser": "Browser", + "label.before": "Före", + "label.bounce-rate": "Avvisningsfrekvens", + "label.breakdown": "Analys", + "label.browser": "Webbläsare", "label.browsers": "Webbläsare", "label.cancel": "Avbryt", "label.change-password": "Byt lösenord", "label.cities": "Städer", - "label.city": "City", + "label.city": "Stad", "label.clear-all": "Rensa alla", "label.confirm": "Bekräfta", "label.confirm-password": "Bekräfta lösenord", - "label.contains": "Contains", + "label.contains": "Innehåller", "label.continue": "Fortsätt", "label.countries": "Länder", - "label.country": "Country", - "label.create": "Create", - "label.create-report": "Create report", + "label.country": "Land", + "label.create": "Skapa", + "label.create-report": "Skapa rapport", "label.create-team": "Skapa team", "label.create-user": "Skapa användare", "label.created": "Skapad", @@ -38,48 +38,48 @@ "label.custom-range": "Anpassat urval", "label.dashboard": "Översikt", "label.data": "Data", - "label.date": "Date", - "label.date-range": "Datumomfång", - "label.day": "Day", - "label.default-date-range": "Standard datum-urval", + "label.date": "Datum", + "label.date-range": "Tidsperiod", + "label.day": "Dag", + "label.default-date-range": "Standard Tidsperiod", "label.delete": "Radera", "label.delete-team": "Radera team", "label.delete-user": "Radera användare", - "label.delete-website": "Radera webbsajt", - "label.description": "Description", + "label.delete-website": "Radera webbplats", + "label.description": "Beskrivning", "label.desktop": "Stationär", - "label.details": "Detailjer", - "label.device": "Device", + "label.details": "Detaljer", + "label.device": "Enhet", "label.devices": "Enheter", "label.dismiss": "Avbryt", - "label.does-not-contain": "Does not contain", + "label.does-not-contain": "Innehåller inte", "label.domain": "Domän", - "label.dropoff": "Dropoff", + "label.dropoff": "Bortfall", "label.edit": "Redigera", "label.edit-dashboard": "Redigera översikt", - "label.enable-share-url": "Aktivera delnings-URL", - "label.event": "Event", - "label.event-data": "Event data", + "label.enable-share-url": "Aktivera delningslänk", + "label.event": "Händelse", + "label.event-data": "Händelsedata", "label.events": "Händelser", - "label.false": "False", - "label.field": "Field", - "label.fields": "Fields", + "label.false": "Falskt", + "label.field": "Fält", + "label.fields": "Fältar", "label.filter": "Filter", "label.filter-combined": "Kombinerade", "label.filter-raw": "Rådata", - "label.filters": "Filters", + "label.filters": "Filter", "label.funnel": "Funnel", - "label.funnel-description": "Understand the conversion and drop-off rate of users.", - "label.greater-than": "Greater than", - "label.greater-than-equals": "Greater than or equals", - "label.insights": "Insights", - "label.insights-description": "Dive deeper into your data by using segments and filters.", - "label.is": "Is", - "label.is-not": "Is not", - "label.is-not-set": "Is not set", - "label.is-set": "Is set", + "label.funnel-description": "Förstå omvandlingen och bortfallsfrekvensen för användare.", + "label.greater-than": "Större än", + "label.greater-than-equals": "Större än eller lika med", + "label.insights": "Insikter", + "label.insights-description": "Dyk djupare in i din data genom att använda olika segment och filter.", + "label.is": "Är", + "label.is-not": "Är inte", + "label.is-not-set": "Är inte inställd", + "label.is-set": "Är inställd", "label.join": "Gå med", - "label.join-team": "gå med i team", + "label.join-team": "Gå med i team", "label.language": "Språk", "label.languages": "Språk", "label.laptop": "Bärbar", @@ -87,8 +87,8 @@ "label.last-hours": "Senaste {x} timmarna", "label.leave": "Lämna", "label.leave-team": "Lämna team", - "label.less-than": "Less than", - "label.less-than-equals": "Less than or equals", + "label.less-than": "Mindre än", + "label.less-than-equals": "Mindre än eller lika med", "label.login": "Logga in", "label.logout": "Logga ut", "label.max": "Max", @@ -96,57 +96,57 @@ "label.min": "Min", "label.mobile": "Mobil", "label.more": "Mer", - "label.my-websites": "My websites", + "label.my-websites": "Mina webbplatser", "label.name": "Namn", "label.new-password": "Nytt lösenord", "label.none": "Inga", - "label.os": "OS", - "label.overview": "Overview", + "label.os": "Operativsystem", + "label.overview": "Översikt", "label.owner": "Ägare", - "label.page-of": "Page {current} of {total}", + "label.page-of": "Sida {current} av {total}", "label.page-views": "Sidvisningar", - "label.pageTitle": "Page title", + "label.pageTitle": "Sidtitel", "label.pages": "Sidor", "label.password": "Lösenord", "label.powered-by": "Drivs av {name}", "label.profile": "Profil", "label.queries": "Frågor", - "label.query": "Frågor", - "label.query-parameters": "Fråge-parametrar", + "label.query": "Fråga", + "label.query-parameters": "Frågeparametrar", "label.realtime": "Realtid", - "label.referrer": "Referrer", + "label.referrer": "Hänvisare", "label.referrers": "Hänvisare", "label.refresh": "Uppdatera", - "label.regenerate": "Regenerera", + "label.regenerate": "Förnya", "label.region": "Region", "label.regions": "Regioner", "label.remove": "Ta bort", - "label.reports": "Reports", + "label.reports": "Rapporter", "label.required": "Krävs", "label.reset": "Återställ", - "label.reset-website": "Återställ statistik", + "label.reset-website": "Återställ webbplats", "label.retention": "Retention", - "label.retention-description": "Measure your website stickiness by tracking how often users return.", + "label.retention-description": "Mät din webbplats engagemang genom att följa hur ofta användare återvänder.", "label.role": "Roll", - "label.run-query": "Run query", + "label.run-query": "Kör sökning", "label.save": "Spara", "label.screens": "Upplösning", - "label.search": "Search", - "label.select-date": "Select date", - "label.select-website": "Välj webbsajt", - "label.sessions": "Sessions", + "label.search": "Sök", + "label.select-date": "Välj datum", + "label.select-website": "Välj webbplats", + "label.sessions": "Sessioner", "label.settings": "Inställningar", - "label.share-url": "Delnings-URL", + "label.share-url": "Delningslänk", "label.single-day": "En dag", - "label.sum": "Sum", - "label.tablet": "Platta", + "label.sum": "Summa", + "label.tablet": "Surfplatta", "label.team": "Team", "label.team-guest": "Team-gäst", "label.team-id": "Team ID", "label.team-member": "Team-medlem", - "label.team-name": "Team name", + "label.team-name": "Team namn", "label.team-owner": "Team-ägare", - "label.team-websites": "Team websites", + "label.team-websites": "Team webbplatser", "label.teams": "Team", "label.theme": "Tema", "label.this-month": "Denna månad", @@ -156,62 +156,62 @@ "label.title": "Titel", "label.today": "Idag", "label.toggle-charts": "Visa/göm grafer", - "label.total": "Total", - "label.total-records": "Total records", + "label.total": "Totalt", + "label.total-records": "Totala poster", "label.tracking-code": "Spårningskod", - "label.true": "True", - "label.type": "Type", - "label.unique": "Unique", + "label.true": "Sant", + "label.type": "Typ", + "label.unique": "Unikt", "label.unique-visitors": "Unika besökare", - "label.unknown": "Okänd", - "label.untitled": "Untitled", - "label.url": "URL", - "label.urls": "URLs", + "label.unknown": "Okänt", + "label.untitled": "Namnlös", + "label.url": "Länk", + "label.urls": "Länkar", "label.user": "Användare", "label.username": "Användarnamn", - "label.users": "Users", - "label.value": "Value", + "label.users": "Användare", + "label.value": "Värde", "label.view": "Visa", "label.view-details": "Visa detaljer", - "label.view-only": "View only", + "label.view-only": "Endast visning", "label.views": "Visningar", "label.visitors": "Besökare", - "label.website": "Website", - "label.website-id": "Webbsajt-ID", - "label.websites": "Webbsajt", - "label.window": "Window", + "label.website": "Webbplats", + "label.website-id": "Webbplats ID", + "label.websites": "Webbplatser", + "label.window": "Fönster", "label.yesterday": "Igår", "message.active-users": "{x} {x, plural, one {besökare} other {besökare}} just nu", "message.confirm-delete": "Är du säker på att du vill radera {target}?", "message.confirm-leave": "Är du säker på att du vill lämna {target}?", "message.confirm-reset": "Är du säker på att du vill återställa statistiken för {target}?", - "message.delete-account": "To delete this account, type {confirmation} in the box below to confirm.", - "message.delete-website": "To delete this website, type {confirmation} in the box below to confirm.", - "message.delete-website-warning": "All tillhörande data kommer också raderas.", + "message.delete-account": "För att radera det här kontot, skriv {confirmation} i rutan nedan för att bekräfta.", + "message.delete-website": "För att radera den här webbplatsen, skriv {confirmation} i rutan nedan för att bekräfta.", + "message.delete-website-warning": "All tillhörande data kommer också att raderas.", "message.error": "Något gick fel.", "message.event-log": "{event} på {url}", "message.go-to-settings": "Gå till inställningar", "message.incorrect-username-password": "Felaktigt användarnamn/lösenord.", "message.invalid-domain": "Ogiltig domän", "message.min-password-length": "Minst {n} tecken", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "En ny version av Umami {version} är tillgänglig!", "message.no-data-available": "Ingen data tillgänglig.", - "message.no-event-data": "No event data is available.", - "message.no-match-password": "Lösenorden är inte samma", - "message.no-results-found": "No results were found.", - "message.no-team-websites": "Det här teamet har inga webbsajter.", + "message.no-event-data": "Ingen händelsedata är tillgänglig.", + "message.no-match-password": "Lösenorden matchar inte", + "message.no-results-found": "Inga resultat hittades.", + "message.no-team-websites": "Det här teamet har inga webbplatser.", "message.no-teams": "Du har inte skapat några team.", "message.no-users": "Det finns inga användare.", - "message.no-websites-configured": "Du har inga webbsajter.", - "message.page-not-found": "Sidan kan inte hittas.", - "message.reset-website": "För att återställa statistiken skriv {confirmation} i rutan nedan.", - "message.reset-website-warning": "All statistik för webbsajten tas bort men spårningskoden förblir oförändrad.", - "message.saved": "Sparades!", - "message.share-url": "Det här är den offentliga delnings-URL:en för {target}.", + "message.no-websites-configured": "Du har inte konfigurerat några webbplatser.", + "message.page-not-found": "Sidan kunde inte hittas.", + "message.reset-website": "För att återställa webbplatsen, skriv {confirmation} i rutan nedan.", + "message.reset-website-warning": "All statistik för webbplatsen tas bort, men spårningskoden förblir oförändrad.", + "message.saved": "Sparat!", + "message.share-url": "Det här är den offentliga delningslänken för {target}.", "message.team-already-member": "Du är redan medlem i teamet.", - "message.team-not-found": "Team kan inte hittas.", - "message.team-websites-info": "Websajter kan ses av alla i teamet.", + "message.team-not-found": "Teamet kunde inte hittas.", + "message.team-websites-info": "Webbplatserna kan ses av alla i teamet.", "message.tracking-code": "Spårningskod", - "message.user-deleted": "Användare raderad.", + "message.user-deleted": "Användaren har raderats.", "message.visitor-log": "Besökare från {country} med {browser} på {os} {device}" } From b8e6517787cee002a8e31d3b801faf5bf0899a3b Mon Sep 17 00:00:00 2001 From: Adebayo <54339202+Braggedtooth@users.noreply.github.com> Date: Fri, 22 Dec 2023 03:57:18 +0100 Subject: [PATCH 003/142] Update Swedish translation for default date range label --- src/lang/sv-SE.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/sv-SE.json b/src/lang/sv-SE.json index f40fead1..1696bbf0 100644 --- a/src/lang/sv-SE.json +++ b/src/lang/sv-SE.json @@ -41,7 +41,7 @@ "label.date": "Datum", "label.date-range": "Tidsperiod", "label.day": "Dag", - "label.default-date-range": "Standard Tidsperiod", + "label.default-date-range": "Standard datum-urval", "label.delete": "Radera", "label.delete-team": "Radera team", "label.delete-user": "Radera användare", From c9d3a18af7e552ae7506ec06df066a77c3588d7a Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 22 Dec 2023 21:26:42 -0800 Subject: [PATCH 004/142] Changed props for new Dropdown. --- package.json | 2 +- src/app/(main)/reports/[id]/FieldFilterForm.tsx | 4 ++-- src/app/(main)/settings/profile/LanguageSetting.tsx | 2 +- src/app/(main)/settings/profile/TimezoneSetting.tsx | 2 +- src/app/(main)/websites/[id]/WebsiteExpandedView.tsx | 2 +- src/components/input/DateFilter.tsx | 2 +- src/components/input/WebsiteSelect.tsx | 2 +- yarn.lock | 8 ++++---- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 4d0cd78c..f5c1dc12 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "npm-run-all": "^4.1.5", "prisma": "5.7.0", "react": "^18.2.0", - "react-basics": "^0.114.0", + "react-basics": "^0.116.0", "react-beautiful-dnd": "^13.1.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.4", diff --git a/src/app/(main)/reports/[id]/FieldFilterForm.tsx b/src/app/(main)/reports/[id]/FieldFilterForm.tsx index 4af7febf..1616e10d 100644 --- a/src/app/(main)/reports/[id]/FieldFilterForm.tsx +++ b/src/app/(main)/reports/[id]/FieldFilterForm.tsx @@ -65,7 +65,7 @@ export default function FieldFilterForm({ items={filters} value={filter} renderValue={renderFilterValue} - onChange={(key: any) => setFilter(key)} + onSelect={(key: any) => setFilter(key)} > {({ value, label }) => { return {label}; @@ -78,7 +78,7 @@ export default function FieldFilterForm({ items={values} value={value} renderValue={renderValue} - onChange={(key: any) => setValue(key)} + onSelect={(key: any) => setValue(key)} style={{ minWidth: '250px', }} diff --git a/src/app/(main)/settings/profile/LanguageSetting.tsx b/src/app/(main)/settings/profile/LanguageSetting.tsx index f1b19626..c7b13f7a 100644 --- a/src/app/(main)/settings/profile/LanguageSetting.tsx +++ b/src/app/(main)/settings/profile/LanguageSetting.tsx @@ -19,7 +19,7 @@ export function LanguageSetting() { items={options} value={locale} renderValue={renderValue} - onChange={saveLocale} + onSelect={saveLocale} menuProps={{ style: { height: 300, width: 300 } }} > {item => {languages[item].label}} diff --git a/src/app/(main)/settings/profile/TimezoneSetting.tsx b/src/app/(main)/settings/profile/TimezoneSetting.tsx index fc318081..473998b3 100644 --- a/src/app/(main)/settings/profile/TimezoneSetting.tsx +++ b/src/app/(main)/settings/profile/TimezoneSetting.tsx @@ -16,7 +16,7 @@ export function TimezoneSetting() { diff --git a/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx index f01d9363..bcf18c77 100644 --- a/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx +++ b/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx @@ -134,7 +134,7 @@ export default function WebsiteExpandedView({ items={items} value={view} renderValue={renderValue} - onChange={handleChange} + onSelect={handleChange} alignment="end" > {({ key, label }) => {label}} diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx index f7739f17..62e2d8da 100644 --- a/src/components/input/DateFilter.tsx +++ b/src/components/input/DateFilter.tsx @@ -113,7 +113,7 @@ export function DateFilter({ value={value} alignment={alignment} placeholder={formatMessage(labels.selectDate)} - onChange={key => handleChange(key as any)} + onSelect={key => handleChange(key as any)} > {({ label, value, divider }) => ( diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index e125e258..3a6ca272 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -27,7 +27,7 @@ export function WebsiteSelect({ items={data?.data} value={websiteId} renderValue={renderValue} - onChange={onSelect} + onSelect={onSelect} alignment="end" placeholder={formatMessage(labels.selectWebsite)} > diff --git a/yarn.lock b/yarn.lock index b15b1a13..aef653fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7570,10 +7570,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.114.0: - version "0.114.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.114.0.tgz#b8e2d55759366a30be7a53546215c6d7e0898bca" - integrity sha512-zdGk0Om4yb0JZotYosbvYAFw1GwU22amFAm3iLTuZA5sL6ArH++8BDg7TFQFyaCk73jBWzYFuCiY3+xcJPxiHw== +react-basics@^0.116.0: + version "0.116.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.116.0.tgz#497aa40ceec6c6e849a64be738853f9f04502f8f" + integrity sha512-Vv9CFbrlJPClQ22EvLIdWDmxzY1yRlEd9D4RLYQejl1CsDwvTCjP0Y3zkOmHiFVP9I2VcwUf9uhDf5GASh17dw== dependencies: "@react-spring/web" "^9.7.3" classnames "^2.3.1" From f01abe23c62c69b0e89677f2f6f9e73dc4db8c60 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 26 Dec 2023 10:11:53 -0800 Subject: [PATCH 005/142] show actions in users websites --- src/app/(main)/settings/users/UserWebsites.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/(main)/settings/users/UserWebsites.tsx b/src/app/(main)/settings/users/UserWebsites.tsx index 2d06e82a..3897b5b0 100644 --- a/src/app/(main)/settings/users/UserWebsites.tsx +++ b/src/app/(main)/settings/users/UserWebsites.tsx @@ -16,7 +16,9 @@ export function UserWebsites({ userId }) { {hasData && ( - {({ data }) => } + {({ data }) => ( + + )} )} From 1cf5bd488c5985f69fdb8ed69428eb0d416f233e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 27 Dec 2023 09:22:32 -0800 Subject: [PATCH 006/142] remove kafka engine tables --- db/clickhouse/schema.sql | 131 +-------------------------------------- 1 file changed, 1 insertion(+), 130 deletions(-) diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index 44428e94..741f06ad 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -1,5 +1,3 @@ -SET allow_experimental_object_type = 1; - -- Create Event CREATE TABLE umami.website_event ( @@ -34,82 +32,6 @@ CREATE TABLE umami.website_event ORDER BY (website_id, session_id, created_at) SETTINGS index_granularity = 8192; -CREATE TABLE umami.website_event_queue ( - website_id UUID, - session_id UUID, - event_id UUID, - --sessions - hostname LowCardinality(String), - browser LowCardinality(String), - os LowCardinality(String), - device LowCardinality(String), - screen LowCardinality(String), - language LowCardinality(String), - country LowCardinality(String), - subdivision1 LowCardinality(String), - subdivision2 LowCardinality(String), - city String, - --pageviews - url_path String, - url_query String, - referrer_path String, - referrer_query String, - referrer_domain String, - page_title String, - --events - event_type UInt32, - event_name String, - created_at DateTime('UTC'), - --virtual columns - _error String, - _raw_message String -) -ENGINE = Kafka -SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input broker list - kafka_topic_list = 'event', - kafka_group_name = 'event_consumer_group', - kafka_format = 'JSONEachRow', - kafka_max_block_size = 1048576, - kafka_handle_error_mode = 'stream'; - -CREATE MATERIALIZED VIEW umami.website_event_queue_mv TO umami.website_event AS -SELECT website_id, - session_id, - event_id, - hostname, - browser, - os, - device, - screen, - language, - country, - subdivision1, - subdivision2, - city, - url_path, - url_query, - referrer_path, - referrer_query, - referrer_domain, - page_title, - event_type, - event_name, - created_at -FROM umami.website_event_queue; - -CREATE MATERIALIZED VIEW umami.website_event_errors_mv -( - error String, - raw String -) -ENGINE = MergeTree -ORDER BY (error, raw) -SETTINGS index_granularity = 8192 AS -SELECT _error AS error, - _raw_message AS raw -FROM umami.website_event_queue -WHERE length(_error) > 0; - CREATE TABLE umami.event_data ( website_id UUID, @@ -127,55 +49,4 @@ CREATE TABLE umami.event_data ) engine = MergeTree ORDER BY (website_id, event_id, event_key, created_at) - SETTINGS index_granularity = 8192; - -CREATE TABLE umami.event_data_queue ( - website_id UUID, - session_id UUID, - event_id UUID, - url_path String, - event_name String, - event_key String, - string_value Nullable(String), - number_value Nullable(Decimal64(4)), --922337203685477.5625 - date_value Nullable(DateTime('UTC')), - data_type UInt32, - created_at DateTime('UTC'), - --virtual columns - _error String, - _raw_message String -) -ENGINE = Kafka -SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input broker list - kafka_topic_list = 'event_data', - kafka_group_name = 'event_data_consumer_group', - kafka_format = 'JSONEachRow', - kafka_max_block_size = 1048576, - kafka_handle_error_mode = 'stream'; - -CREATE MATERIALIZED VIEW umami.event_data_queue_mv TO umami.event_data AS -SELECT website_id, - session_id, - event_id, - url_path, - event_name, - event_key, - string_value, - number_value, - date_value, - data_type, - created_at -FROM umami.event_data_queue; - -CREATE MATERIALIZED VIEW umami.event_data_errors_mv -( - error String, - raw String -) -ENGINE = MergeTree -ORDER BY (error, raw) -SETTINGS index_granularity = 8192 AS -SELECT _error AS error, - _raw_message AS raw -FROM umami.event_data_queue -WHERE length(_error) > 0; \ No newline at end of file + SETTINGS index_granularity = 8192; \ No newline at end of file From 6c4a2976971c16a2c5e1ea7c221b1247acecac35 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 27 Dec 2023 14:20:36 -0800 Subject: [PATCH 007/142] Added search to websites dropdown. --- src/components/common/Empty.module.css | 1 + src/components/input/WebsiteSelect.tsx | 46 ++++++++++++++++++++------ src/lib/types.ts | 2 +- src/pages/api/websites/index.ts | 4 --- src/queries/admin/website.ts | 6 ++-- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/components/common/Empty.module.css b/src/components/common/Empty.module.css index 29e9f8eb..3dccb68e 100644 --- a/src/components/common/Empty.module.css +++ b/src/components/common/Empty.module.css @@ -8,4 +8,5 @@ text-align: center; width: 100%; height: 100%; + min-height: 70px; } diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index 3a6ca272..9dd3dd61 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -1,35 +1,61 @@ +import { useState, Key } from 'react'; import { Dropdown, Item } from 'react-basics'; import useApi from 'components/hooks/useApi'; import useMessages from 'components/hooks/useMessages'; import styles from './WebsiteSelect.module.css'; +import Empty from 'components/common/Empty'; export function WebsiteSelect({ websiteId, onSelect, }: { - websiteId: string; + websiteId?: string; onSelect?: (key: any) => void; }) { - const { formatMessage, labels } = useMessages(); + const [query, setQuery] = useState(''); + const [selectedId, setSelectedId] = useState(websiteId); + const { formatMessage, labels, messages } = useMessages(); const { get, useQuery } = useApi(); - const { data } = useQuery({ - queryKey: ['websites:me'], - queryFn: () => get('/me/websites', { pageSize: 100 }), + const { data: websites, isLoading } = useQuery({ + queryKey: ['websites:me', { query }], + queryFn: () => get('/me/websites', { query, pageSize: 5 }), + }); + const { data: website } = useQuery({ + queryKey: ['websites', { selectedId }], + queryFn: () => get(`/websites/${selectedId}`), + enabled: !!selectedId, }); - const renderValue = value => { - return data?.data?.find(({ id }) => id === value)?.name; + const renderValue = () => { + return website?.name; + }; + + const renderEmpty = () => { + return ; + }; + + const handleSelect = (value: any) => { + setSelectedId(value); + onSelect?.(value); + }; + + const handleSearch = (value: string) => { + setQuery(value); }; return ( {({ id, name }) => {name}} diff --git a/src/lib/types.ts b/src/lib/types.ts index af0ea0f7..c4d018a4 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -53,7 +53,7 @@ export interface SearchFilter { } export interface FilterResult { - data: T[]; + data: T; count: number; page: number; pageSize: number; diff --git a/src/pages/api/websites/index.ts b/src/pages/api/websites/index.ts index b30681cf..d0295b87 100644 --- a/src/pages/api/websites/index.ts +++ b/src/pages/api/websites/index.ts @@ -45,10 +45,6 @@ export default async ( req.query.id = userId; } - if (!req.query.pageSize) { - req.query.pageSize = 100; - } - return userWebsites(req as any, res); } diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 524e2e14..0e7f5124 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -21,7 +21,7 @@ export async function getWebsiteByShareId(shareId: string) { export async function getWebsites( filters: WebsiteSearchFilter, options?: { include?: Prisma.WebsiteInclude }, -): Promise> { +): Promise> { const { userId, teamId, includeTeams, onlyTeams, query } = filters; const mode = prisma.getSearchMode(); @@ -105,7 +105,7 @@ export async function getWebsites( export async function getWebsitesByUserId( userId: string, filters?: WebsiteSearchFilter, -): Promise> { +): Promise> { return getWebsites( { userId, ...filters }, { @@ -133,7 +133,7 @@ export async function getWebsitesByUserId( export async function getWebsitesByTeamId( teamId: string, filters?: WebsiteSearchFilter, -): Promise> { +): Promise> { return getWebsites( { teamId, From 63bfad4d9c4effc9f2a39c846d23f68daed9628f Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 27 Dec 2023 19:14:23 -0800 Subject: [PATCH 008/142] Fixed profile button. --- package.json | 2 +- src/components/input/ProfileButton.module.css | 3 +++ src/components/input/ProfileButton.tsx | 2 +- yarn.lock | 8 ++++---- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f5c1dc12..e159844a 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "npm-run-all": "^4.1.5", "prisma": "5.7.0", "react": "^18.2.0", - "react-basics": "^0.116.0", + "react-basics": "^0.117.0", "react-beautiful-dnd": "^13.1.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.4", diff --git a/src/components/input/ProfileButton.module.css b/src/components/input/ProfileButton.module.css index e7843344..e3557b18 100644 --- a/src/components/input/ProfileButton.module.css +++ b/src/components/input/ProfileButton.module.css @@ -1,6 +1,9 @@ .menu { width: 200px; z-index: var(--z-index-popup); + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + overflow: hidden; } .item { diff --git a/src/components/input/ProfileButton.tsx b/src/components/input/ProfileButton.tsx index 2c3f8629..5c1d33f3 100644 --- a/src/components/input/ProfileButton.tsx +++ b/src/components/input/ProfileButton.tsx @@ -34,7 +34,7 @@ export function ProfileButton() { - + {user.username} diff --git a/yarn.lock b/yarn.lock index aef653fa..9e788ec2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7570,10 +7570,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.116.0: - version "0.116.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.116.0.tgz#497aa40ceec6c6e849a64be738853f9f04502f8f" - integrity sha512-Vv9CFbrlJPClQ22EvLIdWDmxzY1yRlEd9D4RLYQejl1CsDwvTCjP0Y3zkOmHiFVP9I2VcwUf9uhDf5GASh17dw== +react-basics@^0.117.0: + version "0.117.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.117.0.tgz#f75c78acac678f6c4c8e1fdcc7e2a9f415148f1d" + integrity sha512-coGwL84LhNrw9kAN2REvR9i6bVs55ZnnQxlDsnH6hnj75Sp36rigGNClSwVN1XTlUWp6k+Gc4rn78cc1E/qn2g== dependencies: "@react-spring/web" "^9.7.3" classnames "^2.3.1" From 048707dffe46d40eb428b2c8a358ad19c169d023 Mon Sep 17 00:00:00 2001 From: jaasonw Date: Wed, 27 Dec 2023 23:02:29 -0800 Subject: [PATCH 009/142] replace all instances of publically with publicly --- public/intl/messages/en-US.json | 2 +- src/components/messages.ts | 2 +- src/lang/en-US.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/intl/messages/en-US.json b/public/intl/messages/en-US.json index 0ee5b1e6..60044243 100644 --- a/public/intl/messages/en-US.json +++ b/public/intl/messages/en-US.json @@ -1382,7 +1382,7 @@ "message.share-url": [ { "type": 0, - "value": "Your website stats are publically available at the following URL:" + "value": "Your website stats are publicly available at the following URL:" } ], "message.team-already-member": [ diff --git a/src/components/messages.ts b/src/components/messages.ts index 04a29a4c..c58b2ca8 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -227,7 +227,7 @@ export const messages = defineMessages({ }, shareUrl: { id: 'message.share-url', - defaultMessage: 'Your website stats are publically available at the following URL:', + defaultMessage: 'Your website stats are publicly available at the following URL:', }, trackingCode: { id: 'message.tracking-code', diff --git a/src/lang/en-US.json b/src/lang/en-US.json index e1d59230..2f957a45 100644 --- a/src/lang/en-US.json +++ b/src/lang/en-US.json @@ -207,7 +207,7 @@ "message.reset-website": "To reset this website, type {confirmation} in the box below to confirm.", "message.reset-website-warning": "All statistics for this website will be deleted, but your settings will remain intact.", "message.saved": "Saved.", - "message.share-url": "Your website stats are publically available at the following URL:", + "message.share-url": "Your website stats are publicly available at the following URL:", "message.team-already-member": "You are already a member of the team.", "message.team-not-found": "Team not found.", "message.team-websites-info": "Websites can be viewed by anyone on the team.", From c24fe079f178683eb4f2dd4946471e866da75615 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 2 Jan 2024 22:22:15 -0800 Subject: [PATCH 010/142] Tracking script should use defer instead of async. --- src/app/(main)/settings/websites/[id]/TrackingCode.tsx | 2 +- src/components/input/ProfileButton.module.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/(main)/settings/websites/[id]/TrackingCode.tsx b/src/app/(main)/settings/websites/[id]/TrackingCode.tsx index 6d05de31..6e5fd99e 100644 --- a/src/app/(main)/settings/websites/[id]/TrackingCode.tsx +++ b/src/app/(main)/settings/websites/[id]/TrackingCode.tsx @@ -16,7 +16,7 @@ export function TrackingCode({ websiteId }: { websiteId: string }) { ? trackerScriptName : `${trackingCodeUrl}${process.env.basePath}/${trackerScriptName}`; - const code = ``; + const code = ``; return ( <> diff --git a/src/components/input/ProfileButton.module.css b/src/components/input/ProfileButton.module.css index e3557b18..981bf4a9 100644 --- a/src/components/input/ProfileButton.module.css +++ b/src/components/input/ProfileButton.module.css @@ -4,6 +4,7 @@ border: 1px solid var(--border-color); border-radius: var(--border-radius); overflow: hidden; + background: var(--base50); } .item { From 1e0c177fe615ff3fce774d0d82cc3546a6106e15 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 3 Jan 2024 10:17:27 -0800 Subject: [PATCH 011/142] Added search to languages and timezone. --- .../profile/LanguageSetting.module.css | 4 ++++ .../settings/profile/LanguageSetting.tsx | 18 +++++++++++++++--- .../profile/TimezoneSetting.module.css | 4 ++++ .../settings/profile/TimezoneSetting.tsx | 12 +++++++++--- src/lib/clickhouse.ts | 2 +- src/lib/prisma.ts | 2 +- src/queries/admin/website.ts | 4 ++-- 7 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 src/app/(main)/settings/profile/LanguageSetting.module.css create mode 100644 src/app/(main)/settings/profile/TimezoneSetting.module.css diff --git a/src/app/(main)/settings/profile/LanguageSetting.module.css b/src/app/(main)/settings/profile/LanguageSetting.module.css new file mode 100644 index 00000000..141445ec --- /dev/null +++ b/src/app/(main)/settings/profile/LanguageSetting.module.css @@ -0,0 +1,4 @@ +div.menu { + max-height: 300px; + width: 300px; +} diff --git a/src/app/(main)/settings/profile/LanguageSetting.tsx b/src/app/(main)/settings/profile/LanguageSetting.tsx index c7b13f7a..b0426cc7 100644 --- a/src/app/(main)/settings/profile/LanguageSetting.tsx +++ b/src/app/(main)/settings/profile/LanguageSetting.tsx @@ -1,17 +1,27 @@ +import { useState } from 'react'; import { Button, Dropdown, Item, Flexbox } from 'react-basics'; import useLocale from 'components/hooks/useLocale'; import { DEFAULT_LOCALE } from 'lib/constants'; import { languages } from 'lib/lang'; import useMessages from 'components/hooks/useMessages'; +import styles from './LanguageSetting.module.css'; export function LanguageSetting() { + const [search, setSearch] = useState(''); const { formatMessage, labels } = useMessages(); const { locale, saveLocale } = useLocale(); - const options = Object.keys(languages); + const options = search + ? Object.keys(languages).filter(n => { + return ( + n.toLowerCase().includes(search.toLowerCase()) || + languages[n].label.toLowerCase().includes(search.toLowerCase()) + ); + }) + : Object.keys(languages); const handleReset = () => saveLocale(DEFAULT_LOCALE); - const renderValue = value => languages[value].label; + const renderValue = (value: string | number) => languages[value].label; return ( @@ -20,7 +30,9 @@ export function LanguageSetting() { value={locale} renderValue={renderValue} onSelect={saveLocale} - menuProps={{ style: { height: 300, width: 300 } }} + allowSearch={true} + onSearch={setSearch} + menuProps={{ className: styles.menu }} > {item => {languages[item].label}} diff --git a/src/app/(main)/settings/profile/TimezoneSetting.module.css b/src/app/(main)/settings/profile/TimezoneSetting.module.css new file mode 100644 index 00000000..141445ec --- /dev/null +++ b/src/app/(main)/settings/profile/TimezoneSetting.module.css @@ -0,0 +1,4 @@ +div.menu { + max-height: 300px; + width: 300px; +} diff --git a/src/app/(main)/settings/profile/TimezoneSetting.tsx b/src/app/(main)/settings/profile/TimezoneSetting.tsx index 473998b3..be86b570 100644 --- a/src/app/(main)/settings/profile/TimezoneSetting.tsx +++ b/src/app/(main)/settings/profile/TimezoneSetting.tsx @@ -1,13 +1,18 @@ +import { useState } from 'react'; import { Dropdown, Item, Button, Flexbox } from 'react-basics'; import { listTimeZones } from 'timezone-support'; import useTimezone from 'components/hooks/useTimezone'; import useMessages from 'components/hooks/useMessages'; import { getTimezone } from 'lib/date'; +import styles from './TimezoneSetting.module.css'; export function TimezoneSetting() { + const [search, setSearch] = useState(''); const { formatMessage, labels } = useMessages(); const [timezone, saveTimezone] = useTimezone(); - const options = listTimeZones(); + const options = search + ? listTimeZones().filter(n => n.toLowerCase().includes(search.toLowerCase())) + : listTimeZones(); const handleReset = () => saveTimezone(getTimezone()); @@ -17,8 +22,9 @@ export function TimezoneSetting() { items={options} value={timezone} onSelect={saveTimezone} - style={{ flex: 1 }} - menuProps={{ style: { height: 300 } }} + menuProps={{ className: styles.menu }} + allowSearch={true} + onSearch={setSearch} > {item => {item}} diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index 2eed340e..c3843cbf 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -110,7 +110,7 @@ async function parseFilters(websiteId: string, filters: QueryFilters = {}, optio params: { ...normalizeFilters(filters), websiteId, - startDate: maxDate(filters.startDate, new Date(website.resetAt)), + startDate: maxDate(filters.startDate, new Date(website?.resetAt)), websiteDomain: website.domain, }, }; diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index cb119bb8..c8b396dc 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -151,7 +151,7 @@ async function parseFilters( params: { ...normalizeFilters(filters), websiteId, - startDate: maxDate(filters.startDate, website.resetAt), + startDate: maxDate(filters.startDate, website?.resetAt), websiteDomain: website.domain, }, }; diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 0e7f5124..86843ba6 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -252,7 +252,7 @@ export async function createWebsite( } export async function updateWebsite( - websiteId, + websiteId: string, data: Prisma.WebsiteUpdateInput | Prisma.WebsiteUncheckedUpdateInput, ): Promise { return prisma.client.website.update({ @@ -264,7 +264,7 @@ export async function updateWebsite( } export async function resetWebsite( - websiteId, + websiteId: string, ): Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Website]> { const { client, transaction } = prisma; From 37f6102ce205d8254500c58e0f20670ff6b50181 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 8 Jan 2024 11:42:38 -0800 Subject: [PATCH 012/142] update time blocks to hour instead of day --- src/queries/analytics/getWebsiteStats.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/queries/analytics/getWebsiteStats.ts b/src/queries/analytics/getWebsiteStats.ts index 4dbdb462..51716b30 100644 --- a/src/queries/analytics/getWebsiteStats.ts +++ b/src/queries/analytics/getWebsiteStats.ts @@ -31,7 +31,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { from ( select website_event.session_id, - ${getDateQuery('website_event.created_at', 'day')}, + ${getDateQuery('website_event.created_at', 'hour')}, count(*) as "c", min(website_event.created_at) as "min_time", max(website_event.created_at) as "max_time" @@ -70,7 +70,7 @@ async function clickhouseQuery( from ( select session_id, - ${getDateQuery('created_at', 'day')} time_series, + ${getDateQuery('created_at', 'hour')} time_series, count(*) c, min(created_at) min_time, max(created_at) max_time From 8eb897f0ca388201c736b2555c972896e7fb7a7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 02:05:06 +0000 Subject: [PATCH 013/142] Bump follow-redirects from 1.15.3 to 1.15.4 Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index b24830a3..fd76871f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4646,9 +4646,9 @@ flatted@^3.2.9: integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== follow-redirects@^1.15.2: - version "1.15.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" - integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== + version "1.15.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" + integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== for-each@^0.3.3: version "0.3.3" From 6b9c83381cfb3866bcc51338a39bd4a9de860e87 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 14 Jan 2024 02:21:39 -0800 Subject: [PATCH 014/142] Updated types. --- package.json | 4 ++-- .../(main)/settings/profile/DateRangeSetting.tsx | 3 ++- src/components/common/DataTable.module.css | 4 ---- src/components/hooks/useDateRange.ts | 2 +- src/lib/clickhouse.ts | 16 +++++++--------- src/lib/prisma.ts | 10 ++++------ src/pages/api/send.ts | 6 +++++- src/queries/admin/report.ts | 14 +++++++------- src/queries/admin/team.ts | 6 +++--- src/queries/admin/user.ts | 4 ++-- src/queries/admin/website.ts | 6 +++--- yarn.lock | 8 ++++---- 12 files changed, 40 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index e159844a..b36b87bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "2.9.0", + "version": "2.10.0", "description": "A simple, fast, privacy-focused alternative to Google Analytics.", "author": "Mike Cao ", "license": "MIT", @@ -99,7 +99,7 @@ "npm-run-all": "^4.1.5", "prisma": "5.7.0", "react": "^18.2.0", - "react-basics": "^0.117.0", + "react-basics": "^0.118.0", "react-beautiful-dnd": "^13.1.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.4", diff --git a/src/app/(main)/settings/profile/DateRangeSetting.tsx b/src/app/(main)/settings/profile/DateRangeSetting.tsx index 85ad6d79..e44d45db 100644 --- a/src/app/(main)/settings/profile/DateRangeSetting.tsx +++ b/src/app/(main)/settings/profile/DateRangeSetting.tsx @@ -3,13 +3,14 @@ import { Button, Flexbox } from 'react-basics'; import useDateRange from 'components/hooks/useDateRange'; import { DEFAULT_DATE_RANGE } from 'lib/constants'; import useMessages from 'components/hooks/useMessages'; +import { DateRange } from 'lib/types'; export function DateRangeSetting() { const { formatMessage, labels } = useMessages(); const [dateRange, setDateRange] = useDateRange(); const { value } = dateRange; - const handleChange = value => setDateRange(value); + const handleChange = (value: string | DateRange) => setDateRange(value); const handleReset = () => setDateRange(DEFAULT_DATE_RANGE); return ( diff --git a/src/components/common/DataTable.module.css b/src/components/common/DataTable.module.css index e738c895..98d84c75 100644 --- a/src/components/common/DataTable.module.css +++ b/src/components/common/DataTable.module.css @@ -29,10 +29,6 @@ gap: 10px; min-height: 70px; align-items: center; - min-width: min-content; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } .body > div > div > div { diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts index efaa717f..115546c7 100644 --- a/src/components/hooks/useDateRange.ts +++ b/src/components/hooks/useDateRange.ts @@ -46,7 +46,7 @@ export function useDateRange(websiteId?: string) { }; return [dateRange, saveDateRange] as [ - { startDate: Date; endDate: Date; modified?: number }, + { startDate: Date; endDate: Date; modified?: number; value?: string }, (value: string | DateRange) => void, ]; } diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index c3843cbf..75328534 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -46,22 +46,22 @@ function getClient() { return client; } -function getDateStringQuery(data, unit) { +function getDateStringQuery(data: any, unit: string | number) { return `formatDateTime(${data}, '${CLICKHOUSE_DATE_FORMATS[unit]}')`; } -function getDateQuery(field, unit, timezone?) { +function getDateQuery(field: string, unit: string, timezone?: string) { if (timezone) { return `date_trunc('${unit}', ${field}, '${timezone}')`; } return `date_trunc('${unit}', ${field})`; } -function getDateFormat(date) { +function getDateFormat(date: Date) { return `'${dateFormat(date, 'UTC:yyyy-mm-dd HH:MM:ss')}'`; } -function mapFilter(column, operator, name, type = 'String') { +function mapFilter(column: string, operator: string, name: string, type = 'String') { switch (operator) { case OPERATORS.equals: return `${column} = {${name}:${type}}`; @@ -130,12 +130,10 @@ async function rawQuery(query: string, params: Record = {}): Pr format: 'JSONEachRow', }); - const data = await resultSet.json(); - - return data; + return resultSet.json(); } -async function findUnique(data) { +async function findUnique(data: any[]) { if (data.length > 1) { throw `${data.length} records found when expecting 1.`; } @@ -143,7 +141,7 @@ async function findUnique(data) { return findFirst(data); } -async function findFirst(data) { +async function findFirst(data: any[]) { return data[0] ?? null; } diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index c8b396dc..1a8e0ba5 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -206,16 +206,14 @@ function getPageFilters(filters: SearchFilter): [ ]; } -function getSearchMode(): { mode?: Prisma.QueryMode } { +function getQueryMode(): Prisma.QueryMode { const db = getDatabaseType(); if (db === POSTGRESQL) { - return { - mode: 'insensitive', - }; + return 'insensitive'; } - return {}; + return 'default'; } export default { @@ -228,6 +226,6 @@ export default { getFilterQuery, parseFilters, getPageFilters, - getSearchMode, + getQueryMode, rawQuery, }; diff --git a/src/pages/api/send.ts b/src/pages/api/send.ts index 1698d858..84b03197 100644 --- a/src/pages/api/send.ts +++ b/src/pages/api/send.ts @@ -131,7 +131,11 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => { return badRequest(res, 'Data required.'); } - await saveSessionData({ ...session, sessionData: eventData, sessionId: session.id }); + await saveSessionData({ + websiteId: session.websiteId, + sessionId: session.id, + sessionData: eventData, + }); } const token = createToken(session, secret()); diff --git a/src/queries/admin/report.ts b/src/queries/admin/report.ts index 2f987681..8d507a1d 100644 --- a/src/queries/admin/report.ts +++ b/src/queries/admin/report.ts @@ -31,7 +31,7 @@ export async function getReports( ): Promise> { const { query, userId, websiteId, includeTeams } = params; - const mode = prisma.getSearchMode(); + const mode = prisma.getQueryMode(); const where: Prisma.ReportWhereInput = { userId, @@ -66,26 +66,26 @@ export async function getReports( { name: { contains: query, - ...mode, + mode, }, }, { description: { contains: query, - ...mode, + mode, }, }, { type: { contains: query, - ...mode, + mode, }, }, { user: { username: { contains: query, - ...mode, + mode, }, }, }, @@ -93,7 +93,7 @@ export async function getReports( website: { name: { contains: query, - ...mode, + mode, }, }, }, @@ -101,7 +101,7 @@ export async function getReports( website: { domain: { contains: query, - ...mode, + mode, }, }, }, diff --git a/src/queries/admin/team.ts b/src/queries/admin/team.ts index 9947b9a3..7bfbfd21 100644 --- a/src/queries/admin/team.ts +++ b/src/queries/admin/team.ts @@ -86,7 +86,7 @@ export async function getTeams( options?: { include?: Prisma.TeamInclude }, ): Promise> { const { userId, query } = filters; - const mode = prisma.getSearchMode(); + const mode = prisma.getQueryMode(); const where: Prisma.TeamWhereInput = { ...(userId && { @@ -98,7 +98,7 @@ export async function getTeams( AND: { OR: [ { - name: { startsWith: query, ...mode }, + name: { startsWith: query, mode }, }, { teamUser: { @@ -107,7 +107,7 @@ export async function getTeams( user: { username: { startsWith: query, - ...mode, + mode, }, }, }, diff --git a/src/queries/admin/user.ts b/src/queries/admin/user.ts index 11f1c846..ddf4f57e 100644 --- a/src/queries/admin/user.ts +++ b/src/queries/admin/user.ts @@ -45,7 +45,7 @@ export async function getUsers( options?: { include?: Prisma.UserInclude }, ): Promise> { const { teamId, query } = params; - const mode = prisma.getSearchMode(); + const mode = prisma.getQueryMode(); const where: Prisma.UserWhereInput = { ...(teamId && { @@ -61,7 +61,7 @@ export async function getUsers( { username: { contains: query, - ...mode, + mode, }, }, ], diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 86843ba6..295d70c8 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -23,7 +23,7 @@ export async function getWebsites( options?: { include?: Prisma.WebsiteInclude }, ): Promise> { const { userId, teamId, includeTeams, onlyTeams, query } = filters; - const mode = prisma.getSearchMode(); + const mode = prisma.getQueryMode(); const where: Prisma.WebsiteWhereInput = { ...(teamId && { @@ -72,10 +72,10 @@ export async function getWebsites( OR: query ? [ { - name: { contains: query, ...mode }, + name: { contains: query, mode }, }, { - domain: { contains: query, ...mode }, + domain: { contains: query, mode }, }, ] : [], diff --git a/yarn.lock b/yarn.lock index 9e788ec2..3315cf11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7570,10 +7570,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.117.0: - version "0.117.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.117.0.tgz#f75c78acac678f6c4c8e1fdcc7e2a9f415148f1d" - integrity sha512-coGwL84LhNrw9kAN2REvR9i6bVs55ZnnQxlDsnH6hnj75Sp36rigGNClSwVN1XTlUWp6k+Gc4rn78cc1E/qn2g== +react-basics@^0.118.0: + version "0.118.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.118.0.tgz#4c00cc96f8ed0c6f95347b714e0965a7772e9c55" + integrity sha512-DLxlWCygMX1nY1mA83qI6mFoN5oVHJFjDdhX119C+CgUIrGY5ynJmPnM5yVoholDHlOLS32npd6Pe02071X3uA== dependencies: "@react-spring/web" "^9.7.3" classnames "^2.3.1" From 2197551e581144df5ed26854f552410ebe576a6e Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 14 Jan 2024 19:04:02 -0800 Subject: [PATCH 015/142] Removed do not track logic. --- src/tracker/index.js | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/tracker/index.js b/src/tracker/index.js index d5278b21..709adc6c 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -18,7 +18,6 @@ const website = attr(_data + 'website-id'); const hostUrl = attr(_data + 'host-url'); const autoTrack = attr(_data + 'auto-track') !== _false; - const dnt = attr(_data + 'do-not-track'); const domain = attr(_data + 'domains') || ''; const domains = domain.split(',').map(n => n.trim()); const root = hostUrl @@ -61,23 +60,8 @@ }); /* Tracking functions */ - - const doNotTrack = () => { - const { doNotTrack, navigator, external } = window; - - const msTrackProtection = 'msTrackingProtectionEnabled'; - const msTracking = () => { - return external && msTrackProtection in external && external[msTrackProtection](); - }; - - const dnt = doNotTrack || navigator.doNotTrack || navigator.msDoNotTrack || msTracking(); - - return dnt == '1' || dnt === 'yes'; - }; - const trackingDisabled = () => (localStorage && localStorage.getItem('umami.disabled')) || - (dnt && doNotTrack()) || (domain && !domains.includes(hostname)); const handlePush = (state, title, url) => { @@ -174,7 +158,7 @@ } }; - const send = (payload, type = 'event') => { + const send = async (payload, type = 'event') => { if (trackingDisabled()) return; const headers = { 'Content-Type': 'application/json', @@ -182,14 +166,17 @@ if (typeof cache !== 'undefined') { headers['x-umami-cache'] = cache; } - return fetch(endpoint, { - method: 'POST', - body: JSON.stringify({ type, payload }), - headers, - }) - .then(res => res.text()) - .then(text => (cache = text)) - .catch(() => {}); // no-op, gulp error + try { + const res = await fetch(endpoint, { + method: 'POST', + body: JSON.stringify({ type, payload }), + headers, + }); + const text = await res.text(); + return (cache = text); + } catch { + /* empty */ + } }; const track = (obj, data) => { From 28d2787880f260a2f057414c384f4217b5e560aa Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 14 Jan 2024 21:17:11 -0800 Subject: [PATCH 016/142] Refactored tracker. Added handling for buttons. --- package.json | 1 - rollup.tracker.config.mjs | 2 - src/app/(main)/console/TestConsole.module.css | 23 ++- src/app/(main)/console/TestConsole.tsx | 39 ++-- src/components/hooks/useDateRange.ts | 2 +- src/components/metrics/EventsChart.tsx | 4 +- src/components/metrics/Legend.tsx | 2 +- src/tracker/index.js | 177 ++++++++++-------- yarn.lock | 111 +---------- 9 files changed, 152 insertions(+), 209 deletions(-) diff --git a/package.json b/package.json index b36b87bb..72ba5394 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,6 @@ "@formatjs/cli": "^4.2.29", "@netlify/plugin-nextjs": "^4.27.3", "@rollup/plugin-alias": "^5.0.0", - "@rollup/plugin-buble": "^1.0.2", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.2.0", diff --git a/rollup.tracker.config.mjs b/rollup.tracker.config.mjs index 465e1af3..6a692efa 100644 --- a/rollup.tracker.config.mjs +++ b/rollup.tracker.config.mjs @@ -1,5 +1,4 @@ import 'dotenv/config'; -import buble from '@rollup/plugin-buble'; import replace from '@rollup/plugin-replace'; import { terser } from 'rollup-plugin-terser'; @@ -15,7 +14,6 @@ export default { delimiters: ['', ''], preventAssignment: true, }), - buble({ objectAssign: true }), terser({ compress: { evaluate: false } }), ], }; diff --git a/src/app/(main)/console/TestConsole.module.css b/src/app/(main)/console/TestConsole.module.css index 9b10a2b2..7d973529 100644 --- a/src/app/(main)/console/TestConsole.module.css +++ b/src/app/(main)/console/TestConsole.module.css @@ -1,7 +1,16 @@ -.test { +.container { + display: grid; + gap: 30px; +} + +.actions { border: 1px solid var(--base400); border-radius: 5px; padding: 0 20px 20px 20px; + display: grid; + gap: 40px; + grid-template-columns: repeat(3, minmax(300px, 1fr)); + box-shadow: 0 0 0 10px var(--base100); } .header { @@ -9,3 +18,15 @@ font-weight: 700; margin: 20px 0; } + +.group { + display: flex; + flex-direction: column; + gap: 10px; +} + +.wrapped { + border: 1px solid var(--blue900); + border-radius: 4px; + padding: 8px 16px; +} diff --git a/src/app/(main)/console/TestConsole.tsx b/src/app/(main)/console/TestConsole.tsx index 0bb807ff..246b7088 100644 --- a/src/app/(main)/console/TestConsole.tsx +++ b/src/app/(main)/console/TestConsole.tsx @@ -82,15 +82,15 @@ export function TestConsole({ websiteId }: { websiteId: string }) { {website && ( - <> +
`; diff --git a/src/app/Providers.tsx b/src/app/Providers.tsx index ac2f0401..3b4e52e7 100644 --- a/src/app/Providers.tsx +++ b/src/app/Providers.tsx @@ -1,10 +1,8 @@ 'use client'; -import { useEffect, useState } from 'react'; import { IntlProvider } from 'react-intl'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactBasicsProvider } from 'react-basics'; import ErrorBoundary from 'components/common/ErrorBoundary'; -import SettingsContext from 'app/(main)/settings/SettingsContext'; import { useLocale } from 'components/hooks'; import 'chartjs-adapter-date-fns'; @@ -26,34 +24,14 @@ function MessagesProvider({ children }) { ); } -function SettingsProvider({ children }) { - const [config, setConfig] = useState({}); - - useEffect(() => { - const hostUrl = process.env.hostUrl || window?.location.origin; - - setConfig({ - shareUrl: hostUrl, - trackingCodeUrl: hostUrl, - websitesUrl: '/websites', - settingsPath: '/settings/websites', - websitesPath: `/websites`, - }); - }, []); - - return {children}; -} - export function Providers({ children }) { return ( - - - - {children} - - - + + + {children} + + ); } diff --git a/src/index.ts b/src/index.ts index 9222e5bd..8bea579e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,8 +48,6 @@ export * from 'app/(main)/settings/websites/WebsiteSettings'; export * from 'app/(main)/settings/websites/WebsitesDataTable'; export * from 'app/(main)/settings/websites/WebsitesTable'; -export * from 'app/(main)/settings/SettingsContext'; - export * from 'components/common/TypeConfirmationForm'; export * from 'components/common/DataTable'; export * from 'components/common/Empty'; From 18e36aa7b392bf6b58cafdefb7ec86dbdf612752 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Mon, 29 Jan 2024 14:47:52 -0800 Subject: [PATCH 042/142] Changed route ids to be more explicit. --- src/app/(main)/console/TestConsole.tsx | 2 +- src/app/(main)/dashboard/Dashboard.tsx | 2 +- .../{[id] => [reportId]}/BaseParameters.tsx | 0 .../FieldAddForm.module.css | 0 .../{[id] => [reportId]}/FieldAddForm.tsx | 0 .../FieldAggregateForm.tsx | 0 .../FieldFilterForm.module.css | 0 .../{[id] => [reportId]}/FieldFilterForm.tsx | 0 .../FieldSelectForm.module.css | 0 .../{[id] => [reportId]}/FieldSelectForm.tsx | 0 .../{[id] => [reportId]}/FilterSelectForm.tsx | 0 .../ParameterList.module.css | 0 .../{[id] => [reportId]}/ParameterList.tsx | 0 .../{[id] => [reportId]}/PopupForm.module.css | 0 .../{[id] => [reportId]}/PopupForm.tsx | 0 .../{[id] => [reportId]}/Report.module.css | 0 .../reports/{[id] => [reportId]}/Report.tsx | 0 .../ReportBody.module.css | 0 .../{[id] => [reportId]}/ReportBody.tsx | 0 .../{[id] => [reportId]}/ReportDetails.tsx | 0 .../ReportHeader.module.css | 0 .../{[id] => [reportId]}/ReportHeader.tsx | 0 .../ReportMenu.module.css | 0 .../{[id] => [reportId]}/ReportMenu.tsx | 0 .../reports/{[id] => [reportId]}/page.tsx | 6 ++--- .../event-data/EventDataParameters.tsx | 8 +++--- .../reports/event-data/EventDataReport.tsx | 8 +++--- .../reports/event-data/EventDataTable.tsx | 2 +- src/app/(main)/reports/funnel/FunnelChart.tsx | 2 +- .../reports/funnel/FunnelParameters.tsx | 8 +++--- .../(main)/reports/funnel/FunnelReport.tsx | 8 +++--- src/app/(main)/reports/funnel/FunnelTable.tsx | 2 +- .../reports/insights/InsightsParameters.tsx | 12 ++++----- .../reports/insights/InsightsReport.tsx | 8 +++--- .../(main)/reports/insights/InsightsTable.tsx | 2 +- .../reports/retention/RetentionParameters.tsx | 4 +-- .../reports/retention/RetentionReport.tsx | 8 +++--- .../reports/retention/RetentionTable.tsx | 2 +- .../teams/{[id] => [teamId]}/TeamData.tsx | 0 .../teams/{[id] => [teamId]}/TeamEditForm.tsx | 0 .../TeamMemberRemoveButton.tsx | 0 .../teams/{[id] => [teamId]}/TeamMembers.tsx | 0 .../{[id] => [teamId]}/TeamMembersTable.tsx | 0 .../teams/{[id] => [teamId]}/TeamSettings.tsx | 12 +++++++-- .../TeamWebsiteRemoveButton.tsx | 0 .../teams/{[id] => [teamId]}/TeamWebsites.tsx | 0 .../{[id] => [teamId]}/TeamWebsitesTable.tsx | 0 .../teams/{[id] => [teamId]}/page.tsx | 4 +-- .../users/{[id] => [userId]}/UserSettings.tsx | 0 .../users/{[id] => [userId]}/UserWebsites.tsx | 0 .../users/{[id] => [userId]}/page.tsx | 4 +-- .../settings/websites/WebsiteSettings.tsx | 10 +++---- .../{[id] => [websiteId]}/ShareUrl.tsx | 0 .../{[id] => [websiteId]}/TrackingCode.tsx | 4 ++- .../{[id] => [websiteId]}/WebsiteData.tsx | 0 .../WebsiteDeleteForm.tsx | 0 .../{[id] => [websiteId]}/WebsiteEditForm.tsx | 0 .../WebsiteResetForm.tsx | 0 .../websites/{[id] => [websiteId]}/page.tsx | 0 .../(main)/teams/{[id] => [teamId]}/Team.tsx | 0 .../teams/{[id] => [teamId]}/layout.tsx | 0 .../websites/[websiteId]/page.tsx | 2 +- .../{[id] => [teamId]}/websites/page.tsx | 6 ++--- .../WebsiteChart.module.css | 0 .../{[id] => [websiteId]}/WebsiteChart.tsx | 0 .../WebsiteChartList.tsx | 0 .../{[id] => [websiteId]}/WebsiteContext.tsx | 0 .../{[id] => [websiteId]}/WebsiteDetails.tsx | 0 .../WebsiteExpandedView.module.css | 0 .../WebsiteExpandedView.tsx | 0 .../WebsiteFilterButton.tsx | 4 +-- .../WebsiteHeader.module.css | 0 .../{[id] => [websiteId]}/WebsiteHeader.tsx | 0 .../WebsiteMetricsBar.module.css | 0 .../WebsiteMetricsBar.tsx | 0 .../WebsiteTableView.tsx | 0 .../event-data/EventDataMetricsBar.module.css | 0 .../event-data/EventDataMetricsBar.tsx | 0 .../event-data/EventDataTable.tsx | 0 .../event-data/EventDataValueTable.tsx | 0 .../event-data/WebsiteEventData.module.css | 0 .../event-data/WebsiteEventData.tsx | 0 .../{[id] => [websiteId]}/event-data/page.tsx | 0 .../websites/{[id] => [websiteId]}/page.tsx | 0 .../realtime/Realtime.module.css | 0 .../realtime/Realtime.tsx | 0 .../realtime/RealtimeCountries.module.css | 0 .../realtime/RealtimeCountries.tsx | 0 .../realtime/RealtimeHeader.module.css | 0 .../realtime/RealtimeHeader.tsx | 0 .../realtime/RealtimeHome.tsx | 0 .../realtime/RealtimeLog.module.css | 0 .../realtime/RealtimeLog.tsx | 0 .../realtime/RealtimeUrls.tsx | 0 .../{[id] => [websiteId]}/realtime/page.tsx | 0 .../reports/WebsiteReports.tsx | 0 .../{[id] => [websiteId]}/reports/page.tsx | 0 .../Footer.module.css | 0 .../{[...id] => [...shareId]}/Footer.tsx | 0 .../Header.module.css | 0 .../{[...id] => [...shareId]}/Header.tsx | 0 .../Share.module.css | 0 .../share/{[...id] => [...shareId]}/Share.tsx | 2 +- .../share/{[...id] => [...shareId]}/page.tsx | 4 +-- src/index.ts | 26 +++++++++---------- 105 files changed, 86 insertions(+), 76 deletions(-) rename src/app/(main)/reports/{[id] => [reportId]}/BaseParameters.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldAddForm.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldAddForm.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldAggregateForm.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldFilterForm.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldFilterForm.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldSelectForm.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FieldSelectForm.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/FilterSelectForm.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ParameterList.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ParameterList.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/PopupForm.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/PopupForm.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/Report.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/Report.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportBody.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportBody.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportDetails.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportHeader.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportHeader.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportMenu.module.css (100%) rename src/app/(main)/reports/{[id] => [reportId]}/ReportMenu.tsx (100%) rename src/app/(main)/reports/{[id] => [reportId]}/page.tsx (55%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamData.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamEditForm.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamMemberRemoveButton.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamMembers.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamMembersTable.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamSettings.tsx (80%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamWebsiteRemoveButton.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamWebsites.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/TeamWebsitesTable.tsx (100%) rename src/app/(main)/settings/teams/{[id] => [teamId]}/page.tsx (51%) rename src/app/(main)/settings/users/{[id] => [userId]}/UserSettings.tsx (100%) rename src/app/(main)/settings/users/{[id] => [userId]}/UserWebsites.tsx (100%) rename src/app/(main)/settings/users/{[id] => [userId]}/page.tsx (51%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/ShareUrl.tsx (100%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/TrackingCode.tsx (93%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/WebsiteData.tsx (100%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/WebsiteDeleteForm.tsx (100%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/WebsiteEditForm.tsx (100%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/WebsiteResetForm.tsx (100%) rename src/app/(main)/settings/websites/{[id] => [websiteId]}/page.tsx (100%) rename src/app/(main)/teams/{[id] => [teamId]}/Team.tsx (100%) rename src/app/(main)/teams/{[id] => [teamId]}/layout.tsx (100%) rename src/app/(main)/teams/{[id] => [teamId]}/websites/[websiteId]/page.tsx (61%) rename src/app/(main)/teams/{[id] => [teamId]}/websites/page.tsx (50%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteChart.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteChart.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteChartList.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteContext.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteDetails.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteExpandedView.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteExpandedView.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteFilterButton.tsx (93%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteHeader.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteHeader.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteMetricsBar.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteMetricsBar.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/WebsiteTableView.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/EventDataMetricsBar.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/EventDataMetricsBar.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/EventDataTable.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/EventDataValueTable.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/WebsiteEventData.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/WebsiteEventData.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/event-data/page.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/page.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/Realtime.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/Realtime.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeCountries.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeCountries.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeHeader.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeHeader.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeHome.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeLog.module.css (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeLog.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/RealtimeUrls.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/realtime/page.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/reports/WebsiteReports.tsx (100%) rename src/app/(main)/websites/{[id] => [websiteId]}/reports/page.tsx (100%) rename src/app/share/{[...id] => [...shareId]}/Footer.module.css (100%) rename src/app/share/{[...id] => [...shareId]}/Footer.tsx (100%) rename src/app/share/{[...id] => [...shareId]}/Header.module.css (100%) rename src/app/share/{[...id] => [...shareId]}/Header.tsx (100%) rename src/app/share/{[...id] => [...shareId]}/Share.module.css (100%) rename src/app/share/{[...id] => [...shareId]}/Share.tsx (87%) rename src/app/share/{[...id] => [...shareId]}/page.tsx (56%) diff --git a/src/app/(main)/console/TestConsole.tsx b/src/app/(main)/console/TestConsole.tsx index 640a81f6..2e11e4b0 100644 --- a/src/app/(main)/console/TestConsole.tsx +++ b/src/app/(main)/console/TestConsole.tsx @@ -7,7 +7,7 @@ import WebsiteSelect from 'components/input/WebsiteSelect'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import EventsChart from 'components/metrics/EventsChart'; -import WebsiteChart from 'app/(main)/websites/[id]/WebsiteChart'; +import WebsiteChart from '../websites/[websiteId]/WebsiteChart'; import { useApi, useNavigation } from 'components/hooks'; import styles from './TestConsole.module.css'; diff --git a/src/app/(main)/dashboard/Dashboard.tsx b/src/app/(main)/dashboard/Dashboard.tsx index e4d8671a..202f88f6 100644 --- a/src/app/(main)/dashboard/Dashboard.tsx +++ b/src/app/(main)/dashboard/Dashboard.tsx @@ -3,7 +3,7 @@ import { Button, Icon, Icons, Loading, Text } from 'react-basics'; import Link from 'next/link'; import PageHeader from 'components/layout/PageHeader'; import Pager from 'components/common/Pager'; -import WebsiteChartList from 'app/(main)/websites/[id]/WebsiteChartList'; +import WebsiteChartList from '../websites/[websiteId]/WebsiteChartList'; import DashboardSettingsButton from 'app/(main)/dashboard/DashboardSettingsButton'; import DashboardEdit from 'app/(main)/dashboard/DashboardEdit'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; diff --git a/src/app/(main)/reports/[id]/BaseParameters.tsx b/src/app/(main)/reports/[reportId]/BaseParameters.tsx similarity index 100% rename from src/app/(main)/reports/[id]/BaseParameters.tsx rename to src/app/(main)/reports/[reportId]/BaseParameters.tsx diff --git a/src/app/(main)/reports/[id]/FieldAddForm.module.css b/src/app/(main)/reports/[reportId]/FieldAddForm.module.css similarity index 100% rename from src/app/(main)/reports/[id]/FieldAddForm.module.css rename to src/app/(main)/reports/[reportId]/FieldAddForm.module.css diff --git a/src/app/(main)/reports/[id]/FieldAddForm.tsx b/src/app/(main)/reports/[reportId]/FieldAddForm.tsx similarity index 100% rename from src/app/(main)/reports/[id]/FieldAddForm.tsx rename to src/app/(main)/reports/[reportId]/FieldAddForm.tsx diff --git a/src/app/(main)/reports/[id]/FieldAggregateForm.tsx b/src/app/(main)/reports/[reportId]/FieldAggregateForm.tsx similarity index 100% rename from src/app/(main)/reports/[id]/FieldAggregateForm.tsx rename to src/app/(main)/reports/[reportId]/FieldAggregateForm.tsx diff --git a/src/app/(main)/reports/[id]/FieldFilterForm.module.css b/src/app/(main)/reports/[reportId]/FieldFilterForm.module.css similarity index 100% rename from src/app/(main)/reports/[id]/FieldFilterForm.module.css rename to src/app/(main)/reports/[reportId]/FieldFilterForm.module.css diff --git a/src/app/(main)/reports/[id]/FieldFilterForm.tsx b/src/app/(main)/reports/[reportId]/FieldFilterForm.tsx similarity index 100% rename from src/app/(main)/reports/[id]/FieldFilterForm.tsx rename to src/app/(main)/reports/[reportId]/FieldFilterForm.tsx diff --git a/src/app/(main)/reports/[id]/FieldSelectForm.module.css b/src/app/(main)/reports/[reportId]/FieldSelectForm.module.css similarity index 100% rename from src/app/(main)/reports/[id]/FieldSelectForm.module.css rename to src/app/(main)/reports/[reportId]/FieldSelectForm.module.css diff --git a/src/app/(main)/reports/[id]/FieldSelectForm.tsx b/src/app/(main)/reports/[reportId]/FieldSelectForm.tsx similarity index 100% rename from src/app/(main)/reports/[id]/FieldSelectForm.tsx rename to src/app/(main)/reports/[reportId]/FieldSelectForm.tsx diff --git a/src/app/(main)/reports/[id]/FilterSelectForm.tsx b/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx similarity index 100% rename from src/app/(main)/reports/[id]/FilterSelectForm.tsx rename to src/app/(main)/reports/[reportId]/FilterSelectForm.tsx diff --git a/src/app/(main)/reports/[id]/ParameterList.module.css b/src/app/(main)/reports/[reportId]/ParameterList.module.css similarity index 100% rename from src/app/(main)/reports/[id]/ParameterList.module.css rename to src/app/(main)/reports/[reportId]/ParameterList.module.css diff --git a/src/app/(main)/reports/[id]/ParameterList.tsx b/src/app/(main)/reports/[reportId]/ParameterList.tsx similarity index 100% rename from src/app/(main)/reports/[id]/ParameterList.tsx rename to src/app/(main)/reports/[reportId]/ParameterList.tsx diff --git a/src/app/(main)/reports/[id]/PopupForm.module.css b/src/app/(main)/reports/[reportId]/PopupForm.module.css similarity index 100% rename from src/app/(main)/reports/[id]/PopupForm.module.css rename to src/app/(main)/reports/[reportId]/PopupForm.module.css diff --git a/src/app/(main)/reports/[id]/PopupForm.tsx b/src/app/(main)/reports/[reportId]/PopupForm.tsx similarity index 100% rename from src/app/(main)/reports/[id]/PopupForm.tsx rename to src/app/(main)/reports/[reportId]/PopupForm.tsx diff --git a/src/app/(main)/reports/[id]/Report.module.css b/src/app/(main)/reports/[reportId]/Report.module.css similarity index 100% rename from src/app/(main)/reports/[id]/Report.module.css rename to src/app/(main)/reports/[reportId]/Report.module.css diff --git a/src/app/(main)/reports/[id]/Report.tsx b/src/app/(main)/reports/[reportId]/Report.tsx similarity index 100% rename from src/app/(main)/reports/[id]/Report.tsx rename to src/app/(main)/reports/[reportId]/Report.tsx diff --git a/src/app/(main)/reports/[id]/ReportBody.module.css b/src/app/(main)/reports/[reportId]/ReportBody.module.css similarity index 100% rename from src/app/(main)/reports/[id]/ReportBody.module.css rename to src/app/(main)/reports/[reportId]/ReportBody.module.css diff --git a/src/app/(main)/reports/[id]/ReportBody.tsx b/src/app/(main)/reports/[reportId]/ReportBody.tsx similarity index 100% rename from src/app/(main)/reports/[id]/ReportBody.tsx rename to src/app/(main)/reports/[reportId]/ReportBody.tsx diff --git a/src/app/(main)/reports/[id]/ReportDetails.tsx b/src/app/(main)/reports/[reportId]/ReportDetails.tsx similarity index 100% rename from src/app/(main)/reports/[id]/ReportDetails.tsx rename to src/app/(main)/reports/[reportId]/ReportDetails.tsx diff --git a/src/app/(main)/reports/[id]/ReportHeader.module.css b/src/app/(main)/reports/[reportId]/ReportHeader.module.css similarity index 100% rename from src/app/(main)/reports/[id]/ReportHeader.module.css rename to src/app/(main)/reports/[reportId]/ReportHeader.module.css diff --git a/src/app/(main)/reports/[id]/ReportHeader.tsx b/src/app/(main)/reports/[reportId]/ReportHeader.tsx similarity index 100% rename from src/app/(main)/reports/[id]/ReportHeader.tsx rename to src/app/(main)/reports/[reportId]/ReportHeader.tsx diff --git a/src/app/(main)/reports/[id]/ReportMenu.module.css b/src/app/(main)/reports/[reportId]/ReportMenu.module.css similarity index 100% rename from src/app/(main)/reports/[id]/ReportMenu.module.css rename to src/app/(main)/reports/[reportId]/ReportMenu.module.css diff --git a/src/app/(main)/reports/[id]/ReportMenu.tsx b/src/app/(main)/reports/[reportId]/ReportMenu.tsx similarity index 100% rename from src/app/(main)/reports/[id]/ReportMenu.tsx rename to src/app/(main)/reports/[reportId]/ReportMenu.tsx diff --git a/src/app/(main)/reports/[id]/page.tsx b/src/app/(main)/reports/[reportId]/page.tsx similarity index 55% rename from src/app/(main)/reports/[id]/page.tsx rename to src/app/(main)/reports/[reportId]/page.tsx index 9ba87f41..1f173d7c 100644 --- a/src/app/(main)/reports/[id]/page.tsx +++ b/src/app/(main)/reports/[reportId]/page.tsx @@ -1,12 +1,12 @@ import ReportDetails from './ReportDetails'; import { Metadata } from 'next'; -export default function ReportDetailsPage({ params: { id } }) { - if (!id) { +export default function ReportDetailsPage({ params: { reportId } }) { + if (!reportId) { return null; } - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/reports/event-data/EventDataParameters.tsx b/src/app/(main)/reports/event-data/EventDataParameters.tsx index 7a39131b..2ee77a43 100644 --- a/src/app/(main)/reports/event-data/EventDataParameters.tsx +++ b/src/app/(main)/reports/event-data/EventDataParameters.tsx @@ -4,10 +4,10 @@ import Empty from 'components/common/Empty'; import Icons from 'components/icons'; import { useApi, useMessages } from 'components/hooks'; import { DATA_TYPES, REPORT_PARAMETERS } from 'lib/constants'; -import { ReportContext } from '../[id]/Report'; -import FieldAddForm from '../[id]/FieldAddForm'; -import ParameterList from '../[id]/ParameterList'; -import BaseParameters from '../[id]/BaseParameters'; +import { ReportContext } from '../[reportId]/Report'; +import FieldAddForm from '../[reportId]/FieldAddForm'; +import ParameterList from '../[reportId]/ParameterList'; +import BaseParameters from '../[reportId]/BaseParameters'; import styles from './EventDataParameters.module.css'; function useFields(websiteId, startDate, endDate) { diff --git a/src/app/(main)/reports/event-data/EventDataReport.tsx b/src/app/(main)/reports/event-data/EventDataReport.tsx index 8b4dc99c..2ce17306 100644 --- a/src/app/(main)/reports/event-data/EventDataReport.tsx +++ b/src/app/(main)/reports/event-data/EventDataReport.tsx @@ -1,7 +1,7 @@ -import Report from '../[id]/Report'; -import ReportHeader from '../[id]/ReportHeader'; -import ReportMenu from '../[id]/ReportMenu'; -import ReportBody from '../[id]/ReportBody'; +import Report from '../[reportId]/Report'; +import ReportHeader from '../[reportId]/ReportHeader'; +import ReportMenu from '../[reportId]/ReportMenu'; +import ReportBody from '../[reportId]/ReportBody'; import EventDataParameters from './EventDataParameters'; import EventDataTable from './EventDataTable'; import Nodes from 'assets/nodes.svg'; diff --git a/src/app/(main)/reports/event-data/EventDataTable.tsx b/src/app/(main)/reports/event-data/EventDataTable.tsx index b709aee7..740cbce4 100644 --- a/src/app/(main)/reports/event-data/EventDataTable.tsx +++ b/src/app/(main)/reports/event-data/EventDataTable.tsx @@ -1,7 +1,7 @@ import { useContext } from 'react'; import { GridTable, GridColumn } from 'react-basics'; import { useMessages } from 'components/hooks'; -import { ReportContext } from '../[id]/Report'; +import { ReportContext } from '../[reportId]/Report'; export function EventDataTable() { const { report } = useContext(ReportContext); diff --git a/src/app/(main)/reports/funnel/FunnelChart.tsx b/src/app/(main)/reports/funnel/FunnelChart.tsx index e401e3cb..38373517 100644 --- a/src/app/(main)/reports/funnel/FunnelChart.tsx +++ b/src/app/(main)/reports/funnel/FunnelChart.tsx @@ -3,7 +3,7 @@ import { Loading, StatusLight } from 'react-basics'; import { useMessages, useTheme } from 'components/hooks'; import BarChart from 'components/metrics/BarChart'; import { formatLongNumber } from 'lib/format'; -import { ReportContext } from '../[id]/Report'; +import { ReportContext } from '../[reportId]/Report'; import styles from './FunnelChart.module.css'; export interface FunnelChartProps { diff --git a/src/app/(main)/reports/funnel/FunnelParameters.tsx b/src/app/(main)/reports/funnel/FunnelParameters.tsx index 0bb45415..c4f8f384 100644 --- a/src/app/(main)/reports/funnel/FunnelParameters.tsx +++ b/src/app/(main)/reports/funnel/FunnelParameters.tsx @@ -13,10 +13,10 @@ import { } from 'react-basics'; import Icons from 'components/icons'; import UrlAddForm from './UrlAddForm'; -import { ReportContext } from '../[id]/Report'; -import BaseParameters from '../[id]/BaseParameters'; -import ParameterList from '../[id]/ParameterList'; -import PopupForm from '../[id]/PopupForm'; +import { ReportContext } from '../[reportId]/Report'; +import BaseParameters from '../[reportId]/BaseParameters'; +import ParameterList from '../[reportId]/ParameterList'; +import PopupForm from '../[reportId]/PopupForm'; export function FunnelParameters() { const { report, runReport, updateReport, isRunning } = useContext(ReportContext); diff --git a/src/app/(main)/reports/funnel/FunnelReport.tsx b/src/app/(main)/reports/funnel/FunnelReport.tsx index 69f46091..b9b4bd77 100644 --- a/src/app/(main)/reports/funnel/FunnelReport.tsx +++ b/src/app/(main)/reports/funnel/FunnelReport.tsx @@ -2,10 +2,10 @@ import FunnelChart from './FunnelChart'; import FunnelTable from './FunnelTable'; import FunnelParameters from './FunnelParameters'; -import Report from '../[id]/Report'; -import ReportHeader from '../[id]/ReportHeader'; -import ReportMenu from '../[id]/ReportMenu'; -import ReportBody from '../[id]/ReportBody'; +import Report from '../[reportId]/Report'; +import ReportHeader from '../[reportId]/ReportHeader'; +import ReportMenu from '../[reportId]/ReportMenu'; +import ReportBody from '../[reportId]/ReportBody'; import Funnel from 'assets/funnel.svg'; import { REPORT_TYPES } from 'lib/constants'; diff --git a/src/app/(main)/reports/funnel/FunnelTable.tsx b/src/app/(main)/reports/funnel/FunnelTable.tsx index 4cf797f2..1fe1fdd9 100644 --- a/src/app/(main)/reports/funnel/FunnelTable.tsx +++ b/src/app/(main)/reports/funnel/FunnelTable.tsx @@ -1,7 +1,7 @@ import { useContext } from 'react'; import ListTable from 'components/metrics/ListTable'; import { useMessages } from 'components/hooks'; -import { ReportContext } from '../[id]/Report'; +import { ReportContext } from '../[reportId]/Report'; export function FunnelTable() { const { report } = useContext(ReportContext); diff --git a/src/app/(main)/reports/insights/InsightsParameters.tsx b/src/app/(main)/reports/insights/InsightsParameters.tsx index cd643eed..a5a98dd2 100644 --- a/src/app/(main)/reports/insights/InsightsParameters.tsx +++ b/src/app/(main)/reports/insights/InsightsParameters.tsx @@ -11,12 +11,12 @@ import { TooltipPopup, } from 'react-basics'; import Icons from 'components/icons'; -import BaseParameters from '../[id]/BaseParameters'; -import { ReportContext } from '../[id]/Report'; -import ParameterList from '../[id]/ParameterList'; -import FilterSelectForm from '../[id]/FilterSelectForm'; -import FieldSelectForm from '../[id]/FieldSelectForm'; -import PopupForm from '../[id]/PopupForm'; +import BaseParameters from '../[reportId]/BaseParameters'; +import { ReportContext } from '../[reportId]/Report'; +import ParameterList from '../[reportId]/ParameterList'; +import FilterSelectForm from '../[reportId]/FilterSelectForm'; +import FieldSelectForm from '../[reportId]/FieldSelectForm'; +import PopupForm from '../[reportId]/PopupForm'; import styles from './InsightsParameters.module.css'; export function InsightsParameters() { diff --git a/src/app/(main)/reports/insights/InsightsReport.tsx b/src/app/(main)/reports/insights/InsightsReport.tsx index b90ff396..709cdf72 100644 --- a/src/app/(main)/reports/insights/InsightsReport.tsx +++ b/src/app/(main)/reports/insights/InsightsReport.tsx @@ -1,8 +1,8 @@ 'use client'; -import Report from '../[id]/Report'; -import ReportHeader from '../[id]/ReportHeader'; -import ReportMenu from '../[id]/ReportMenu'; -import ReportBody from '../[id]/ReportBody'; +import Report from '../[reportId]/Report'; +import ReportHeader from '../[reportId]/ReportHeader'; +import ReportMenu from '../[reportId]/ReportMenu'; +import ReportBody from '../[reportId]/ReportBody'; import InsightsParameters from './InsightsParameters'; import InsightsTable from './InsightsTable'; import Lightbulb from 'assets/lightbulb.svg'; diff --git a/src/app/(main)/reports/insights/InsightsTable.tsx b/src/app/(main)/reports/insights/InsightsTable.tsx index a4517698..2cccc24c 100644 --- a/src/app/(main)/reports/insights/InsightsTable.tsx +++ b/src/app/(main)/reports/insights/InsightsTable.tsx @@ -1,7 +1,7 @@ import { useContext, useEffect, useState } from 'react'; import { GridTable, GridColumn } from 'react-basics'; import { useFormat, useMessages } from 'components/hooks'; -import { ReportContext } from '../[id]/Report'; +import { ReportContext } from '../[reportId]/Report'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; export function InsightsTable() { diff --git a/src/app/(main)/reports/retention/RetentionParameters.tsx b/src/app/(main)/reports/retention/RetentionParameters.tsx index fc168695..9bc1c548 100644 --- a/src/app/(main)/reports/retention/RetentionParameters.tsx +++ b/src/app/(main)/reports/retention/RetentionParameters.tsx @@ -1,9 +1,9 @@ import { useContext } from 'react'; import { useMessages } from 'components/hooks'; import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics'; -import { ReportContext } from '../[id]/Report'; +import { ReportContext } from '../[reportId]/Report'; import { MonthSelect } from 'components/input/MonthSelect'; -import BaseParameters from '../[id]/BaseParameters'; +import BaseParameters from '../[reportId]/BaseParameters'; import { parseDateRange } from 'lib/date'; export function RetentionParameters() { diff --git a/src/app/(main)/reports/retention/RetentionReport.tsx b/src/app/(main)/reports/retention/RetentionReport.tsx index 35f0fcb1..b49975dc 100644 --- a/src/app/(main)/reports/retention/RetentionReport.tsx +++ b/src/app/(main)/reports/retention/RetentionReport.tsx @@ -1,10 +1,10 @@ 'use client'; import RetentionTable from './RetentionTable'; import RetentionParameters from './RetentionParameters'; -import Report from '../[id]/Report'; -import ReportHeader from '../[id]/ReportHeader'; -import ReportMenu from '../[id]/ReportMenu'; -import ReportBody from '../[id]/ReportBody'; +import Report from '../[reportId]/Report'; +import ReportHeader from '../[reportId]/ReportHeader'; +import ReportMenu from '../[reportId]/ReportMenu'; +import ReportBody from '../[reportId]/ReportBody'; import Magnet from 'assets/magnet.svg'; import { REPORT_TYPES } from 'lib/constants'; import { parseDateRange } from 'lib/date'; diff --git a/src/app/(main)/reports/retention/RetentionTable.tsx b/src/app/(main)/reports/retention/RetentionTable.tsx index d2e7f129..171c5bd3 100644 --- a/src/app/(main)/reports/retention/RetentionTable.tsx +++ b/src/app/(main)/reports/retention/RetentionTable.tsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; import classNames from 'classnames'; -import { ReportContext } from '../[id]/Report'; +import { ReportContext } from '../[reportId]/Report'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import { useMessages, useLocale } from 'components/hooks'; import { formatDate } from 'lib/date'; diff --git a/src/app/(main)/settings/teams/[id]/TeamData.tsx b/src/app/(main)/settings/teams/[teamId]/TeamData.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamData.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamData.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamEditForm.tsx b/src/app/(main)/settings/teams/[teamId]/TeamEditForm.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamEditForm.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamEditForm.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamMemberRemoveButton.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamMembers.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamMembers.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamMembersTable.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMembersTable.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamMembersTable.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamMembersTable.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamSettings.tsx b/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx similarity index 80% rename from src/app/(main)/settings/teams/[id]/TeamSettings.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx index 21aafbc4..39d03b87 100644 --- a/src/app/(main)/settings/teams/[id]/TeamSettings.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx @@ -1,6 +1,6 @@ 'use client'; import { useState } from 'react'; -import { Item, Loading, Tabs, Flexbox } from 'react-basics'; +import { Item, Loading, Tabs, Flexbox, Text, Icon } from 'react-basics'; import TeamsContext from 'app/(main)/teams/TeamsContext'; import PageHeader from 'components/layout/PageHeader'; import { ROLES } from 'lib/constants'; @@ -10,6 +10,7 @@ import TeamEditForm from './TeamEditForm'; import TeamMembers from './TeamMembers'; import TeamWebsites from './TeamWebsites'; import TeamData from './TeamData'; +import LinkButton from 'components/common/LinkButton'; export function TeamSettings({ teamId }: { teamId: string }) { const { formatMessage, labels } = useMessages(); @@ -28,7 +29,14 @@ export function TeamSettings({ teamId }: { teamId: string }) { return ( - } /> + }> + + + + + {formatMessage(labels.view)} + + setTab(value)} diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsiteRemoveButton.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamWebsiteRemoveButton.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsites.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamWebsites.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx similarity index 100% rename from src/app/(main)/settings/teams/[id]/TeamWebsitesTable.tsx rename to src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx diff --git a/src/app/(main)/settings/teams/[id]/page.tsx b/src/app/(main)/settings/teams/[teamId]/page.tsx similarity index 51% rename from src/app/(main)/settings/teams/[id]/page.tsx rename to src/app/(main)/settings/teams/[teamId]/page.tsx index 652e65c1..ad242431 100644 --- a/src/app/(main)/settings/teams/[id]/page.tsx +++ b/src/app/(main)/settings/teams/[teamId]/page.tsx @@ -1,9 +1,9 @@ import TeamSettings from './TeamSettings'; -export default function ({ params }) { +export default function ({ params: { teamId } }) { if (process.env.cloudMode) { return null; } - return ; + return ; } diff --git a/src/app/(main)/settings/users/[id]/UserSettings.tsx b/src/app/(main)/settings/users/[userId]/UserSettings.tsx similarity index 100% rename from src/app/(main)/settings/users/[id]/UserSettings.tsx rename to src/app/(main)/settings/users/[userId]/UserSettings.tsx diff --git a/src/app/(main)/settings/users/[id]/UserWebsites.tsx b/src/app/(main)/settings/users/[userId]/UserWebsites.tsx similarity index 100% rename from src/app/(main)/settings/users/[id]/UserWebsites.tsx rename to src/app/(main)/settings/users/[userId]/UserWebsites.tsx diff --git a/src/app/(main)/settings/users/[id]/page.tsx b/src/app/(main)/settings/users/[userId]/page.tsx similarity index 51% rename from src/app/(main)/settings/users/[id]/page.tsx rename to src/app/(main)/settings/users/[userId]/page.tsx index 7a6378aa..e8f1793e 100644 --- a/src/app/(main)/settings/users/[id]/page.tsx +++ b/src/app/(main)/settings/users/[userId]/page.tsx @@ -1,9 +1,9 @@ import UserSettings from './UserSettings'; -export default function ({ params }) { +export default function ({ params: { userId } }) { if (process.env.cloudMode) { return null; } - return ; + return ; } diff --git a/src/app/(main)/settings/websites/WebsiteSettings.tsx b/src/app/(main)/settings/websites/WebsiteSettings.tsx index 55037cee..bceeff01 100644 --- a/src/app/(main)/settings/websites/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/WebsiteSettings.tsx @@ -4,12 +4,12 @@ import { Item, Tabs, Button, Text, Icon, Loading } from 'react-basics'; import Link from 'next/link'; import Icons from 'components/icons'; import PageHeader from 'components/layout/PageHeader'; -import WebsiteEditForm from './[id]/WebsiteEditForm'; -import WebsiteData from './[id]/WebsiteData'; -import TrackingCode from './[id]/TrackingCode'; -import ShareUrl from './[id]/ShareUrl'; +import WebsiteEditForm from './[websiteId]/WebsiteEditForm'; +import WebsiteData from './[websiteId]/WebsiteData'; +import TrackingCode from './[websiteId]/TrackingCode'; +import ShareUrl from './[websiteId]/ShareUrl'; import { useWebsite, useMessages } from 'components/hooks'; -import WebsiteContext from 'app/(main)/websites/[id]/WebsiteContext'; +import WebsiteContext from '../../websites/[websiteId]/WebsiteContext'; export function WebsiteSettings({ websiteId, openExternal = false }) { const { formatMessage, labels } = useMessages(); diff --git a/src/app/(main)/settings/websites/[id]/ShareUrl.tsx b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx similarity index 100% rename from src/app/(main)/settings/websites/[id]/ShareUrl.tsx rename to src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx diff --git a/src/app/(main)/settings/websites/[id]/TrackingCode.tsx b/src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx similarity index 93% rename from src/app/(main)/settings/websites/[id]/TrackingCode.tsx rename to src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx index bf4168d3..66222349 100644 --- a/src/app/(main)/settings/websites/[id]/TrackingCode.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx @@ -1,12 +1,14 @@ import { TextArea } from 'react-basics'; import { useMessages, useConfig } from 'components/hooks'; +const SCRIPT_NAME = 'script.js'; + export function TrackingCode({ websiteId, hostUrl }: { websiteId: string; hostUrl?: string }) { const { formatMessage, messages } = useMessages(); const config = useConfig(); const trackerScriptName = - config?.trackerScriptName?.split(',')?.map((n: string) => n.trim())?.[0] || 'script.js'; + config?.trackerScriptName?.split(',')?.map((n: string) => n.trim())?.[0] || SCRIPT_NAME; const url = trackerScriptName?.startsWith('http') ? trackerScriptName diff --git a/src/app/(main)/settings/websites/[id]/WebsiteData.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx similarity index 100% rename from src/app/(main)/settings/websites/[id]/WebsiteData.tsx rename to src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx diff --git a/src/app/(main)/settings/websites/[id]/WebsiteDeleteForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx similarity index 100% rename from src/app/(main)/settings/websites/[id]/WebsiteDeleteForm.tsx rename to src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx diff --git a/src/app/(main)/settings/websites/[id]/WebsiteEditForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx similarity index 100% rename from src/app/(main)/settings/websites/[id]/WebsiteEditForm.tsx rename to src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx diff --git a/src/app/(main)/settings/websites/[id]/WebsiteResetForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteResetForm.tsx similarity index 100% rename from src/app/(main)/settings/websites/[id]/WebsiteResetForm.tsx rename to src/app/(main)/settings/websites/[websiteId]/WebsiteResetForm.tsx diff --git a/src/app/(main)/settings/websites/[id]/page.tsx b/src/app/(main)/settings/websites/[websiteId]/page.tsx similarity index 100% rename from src/app/(main)/settings/websites/[id]/page.tsx rename to src/app/(main)/settings/websites/[websiteId]/page.tsx diff --git a/src/app/(main)/teams/[id]/Team.tsx b/src/app/(main)/teams/[teamId]/Team.tsx similarity index 100% rename from src/app/(main)/teams/[id]/Team.tsx rename to src/app/(main)/teams/[teamId]/Team.tsx diff --git a/src/app/(main)/teams/[id]/layout.tsx b/src/app/(main)/teams/[teamId]/layout.tsx similarity index 100% rename from src/app/(main)/teams/[id]/layout.tsx rename to src/app/(main)/teams/[teamId]/layout.tsx diff --git a/src/app/(main)/teams/[id]/websites/[websiteId]/page.tsx b/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx similarity index 61% rename from src/app/(main)/teams/[id]/websites/[websiteId]/page.tsx rename to src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx index c9f2927b..eb506411 100644 --- a/src/app/(main)/teams/[id]/websites/[websiteId]/page.tsx +++ b/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx @@ -1,4 +1,4 @@ -import WebsiteDetails from 'app/(main)/websites/[id]/WebsiteDetails'; +import WebsiteDetails from '../../../../websites/[websiteId]/WebsiteDetails'; export default function TeamWebsitePage({ params: { websiteId } }) { return ; diff --git a/src/app/(main)/teams/[id]/websites/page.tsx b/src/app/(main)/teams/[teamId]/websites/page.tsx similarity index 50% rename from src/app/(main)/teams/[id]/websites/page.tsx rename to src/app/(main)/teams/[teamId]/websites/page.tsx index aed17d84..1218c620 100644 --- a/src/app/(main)/teams/[id]/websites/page.tsx +++ b/src/app/(main)/teams/[teamId]/websites/page.tsx @@ -1,11 +1,11 @@ import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable'; import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader'; -export default function TeamWebsitesPage({ params: { id } }: { params: { id: string } }) { +export default function TeamWebsitesPage({ params: { teamId } }: { params: { teamId: string } }) { return ( <> - - + + ); } diff --git a/src/app/(main)/websites/[id]/WebsiteChart.module.css b/src/app/(main)/websites/[websiteId]/WebsiteChart.module.css similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteChart.module.css rename to src/app/(main)/websites/[websiteId]/WebsiteChart.module.css diff --git a/src/app/(main)/websites/[id]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteChart.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteChart.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteChartList.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteChartList.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteContext.tsx b/src/app/(main)/websites/[websiteId]/WebsiteContext.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteContext.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteContext.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteDetails.tsx b/src/app/(main)/websites/[websiteId]/WebsiteDetails.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteDetails.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteDetails.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteExpandedView.module.css b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.module.css similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteExpandedView.module.css rename to src/app/(main)/websites/[websiteId]/WebsiteExpandedView.module.css diff --git a/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteExpandedView.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteFilterButton.tsx b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx similarity index 93% rename from src/app/(main)/websites/[id]/WebsiteFilterButton.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx index 6a02cd47..c06cff45 100644 --- a/src/app/(main)/websites/[id]/WebsiteFilterButton.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx @@ -1,6 +1,6 @@ import { Button, Icon, Icons, Popup, PopupTrigger, Text } from 'react-basics'; -import PopupForm from 'app/(main)/reports/[id]/PopupForm'; -import FilterSelectForm from 'app/(main)/reports/[id]/FilterSelectForm'; +import PopupForm from '../../reports/[reportId]/PopupForm'; +import FilterSelectForm from '../../reports/[reportId]/FilterSelectForm'; import { useMessages, useNavigation } from 'components/hooks'; export function WebsiteFilterButton({ diff --git a/src/app/(main)/websites/[id]/WebsiteHeader.module.css b/src/app/(main)/websites/[websiteId]/WebsiteHeader.module.css similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteHeader.module.css rename to src/app/(main)/websites/[websiteId]/WebsiteHeader.module.css diff --git a/src/app/(main)/websites/[id]/WebsiteHeader.tsx b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteHeader.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteMetricsBar.module.css b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.module.css similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteMetricsBar.module.css rename to src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.module.css diff --git a/src/app/(main)/websites/[id]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteMetricsBar.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx diff --git a/src/app/(main)/websites/[id]/WebsiteTableView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteTableView.tsx similarity index 100% rename from src/app/(main)/websites/[id]/WebsiteTableView.tsx rename to src/app/(main)/websites/[websiteId]/WebsiteTableView.tsx diff --git a/src/app/(main)/websites/[id]/event-data/EventDataMetricsBar.module.css b/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.module.css similarity index 100% rename from src/app/(main)/websites/[id]/event-data/EventDataMetricsBar.module.css rename to src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.module.css diff --git a/src/app/(main)/websites/[id]/event-data/EventDataMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx similarity index 100% rename from src/app/(main)/websites/[id]/event-data/EventDataMetricsBar.tsx rename to src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx diff --git a/src/app/(main)/websites/[id]/event-data/EventDataTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx similarity index 100% rename from src/app/(main)/websites/[id]/event-data/EventDataTable.tsx rename to src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx diff --git a/src/app/(main)/websites/[id]/event-data/EventDataValueTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx similarity index 100% rename from src/app/(main)/websites/[id]/event-data/EventDataValueTable.tsx rename to src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx diff --git a/src/app/(main)/websites/[id]/event-data/WebsiteEventData.module.css b/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.module.css similarity index 100% rename from src/app/(main)/websites/[id]/event-data/WebsiteEventData.module.css rename to src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.module.css diff --git a/src/app/(main)/websites/[id]/event-data/WebsiteEventData.tsx b/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx similarity index 100% rename from src/app/(main)/websites/[id]/event-data/WebsiteEventData.tsx rename to src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx diff --git a/src/app/(main)/websites/[id]/event-data/page.tsx b/src/app/(main)/websites/[websiteId]/event-data/page.tsx similarity index 100% rename from src/app/(main)/websites/[id]/event-data/page.tsx rename to src/app/(main)/websites/[websiteId]/event-data/page.tsx diff --git a/src/app/(main)/websites/[id]/page.tsx b/src/app/(main)/websites/[websiteId]/page.tsx similarity index 100% rename from src/app/(main)/websites/[id]/page.tsx rename to src/app/(main)/websites/[websiteId]/page.tsx diff --git a/src/app/(main)/websites/[id]/realtime/Realtime.module.css b/src/app/(main)/websites/[websiteId]/realtime/Realtime.module.css similarity index 100% rename from src/app/(main)/websites/[id]/realtime/Realtime.module.css rename to src/app/(main)/websites/[websiteId]/realtime/Realtime.module.css diff --git a/src/app/(main)/websites/[id]/realtime/Realtime.tsx b/src/app/(main)/websites/[websiteId]/realtime/Realtime.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/Realtime.tsx rename to src/app/(main)/websites/[websiteId]/realtime/Realtime.tsx diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeCountries.module.css b/src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.module.css similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeCountries.module.css rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.module.css diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeCountries.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeCountries.tsx rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeHeader.module.css b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.module.css similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeHeader.module.css rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.module.css diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeHeader.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeHeader.tsx rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeHome.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeHome.tsx rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeLog.module.css b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.module.css similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeLog.module.css rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.module.css diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeLog.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeLog.tsx rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx diff --git a/src/app/(main)/websites/[id]/realtime/RealtimeUrls.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/RealtimeUrls.tsx rename to src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx diff --git a/src/app/(main)/websites/[id]/realtime/page.tsx b/src/app/(main)/websites/[websiteId]/realtime/page.tsx similarity index 100% rename from src/app/(main)/websites/[id]/realtime/page.tsx rename to src/app/(main)/websites/[websiteId]/realtime/page.tsx diff --git a/src/app/(main)/websites/[id]/reports/WebsiteReports.tsx b/src/app/(main)/websites/[websiteId]/reports/WebsiteReports.tsx similarity index 100% rename from src/app/(main)/websites/[id]/reports/WebsiteReports.tsx rename to src/app/(main)/websites/[websiteId]/reports/WebsiteReports.tsx diff --git a/src/app/(main)/websites/[id]/reports/page.tsx b/src/app/(main)/websites/[websiteId]/reports/page.tsx similarity index 100% rename from src/app/(main)/websites/[id]/reports/page.tsx rename to src/app/(main)/websites/[websiteId]/reports/page.tsx diff --git a/src/app/share/[...id]/Footer.module.css b/src/app/share/[...shareId]/Footer.module.css similarity index 100% rename from src/app/share/[...id]/Footer.module.css rename to src/app/share/[...shareId]/Footer.module.css diff --git a/src/app/share/[...id]/Footer.tsx b/src/app/share/[...shareId]/Footer.tsx similarity index 100% rename from src/app/share/[...id]/Footer.tsx rename to src/app/share/[...shareId]/Footer.tsx diff --git a/src/app/share/[...id]/Header.module.css b/src/app/share/[...shareId]/Header.module.css similarity index 100% rename from src/app/share/[...id]/Header.module.css rename to src/app/share/[...shareId]/Header.module.css diff --git a/src/app/share/[...id]/Header.tsx b/src/app/share/[...shareId]/Header.tsx similarity index 100% rename from src/app/share/[...id]/Header.tsx rename to src/app/share/[...shareId]/Header.tsx diff --git a/src/app/share/[...id]/Share.module.css b/src/app/share/[...shareId]/Share.module.css similarity index 100% rename from src/app/share/[...id]/Share.module.css rename to src/app/share/[...shareId]/Share.module.css diff --git a/src/app/share/[...id]/Share.tsx b/src/app/share/[...shareId]/Share.tsx similarity index 87% rename from src/app/share/[...id]/Share.tsx rename to src/app/share/[...shareId]/Share.tsx index 174f1e44..d8b83fe7 100644 --- a/src/app/share/[...id]/Share.tsx +++ b/src/app/share/[...shareId]/Share.tsx @@ -1,5 +1,5 @@ 'use client'; -import WebsiteDetails from 'app/(main)/websites/[id]/WebsiteDetails'; +import WebsiteDetails from '../../(main)/websites/[websiteId]/WebsiteDetails'; import { useShareToken } from 'components/hooks'; import styles from './Share.module.css'; import Page from 'components/layout/Page'; diff --git a/src/app/share/[...id]/page.tsx b/src/app/share/[...shareId]/page.tsx similarity index 56% rename from src/app/share/[...id]/page.tsx rename to src/app/share/[...shareId]/page.tsx index 2a69f406..5a0b2822 100644 --- a/src/app/share/[...id]/page.tsx +++ b/src/app/share/[...shareId]/page.tsx @@ -1,8 +1,8 @@ import Share from './Share'; import { Metadata } from 'next'; -export default function ({ params: { id } }) { - return ; +export default function ({ params: { shareId } }) { + return ; } export const metadata: Metadata = { diff --git a/src/index.ts b/src/index.ts index 8bea579e..abd00fbf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,14 +19,14 @@ export * from 'components/hooks/useSticky'; export * from 'components/hooks/useTheme'; export * from 'components/hooks/useTimezone'; -export * from 'app/(main)/settings/teams/[id]/TeamEditForm'; -export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton'; -export * from 'app/(main)/settings/teams/[id]/TeamMembers'; -export * from 'app/(main)/settings/teams/[id]/TeamMembersTable'; -export * from 'app/(main)/settings/teams/[id]/TeamSettings'; -export * from 'app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton'; -export * from 'app/(main)/settings/teams/[id]/TeamWebsites'; -export * from 'app/(main)/settings/teams/[id]/TeamWebsitesTable'; +export * from './app/(main)/settings/teams/[teamId]/TeamEditForm'; +export * from './app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton'; +export * from './app/(main)/settings/teams/[teamId]/TeamMembers'; +export * from './app/(main)/settings/teams/[teamId]/TeamMembersTable'; +export * from './app/(main)/settings/teams/[teamId]/TeamSettings'; +export * from './app/(main)/settings/teams/[teamId]/TeamWebsiteRemoveButton'; +export * from './app/(main)/settings/teams/[teamId]/TeamWebsites'; +export * from './app/(main)/settings/teams/[teamId]/TeamWebsitesTable'; export * from 'app/(main)/settings/teams/TeamAddForm'; export * from 'app/(main)/settings/teams/TeamDeleteForm'; export * from 'app/(main)/settings/teams/TeamsHeader'; @@ -36,11 +36,11 @@ export * from 'app/(main)/settings/teams/TeamsDataTable'; export * from 'app/(main)/settings/teams/TeamsTable'; export * from 'app/(main)/settings/teams/WebsiteTags'; -export * from 'app/(main)/settings/websites/[id]/ShareUrl'; -export * from 'app/(main)/settings/websites/[id]/TrackingCode'; -export * from 'app/(main)/settings/websites/[id]/WebsiteDeleteForm'; -export * from 'app/(main)/settings/websites/[id]/WebsiteEditForm'; -export * from 'app/(main)/settings/websites/[id]/WebsiteResetForm'; +export * from './app/(main)/settings/websites/[websiteId]/ShareUrl'; +export * from './app/(main)/settings/websites/[websiteId]/TrackingCode'; +export * from './app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm'; +export * from './app/(main)/settings/websites/[websiteId]/WebsiteEditForm'; +export * from './app/(main)/settings/websites/[websiteId]/WebsiteResetForm'; export * from 'app/(main)/settings/websites/WebsiteAddForm'; export * from 'app/(main)/settings/websites/WebsitesHeader'; From b16f5cc067147b09fd7b27921462d2fc3e303462 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 30 Jan 2024 00:10:25 -0800 Subject: [PATCH 043/142] Refactored queries. --- src/app/(main)/NavBar.tsx | 17 +- .../{[[...id]] => [[...websiteId]]}/page.tsx | 4 +- src/app/(main)/reports/ReportsDataTable.tsx | 10 +- src/app/(main)/reports/ReportsHeader.tsx | 14 +- .../(main)/reports/create/ReportTemplates.tsx | 11 +- .../reports/retention/{page.js => page.tsx} | 3 +- .../settings/profile/LanguageSetting.tsx | 2 +- src/app/(main)/settings/teams/TeamAddForm.tsx | 6 +- .../(main)/settings/teams/TeamJoinForm.tsx | 4 +- .../settings/teams/[teamId]/TeamEditForm.tsx | 28 +-- .../teams/[teamId]/TeamMemberRemoveButton.tsx | 4 +- .../settings/teams/[teamId]/TeamMembers.tsx | 19 +- .../teams/[teamId]/TeamMembersTable.tsx | 18 +- .../settings/teams/[teamId]/TeamSettings.tsx | 6 +- .../settings/teams/[teamId]/TeamWebsites.tsx | 4 +- .../settings/websites/WebsiteAddButton.tsx | 4 +- src/app/(main)/settings/websites/Websites.tsx | 1 + .../settings/websites/WebsitesTable.tsx | 5 +- .../settings/websites/[websiteId]/page.tsx | 6 +- .../teams/[teamId]/reports/TeamReports.tsx | 27 +++ .../teams/[teamId]/reports/create/page.tsx | 10 + .../(main)/teams/[teamId]/reports/page.tsx | 15 ++ .../[teamId]/websites/[websiteId]/page.tsx | 2 +- .../[websiteId]/WebsiteExpandedView.tsx | 28 +-- .../[websiteId]/WebsiteFilterButton.tsx | 4 +- .../[websiteId]/event-data/EventDataTable.tsx | 4 +- .../event-data/EventDataValueTable.tsx | 4 +- .../websites/[websiteId]/event-data/page.tsx | 8 +- src/app/(main)/websites/[websiteId]/page.tsx | 4 +- .../websites/[websiteId]/realtime/page.tsx | 6 +- .../websites/[websiteId]/reports/page.tsx | 6 +- src/components/common/FilterLink.tsx | 4 +- src/components/hooks/queries/useReports.ts | 20 +- .../hooks/queries/useTeamMembers.ts | 16 ++ src/components/hooks/useLocale.ts | 6 +- src/components/hooks/useNavigation.ts | 13 +- src/components/metrics/FilterTags.tsx | 6 +- src/components/metrics/MetricsTable.tsx | 4 +- src/components/metrics/PagesTable.tsx | 4 +- src/lib/cache.ts | 14 +- src/lib/load.ts | 6 +- src/lib/middleware.ts | 6 +- src/lib/prisma.ts | 29 +-- src/lib/types.ts | 4 + src/pages/api/admin/users.ts | 4 +- src/pages/api/admin/websites.ts | 24 +-- src/pages/api/auth/verify.ts | 9 +- src/pages/api/me/password.ts | 4 +- src/pages/api/reports/[id].ts | 8 +- src/pages/api/reports/index.ts | 5 +- src/pages/api/share/[id].ts | 4 +- src/pages/api/teams/[id]/index.ts | 4 +- src/pages/api/teams/[id]/users/index.ts | 4 +- src/pages/api/teams/[id]/websites/index.ts | 4 +- src/pages/api/teams/index.ts | 4 +- src/pages/api/teams/join.ts | 8 +- src/pages/api/users/[id]/index.ts | 6 +- src/pages/api/users/[id]/teams.ts | 4 +- src/pages/api/users/[id]/usage.ts | 6 +- src/pages/api/users/[id]/websites.ts | 4 +- src/pages/api/websites/[id]/index.ts | 4 +- src/pages/api/websites/[id]/reports.ts | 4 +- src/queries/admin/report.ts | 84 ++++---- src/queries/admin/team.ts | 197 +++++++++--------- src/queries/admin/teamUser.ts | 62 ++---- src/queries/admin/user.ts | 84 +++----- src/queries/admin/website.ts | 146 ++++--------- 67 files changed, 523 insertions(+), 576 deletions(-) rename src/app/(main)/console/{[[...id]] => [[...websiteId]]}/page.tsx (73%) rename src/app/(main)/reports/retention/{page.js => page.tsx} (72%) create mode 100644 src/app/(main)/teams/[teamId]/reports/TeamReports.tsx create mode 100644 src/app/(main)/teams/[teamId]/reports/create/page.tsx create mode 100644 src/app/(main)/teams/[teamId]/reports/page.tsx create mode 100644 src/components/hooks/queries/useTeamMembers.ts diff --git a/src/app/(main)/NavBar.tsx b/src/app/(main)/NavBar.tsx index 6eb46cb2..8bdee61a 100644 --- a/src/app/(main)/NavBar.tsx +++ b/src/app/(main)/NavBar.tsx @@ -6,31 +6,30 @@ import Icons from 'components/icons'; import ThemeButton from 'components/input/ThemeButton'; import LanguageButton from 'components/input/LanguageButton'; import ProfileButton from 'components/input/ProfileButton'; -import { useMessages } from 'components/hooks'; +import { useMessages, useNavigation } from 'components/hooks'; import HamburgerButton from 'components/common/HamburgerButton'; -import { usePathname } from 'next/navigation'; import styles from './NavBar.module.css'; export function NavBar() { - const pathname = usePathname(); const { formatMessage, labels } = useMessages(); const cloudMode = Boolean(process.env.cloudMode); + const { pathname, renderTeamUrl } = useNavigation(); const links = [ - { label: formatMessage(labels.dashboard), url: '/dashboard' }, - { label: formatMessage(labels.websites), url: '/websites' }, - { label: formatMessage(labels.reports), url: '/reports' }, - { label: formatMessage(labels.settings), url: '/settings' }, + { label: formatMessage(labels.dashboard), url: renderTeamUrl('/dashboard') }, + { label: formatMessage(labels.websites), url: renderTeamUrl('/websites') }, + { label: formatMessage(labels.reports), url: renderTeamUrl('/reports') }, + { label: formatMessage(labels.settings), url: renderTeamUrl('/settings') }, ].filter(n => n); const menuItems = [ { label: formatMessage(labels.dashboard), - url: '/dashboard', + url: renderTeamUrl('/dashboard'), }, !cloudMode && { label: formatMessage(labels.settings), - url: '/settings', + url: renderTeamUrl('/settings'), children: [ { label: formatMessage(labels.websites), diff --git a/src/app/(main)/console/[[...id]]/page.tsx b/src/app/(main)/console/[[...websiteId]]/page.tsx similarity index 73% rename from src/app/(main)/console/[[...id]]/page.tsx rename to src/app/(main)/console/[[...websiteId]]/page.tsx index f3d865f6..3c4b8bb8 100644 --- a/src/app/(main)/console/[[...id]]/page.tsx +++ b/src/app/(main)/console/[[...websiteId]]/page.tsx @@ -5,14 +5,14 @@ async function getEnabled() { return !!process.env.ENABLE_TEST_CONSOLE; } -export default async function ({ params: { id } }) { +export default async function ({ params: { websiteId } }) { const enabled = await getEnabled(); if (!enabled) { return null; } - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/reports/ReportsDataTable.tsx b/src/app/(main)/reports/ReportsDataTable.tsx index 3ede4783..5e0de599 100644 --- a/src/app/(main)/reports/ReportsDataTable.tsx +++ b/src/app/(main)/reports/ReportsDataTable.tsx @@ -3,8 +3,14 @@ import { useReports } from 'components/hooks'; import ReportsTable from './ReportsTable'; import DataTable from 'components/common/DataTable'; -export default function ReportsDataTable({ websiteId }: { websiteId?: string }) { - const queryResult = useReports(websiteId); +export default function ReportsDataTable({ + websiteId, + teamId, +}: { + websiteId?: string; + teamId?: string; +}) { + const queryResult = useReports({ websiteId, teamId }); return ( diff --git a/src/app/(main)/reports/ReportsHeader.tsx b/src/app/(main)/reports/ReportsHeader.tsx index 43cce217..0f885af7 100644 --- a/src/app/(main)/reports/ReportsHeader.tsx +++ b/src/app/(main)/reports/ReportsHeader.tsx @@ -1,23 +1,21 @@ 'use client'; import PageHeader from 'components/layout/PageHeader'; -import { Button, Icon, Icons, Text } from 'react-basics'; -import { useMessages } from 'components/hooks'; -import { useRouter } from 'next/navigation'; +import { Icon, Icons, Text } from 'react-basics'; +import { useMessages, useNavigation } from 'components/hooks'; +import LinkButton from 'components/common/LinkButton'; export function ReportsHeader() { const { formatMessage, labels } = useMessages(); - const router = useRouter(); - - const handleClick = () => router.push('/reports/create'); + const { renderTeamUrl } = useNavigation(); return ( - + ); } diff --git a/src/app/(main)/reports/create/ReportTemplates.tsx b/src/app/(main)/reports/create/ReportTemplates.tsx index 003cb3fc..886146b2 100644 --- a/src/app/(main)/reports/create/ReportTemplates.tsx +++ b/src/app/(main)/reports/create/ReportTemplates.tsx @@ -6,7 +6,7 @@ import Funnel from 'assets/funnel.svg'; import Lightbulb from 'assets/lightbulb.svg'; import Magnet from 'assets/magnet.svg'; import styles from './ReportTemplates.module.css'; -import { useMessages } from 'components/hooks'; +import { useMessages, useNavigation } from 'components/hooks'; function ReportItem({ title, description, url, icon }) { const { formatMessage, labels } = useMessages(); @@ -32,26 +32,27 @@ function ReportItem({ title, description, url, icon }) { ); } -export function ReportTemplates({ showHeader = true }) { +export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) { const { formatMessage, labels } = useMessages(); + const { renderTeamUrl } = useNavigation(); const reports = [ { title: formatMessage(labels.insights), description: formatMessage(labels.insightsDescription), - url: '/reports/insights', + url: renderTeamUrl('/reports/insights'), icon: , }, { title: formatMessage(labels.funnel), description: formatMessage(labels.funnelDescription), - url: '/reports/funnel', + url: renderTeamUrl('/reports/funnel'), icon: , }, { title: formatMessage(labels.retention), description: formatMessage(labels.retentionDescription), - url: '/reports/retention', + url: renderTeamUrl('/reports/retention'), icon: , }, ]; diff --git a/src/app/(main)/reports/retention/page.js b/src/app/(main)/reports/retention/page.tsx similarity index 72% rename from src/app/(main)/reports/retention/page.js rename to src/app/(main)/reports/retention/page.tsx index 7c60cee8..4e316793 100644 --- a/src/app/(main)/reports/retention/page.js +++ b/src/app/(main)/reports/retention/page.tsx @@ -1,9 +1,10 @@ +import { Metadata } from 'next'; import RetentionReport from './RetentionReport'; export default function RetentionReportPage() { return ; } -export const metadata = { +export const metadata: Metadata = { title: 'Create Report | umami', }; diff --git a/src/app/(main)/settings/profile/LanguageSetting.tsx b/src/app/(main)/settings/profile/LanguageSetting.tsx index 40546f4d..3004af1e 100644 --- a/src/app/(main)/settings/profile/LanguageSetting.tsx +++ b/src/app/(main)/settings/profile/LanguageSetting.tsx @@ -28,7 +28,7 @@ export function LanguageSetting() { items={options} value={locale} renderValue={renderValue} - onChange={saveLocale} + onChange={val => saveLocale(val as string)} allowSearch={true} onSearch={setSearch} menuProps={{ className: styles.menu }} diff --git a/src/app/(main)/settings/teams/TeamAddForm.tsx b/src/app/(main)/settings/teams/TeamAddForm.tsx index 24a8d96e..0af3cc8f 100644 --- a/src/app/(main)/settings/teams/TeamAddForm.tsx +++ b/src/app/(main)/settings/teams/TeamAddForm.tsx @@ -7,7 +7,7 @@ import { Button, SubmitButton, } from 'react-basics'; -import { setValue } from 'store/cache'; +import { touch } from 'store/cache'; import { useApi, useMessages } from 'components/hooks'; export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) { @@ -17,10 +17,10 @@ export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose: mutationFn: (data: any) => post('/teams', data), }); - const handleSubmit = async data => { + const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { - setValue('teams', Date.now()); + touch('teams'); onSave?.(); onClose?.(); }, diff --git a/src/app/(main)/settings/teams/TeamJoinForm.tsx b/src/app/(main)/settings/teams/TeamJoinForm.tsx index 9a91d1a5..5c292b51 100644 --- a/src/app/(main)/settings/teams/TeamJoinForm.tsx +++ b/src/app/(main)/settings/teams/TeamJoinForm.tsx @@ -9,7 +9,7 @@ import { SubmitButton, } from 'react-basics'; import { useApi, useMessages } from 'components/hooks'; -import { setValue } from 'store/cache'; +import { touch } from 'store/cache'; export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) { const { formatMessage, labels, getMessage } = useMessages(); @@ -20,7 +20,7 @@ export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { - setValue('teams:members', Date.now()); + touch('teams:members'); onSave?.(); onClose?.(); }, diff --git a/src/app/(main)/settings/teams/[teamId]/TeamEditForm.tsx b/src/app/(main)/settings/teams/[teamId]/TeamEditForm.tsx index 6cc8de5d..8af74a26 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamEditForm.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamEditForm.tsx @@ -18,11 +18,11 @@ const generateId = () => getRandomChars(16); export function TeamEditForm({ teamId, data, - readOnly, + allowEdit, }: { teamId: string; data?: { name: string; accessCode: string }; - readOnly?: boolean; + allowEdit?: boolean; }) { const { formatMessage, labels, messages } = useMessages(); const { post, useMutation } = useApi(); @@ -57,22 +57,24 @@ export function TeamEditForm({ - {!readOnly && ( + {allowEdit && ( )} - {readOnly && data.name} + {!allowEdit && data.name} - - - - {!readOnly && ( - - )} - - - {!readOnly && ( + {allowEdit && ( + + + + {allowEdit && ( + + )} + + + )} + {allowEdit && ( {formatMessage(labels.save)} diff --git a/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx index a5e05bd7..19f29fd2 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx @@ -1,6 +1,6 @@ import { useApi, useMessages } from 'components/hooks'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; -import { setValue } from 'store/cache'; +import { touch } from 'store/cache'; export function TeamMemberRemoveButton({ teamId, @@ -22,7 +22,7 @@ export function TeamMemberRemoveButton({ const handleRemoveTeamMember = () => { mutate(null, { onSuccess: () => { - setValue('team:members', Date.now()); + touch('team:members'); onSave?.(); }, }); diff --git a/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx index cd6965c5..75e88e25 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx @@ -1,24 +1,13 @@ -import { useApi, useFilterQuery } from 'components/hooks'; import DataTable from 'components/common/DataTable'; -import useCache from 'store/cache'; import TeamMembersTable from './TeamMembersTable'; +import useTeamMembers from 'components/hooks/queries/useTeamMembers'; -export function TeamMembers({ teamId, readOnly }: { teamId: string; readOnly: boolean }) { - const { get } = useApi(); - const modified = useCache(state => state?.['team:members']); - const queryResult = useFilterQuery({ - queryKey: ['team:members', { teamId, modified }], - queryFn: params => { - return get(`/teams/${teamId}/users`, { - ...params, - }); - }, - enabled: !!teamId, - }); +export function TeamMembers({ teamId, allowEdit }: { teamId: string; allowEdit: boolean }) { + const queryResult = useTeamMembers(teamId); return ( - {({ data }) => } + {({ data }) => } ); } diff --git a/src/app/(main)/settings/teams/[teamId]/TeamMembersTable.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMembersTable.tsx index 93d7c521..d993bbc0 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamMembersTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamMembersTable.tsx @@ -6,11 +6,11 @@ import TeamMemberRemoveButton from './TeamMemberRemoveButton'; export function TeamMembersTable({ data = [], teamId, - readOnly, + allowEdit, }: { data: any[]; teamId: string; - readOnly: boolean; + allowEdit: boolean; }) { const { formatMessage, labels } = useMessages(); const { user } = useLogin(); @@ -23,16 +23,20 @@ export function TeamMembersTable({ return ( - + + {row => row?.user?.username} + - {row => roles[row?.teamUser?.[0]?.role]} + {row => roles[row?.role]} {row => { return ( - !readOnly && - row?.teamUser?.[0]?.role !== ROLES.teamOwner && - user?.id !== row?.id && + allowEdit && + row?.role !== ROLES.teamOwner && + user?.id !== row?.id && ( + + ) ); }} diff --git a/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx b/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx index 39d03b87..f0a16604 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx @@ -47,9 +47,9 @@ export function TeamSettings({ teamId }: { teamId: string }) { {formatMessage(labels.websites)} {formatMessage(labels.data)} - {tab === 'details' && } - {tab === 'members' && } - {tab === 'websites' && } + {tab === 'details' && } + {tab === 'members' && } + {tab === 'websites' && } {canEdit && tab === 'data' && } diff --git a/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx index 24d38bc3..25f459d5 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx @@ -1,7 +1,7 @@ import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable'; -export function TeamWebsites({ teamId }: { teamId: string; readOnly: boolean }) { - return ; +export function TeamWebsites({ teamId, allowEdit }: { teamId: string; allowEdit: boolean }) { + return ; } export default TeamWebsites; diff --git a/src/app/(main)/settings/websites/WebsiteAddButton.tsx b/src/app/(main)/settings/websites/WebsiteAddButton.tsx index edda0c1b..e16b900e 100644 --- a/src/app/(main)/settings/websites/WebsiteAddButton.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddButton.tsx @@ -1,7 +1,7 @@ import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import WebsiteAddForm from './WebsiteAddForm'; import { useMessages } from 'components/hooks'; -import { setValue } from 'store/cache'; +import { touch } from 'store/cache'; export function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); @@ -9,7 +9,7 @@ export function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?: const handleSave = async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); - setValue('websites', Date.now()); + touch('websites'); onSave?.(); }; diff --git a/src/app/(main)/settings/websites/Websites.tsx b/src/app/(main)/settings/websites/Websites.tsx index f767cd5f..9f14f4e6 100644 --- a/src/app/(main)/settings/websites/Websites.tsx +++ b/src/app/(main)/settings/websites/Websites.tsx @@ -5,6 +5,7 @@ import WebsitesHeader from './WebsitesHeader'; export default function Websites() { const { user } = useLogin(); + return ( <> diff --git a/src/app/(main)/settings/websites/WebsitesTable.tsx b/src/app/(main)/settings/websites/WebsitesTable.tsx index 701678f5..159d0b5e 100644 --- a/src/app/(main)/settings/websites/WebsitesTable.tsx +++ b/src/app/(main)/settings/websites/WebsitesTable.tsx @@ -1,7 +1,7 @@ import { ReactNode } from 'react'; import Link from 'next/link'; import { Button, Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; -import { useMessages, useLogin } from 'components/hooks'; +import { useMessages, useLogin, useNavigation } from 'components/hooks'; export interface WebsitesTableProps { data: any[]; @@ -23,6 +23,7 @@ export function WebsitesTable({ const { formatMessage, labels } = useMessages(); const { user } = useLogin(); const breakpoint = useBreakpoint(); + const { renderTeamUrl } = useNavigation(); return ( @@ -46,7 +47,7 @@ export function WebsitesTable({ )} {allowView && ( - + + + + + + ); +} + +export default TeamReports; diff --git a/src/app/(main)/teams/[teamId]/reports/create/page.tsx b/src/app/(main)/teams/[teamId]/reports/create/page.tsx new file mode 100644 index 00000000..77127dfb --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/create/page.tsx @@ -0,0 +1,10 @@ +import { Metadata } from 'next'; +import ReportTemplates from 'app/(main)/reports/create/ReportTemplates'; + +export default function () { + return ; +} + +export const metadata: Metadata = { + title: 'Create Report | umami', +}; diff --git a/src/app/(main)/teams/[teamId]/reports/page.tsx b/src/app/(main)/teams/[teamId]/reports/page.tsx new file mode 100644 index 00000000..ad2ea4dd --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/page.tsx @@ -0,0 +1,15 @@ +import { Metadata } from 'next'; +import ReportsHeader from 'app/(main)/reports/ReportsHeader'; +import ReportsDataTable from 'app/(main)/reports/ReportsDataTable'; + +export default function ({ params: { teamId } }) { + return ( + <> + + + + ); +} +export const metadata: Metadata = { + title: 'Reports | umami', +}; diff --git a/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx b/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx index eb506411..1684e740 100644 --- a/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx +++ b/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx @@ -1,4 +1,4 @@ -import WebsiteDetails from '../../../../websites/[websiteId]/WebsiteDetails'; +import WebsiteDetails from 'app/(main)/websites/[websiteId]/WebsiteDetails'; export default function TeamWebsitePage({ params: { websiteId } }) { return ; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx index 2f7a9a9f..e0826a73 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx @@ -43,7 +43,7 @@ export default function WebsiteExpandedView({ const { formatMessage, labels } = useMessages(); const { router, - makeUrl, + renderUrl, pathname, query: { view }, } = useNavigation(); @@ -52,69 +52,69 @@ export default function WebsiteExpandedView({ { key: 'url', label: formatMessage(labels.pages), - url: makeUrl({ view: 'url' }), + url: renderUrl({ view: 'url' }), }, { key: 'referrer', label: formatMessage(labels.referrers), - url: makeUrl({ view: 'referrer' }), + url: renderUrl({ view: 'referrer' }), }, { key: 'browser', label: formatMessage(labels.browsers), - url: makeUrl({ view: 'browser' }), + url: renderUrl({ view: 'browser' }), }, { key: 'os', label: formatMessage(labels.os), - url: makeUrl({ view: 'os' }), + url: renderUrl({ view: 'os' }), }, { key: 'device', label: formatMessage(labels.devices), - url: makeUrl({ view: 'device' }), + url: renderUrl({ view: 'device' }), }, { key: 'country', label: formatMessage(labels.countries), - url: makeUrl({ view: 'country' }), + url: renderUrl({ view: 'country' }), }, { key: 'region', label: formatMessage(labels.regions), - url: makeUrl({ view: 'region' }), + url: renderUrl({ view: 'region' }), }, { key: 'city', label: formatMessage(labels.cities), - url: makeUrl({ view: 'city' }), + url: renderUrl({ view: 'city' }), }, { key: 'language', label: formatMessage(labels.languages), - url: makeUrl({ view: 'language' }), + url: renderUrl({ view: 'language' }), }, { key: 'screen', label: formatMessage(labels.screens), - url: makeUrl({ view: 'screen' }), + url: renderUrl({ view: 'screen' }), }, { key: 'event', label: formatMessage(labels.events), - url: makeUrl({ view: 'event' }), + url: renderUrl({ view: 'event' }), }, { key: 'query', label: formatMessage(labels.queryParameters), - url: makeUrl({ view: 'query' }), + url: renderUrl({ view: 'query' }), }, ]; const DetailsComponent = views[view] || (() => null); const handleChange = (view: any) => { - router.push(makeUrl({ view })); + router.push(renderUrl({ view })); }; const renderValue = (value: string) => items.find(({ key }) => key === value)?.label; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx index c06cff45..63348cc0 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx @@ -11,7 +11,7 @@ export function WebsiteFilterButton({ className?: string; }) { const { formatMessage, labels } = useMessages(); - const { makeUrl, router } = useNavigation(); + const { renderUrl, router } = useNavigation(); const fieldOptions = [ { name: 'url', type: 'string', label: formatMessage(labels.url) }, @@ -25,7 +25,7 @@ export function WebsiteFilterButton({ ]; const handleAddFilter = ({ name, value }) => { - router.push(makeUrl({ [name]: value })); + router.push(renderUrl({ [name]: value })); }; return ( diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx index fb98e7e7..71c36992 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx @@ -6,7 +6,7 @@ import { DATA_TYPES } from 'lib/constants'; export function EventDataTable({ data = [] }) { const { formatMessage, labels } = useMessages(); - const { makeUrl } = useNavigation(); + const { renderUrl } = useNavigation(); if (data.length === 0) { return ; @@ -16,7 +16,7 @@ export function EventDataTable({ data = [] }) { {row => ( - + {row.eventName} )} diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx index 7976ce36..acaa6ae9 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx @@ -8,12 +8,12 @@ import { DATA_TYPES } from 'lib/constants'; export function EventDataValueTable({ data = [], event }: { data: any[]; event: string }) { const { formatMessage, labels } = useMessages(); - const { makeUrl } = useNavigation(); + const { renderUrl } = useNavigation(); const Title = () => { return ( <> - + diff --git a/src/components/metrics/ListTable.tsx b/src/components/metrics/ListTable.tsx index fa6bc656..133905e1 100644 --- a/src/components/metrics/ListTable.tsx +++ b/src/components/metrics/ListTable.tsx @@ -63,6 +63,7 @@ export function ListTable({ {data?.length === 0 && } {virtualize && data.length > 0 ? ( Date: Tue, 30 Jan 2024 13:46:16 -0800 Subject: [PATCH 045/142] Refactored date navigation. --- src/components/hooks/useDateRange.ts | 7 +- src/components/input/DateFilter.tsx | 50 +++-- src/components/input/WebsiteDateFilter.tsx | 25 ++- src/lib/date.ts | 215 +++++++++++++-------- src/lib/types.ts | 5 +- 5 files changed, 181 insertions(+), 121 deletions(-) diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts index 7e3b8bcb..e022d960 100644 --- a/src/components/hooks/useDateRange.ts +++ b/src/components/hooks/useDateRange.ts @@ -7,7 +7,7 @@ import { DateRange } from 'lib/types'; import { useLocale } from './useLocale'; import { useApi } from './queries/useApi'; -export function useDateRange(websiteId?: string) { +export function useDateRange(websiteId?: string): [DateRange, (value: string | DateRange) => void] { const { get } = useApi(); const { locale } = useLocale(); const websiteConfig = websiteStore(state => state[websiteId]?.dateRange); @@ -45,10 +45,7 @@ export function useDateRange(websiteId?: string) { } }; - return [dateRange, saveDateRange] as [ - { startDate: Date; endDate: Date; modified?: number; value?: string; unit?: string }, - (value: string | DateRange) => void, - ]; + return [dateRange, saveDateRange]; } export default useDateRange; diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx index 767f5e40..1fabc735 100644 --- a/src/components/input/DateFilter.tsx +++ b/src/components/input/DateFilter.tsx @@ -5,12 +5,13 @@ import DatePickerForm from 'components/metrics/DatePickerForm'; import { useLocale } from 'components/hooks'; import { useMessages } from 'components/hooks'; import Icons from 'components/icons'; -import { formatDate } from 'lib/date'; +import { formatDate, parseDateValue } from 'lib/date'; export interface DateFilterProps { value: string; startDate: Date; endDate: Date; + offset: number; className?: string; onChange?: (value: string) => void; selectedUnit?: string; @@ -19,17 +20,18 @@ export interface DateFilterProps { } export function DateFilter({ - value, startDate, endDate, + value, + offset, className, onChange, - selectedUnit, showAllTime = false, alignment = 'end', }: DateFilterProps) { const { formatMessage, labels } = useMessages(); const [showPicker, setShowPicker] = useState(false); + const { locale } = useLocale(); const options = [ { label: formatMessage(labels.today), value: '1day' }, @@ -76,19 +78,6 @@ export function DateFilter({ }, ].filter(n => n); - const renderValue = (value: string) => { - return value.startsWith('range') ? ( - handleChange('custom')} - /> - ) : ( - options.find(e => e.value === value).label - ); - }; - const handleChange = (value: string) => { if (value === 'custom') { setShowPicker(true); @@ -104,6 +93,31 @@ export function DateFilter({ const handleClose = () => setShowPicker(false); + const renderValue = (value: string) => { + const { unit } = parseDateValue(value); + + if (offset && unit === 'year') { + return formatDate(startDate, 'yyyy', locale); + } + + if (offset && unit === 'month') { + return formatDate(startDate, 'MMMM yyyy', locale); + } + + if (value.startsWith('range') || offset) { + return ( + handleChange('custom')} + /> + ); + } + + return options.find(e => e.value === value).label; + }; + return ( <> { +const CustomRange = ({ startDate, endDate, unit, onClick }) => { const { locale } = useLocale(); - const monthFormat = +selectedUnit?.num === 1 && selectedUnit?.unit === 'month'; + const monthFormat = unit === 'month'; function handleClick(e) { e.stopPropagation(); diff --git a/src/components/input/WebsiteDateFilter.tsx b/src/components/input/WebsiteDateFilter.tsx index 03a84146..46df3623 100644 --- a/src/components/input/WebsiteDateFilter.tsx +++ b/src/components/input/WebsiteDateFilter.tsx @@ -1,36 +1,35 @@ import { useDateRange } from 'components/hooks'; import { isAfter } from 'date-fns'; -import { incrementDateRange } from 'lib/date'; +import { getOffsetDateRange } from 'lib/date'; import { Button, Icon, Icons } from 'react-basics'; import DateFilter from './DateFilter'; import styles from './WebsiteDateFilter.module.css'; +import { DateRange } from 'lib/types'; export function WebsiteDateFilter({ websiteId }: { websiteId: string }) { const [dateRange, setDateRange] = useDateRange(websiteId); - const { value, startDate, endDate, selectedUnit } = dateRange; - const isFutureDate = - value !== 'all' && - selectedUnit && - isAfter(incrementDateRange(dateRange, -1).startDate, new Date()); + const { value, startDate, endDate, offset } = dateRange; + const disableForward = + value === 'all' || isAfter(getOffsetDateRange(dateRange, 1).startDate, new Date()); - const handleChange = value => { + const handleChange = (value: string | DateRange) => { setDateRange(value); }; - const handleIncrement = value => { - setDateRange(incrementDateRange(dateRange, value)); + const handleIncrement = (increment: number) => { + setDateRange(getOffsetDateRange(dateRange, increment)); }; return (
- {value !== 'all' && selectedUnit && ( + {value !== 'all' && (
- -
+ {user?.teams?.length && } diff --git a/src/components/common/Avatar.tsx b/src/components/common/Avatar.tsx new file mode 100644 index 00000000..b25b0854 --- /dev/null +++ b/src/components/common/Avatar.tsx @@ -0,0 +1,158 @@ +import md5 from 'md5'; + +const pallette = [ + ['#ff9a9e', '#fad0c4'], + ['#a18cd1', '#fbc2eb'], + ['#fad0c4', '#ffd1ff'], + ['#ffecd2', '#fcb69f'], + ['#ff9a9e', '#fecfef'], + ['#f6d365', '#fda085'], + ['#fbc2eb', '#a6c1ee'], + ['#fdcbf1', '#e6dee9'], + ['#a1c4fd', '#c2e9fb'], + ['#d4fc79', '#96e6a1'], + ['#84fab0', '#8fd3f4'], + ['#cfd9df', '#e2ebf0'], + ['#a6c0fe', '#f68084'], + ['#fccb90', '#d57eeb'], + ['#e0c3fc', '#8ec5fc'], + ['#f093fb', '#f5576c'], + ['#fdfbfb', '#ebedee'], + ['#4facfe', '#00f2fe'], + ['#43e97b', '#38f9d7'], + ['#fa709a', '#fee140'], + ['#30cfd0', '#330867'], + ['#a8edea', '#fed6e3'], + ['#5ee7df', '#b490ca'], + ['#d299c2', '#fef9d7'], + ['#f5f7fa', '#c3cfe2'], + ['#667eea', '#764ba2'], + ['#fdfcfb', '#e2d1c3'], + ['#89f7fe', '#66a6ff'], + ['#fddb92', '#d1fdff'], + ['#9890e3', '#b1f4cf'], + ['#ebc0fd', '#d9ded8'], + ['#96fbc4', '#f9f586'], + ['#2af598', '#009efd'], + ['#cd9cf2', '#f6f3ff'], + ['#6a11cb', '#2575fc'], + ['#37ecba', '#72afd3'], + ['#ebbba7', '#cfc7f8'], + ['#fff1eb', '#ace0f9'], + ['#c471f5', '#fa71cd'], + ['#48c6ef', '#6f86d6'], + ['#feada6', '#f5efef'], + ['#e6e9f0', '#eef1f5'], + ['#accbee', '#e7f0fd'], + ['#e9defa', '#fbfcdb'], + ['#c1dfc4', '#deecdd'], + ['#0ba360', '#3cba92'], + ['#00c6fb', '#005bea'], + ['#74ebd5', '#9face6'], + ['#6a85b6', '#bac8e0'], + ['#a3bded', '#6991c7'], + ['#9795f0', '#fbc8d4'], + ['#a7a6cb', '#8989ba'], + ['#f43b47', '#453a94'], + ['#0250c5', '#d43f8d'], + ['#88d3ce', '#6e45e2'], + ['#d9afd9', '#97d9e1'], + ['#7028e4', '#e5b2ca'], + ['#13547a', '#80d0c7'], + ['#ff0844', '#ffb199'], + ['#93a5cf', '#e4efe9'], + ['#434343', '#000000'], + ['#93a5cf', '#e4efe9'], + ['#92fe9d', '#00c9ff'], + ['#ff758c', '#ff7eb3'], + ['#868f96', '#596164'], + ['#c79081', '#dfa579'], + ['#8baaaa', '#ae8b9c'], + ['#f83600', '#f9d423'], + ['#b721ff', '#21d4fd'], + ['#6e45e2', '#88d3ce'], + ['#d558c8', '#24d292'], + ['#abecd6', '#fbed96'], + ['#5f72bd', '#9b23ea'], + ['#09203f', '#537895'], + ['#ddd6f3', '#faaca8'], + ['#dcb0ed', '#99c99c'], + ['#f3e7e9', '#e3eeff'], + ['#c71d6f', '#d09693'], + ['#96deda', '#50c9c3'], + ['#f77062', '#fe5196'], + ['#a8caba', '#5d4157'], + ['#29323c', '#485563'], + ['#16a085', '#f4d03f'], + ['#ff5858', '#f09819'], + ['#2b5876', '#4e4376'], + ['#00cdac', '#8ddad5'], + ['#4481eb', '#04befe'], + ['#dad4ec', '#f3e7e9'], + ['#874da2', '#c43a30'], + ['#4481eb', '#04befe'], + ['#e8198b', '#c7eafd'], + ['#f794a4', '#fdd6bd'], + ['#64b3f4', '#c2e59c'], + ['#0fd850', '#f9f047'], + ['#ee9ca7', '#ffdde1'], + ['#209cff', '#68e0cf'], + ['#bdc2e8', '#e6dee9'], + ['#e6b980', '#eacda3'], + ['#1e3c72', '#2a5298'], + ['#9be15d', '#00e3ae'], + ['#ed6ea0', '#ec8c69'], + ['#ffc3a0', '#ffafbd'], + ['#cc208e', '#6713d2'], + ['#b3ffab', '#12fff7'], + ['#243949', '#517fa4'], + ['#fc6076', '#ff9a44'], + ['#dfe9f3', '#ffffff'], + ['#00dbde', '#fc00ff'], + ['#f9d423', '#ff4e50'], + ['#50cc7f', '#f5d100'], + ['#0acffe', '#495aff'], + ['#616161', '#9bc5c3'], + ['#df89b5', '#bfd9fe'], + ['#ed6ea0', '#ec8c69'], + ['#d7d2cc', '#304352'], + ['#e14fad', '#f9d423'], + ['#b224ef', '#7579ff'], + ['#c1c161', '#d4d4b1'], + ['#ec77ab', '#7873f5'], + ['#007adf', '#00ecbc'], + ['#20E2D7', '#F9FEA5'], + ['#A8BFFF', '#884D80'], + ['#B6CEE8', '#F578DC'], + ['#FFFEFF', '#D7FFFE'], + ['#E3FDF5', '#FFE6FA'], + ['#7DE2FC', '#B9B6E5'], + ['#CBBACC', '#2580B3'], + ['#B7F8DB', '#50A7C2'], + ['#007adf', '#00ecbc'], +]; + +export function Avatar({ value }: { value: string }) { + const hash = md5(value); + let num = 0; + + for (let i = 0; i < 8; i++) { + num += parseInt(hash.substring(i * 4, i * 4 + 4), 16); + } + + const index = num % pallette.length; + + return ( + + + + + + + + + + ); +} + +export default Avatar; diff --git a/src/components/input/TeamsButton.module.css b/src/components/input/TeamsButton.module.css new file mode 100644 index 00000000..5edee957 --- /dev/null +++ b/src/components/input/TeamsButton.module.css @@ -0,0 +1,17 @@ +.button { + margin-right: 10px; +} + +.menu { + background: var(--base50); + right: -10px; +} + +.heading { + color: var(--base600); + font-size: 10px; + font-weight: 700; + padding: 8px 16px; + text-transform: uppercase; + border-bottom: 1px solid var(--base300); +} diff --git a/src/components/input/TeamsButton.tsx b/src/components/input/TeamsButton.tsx new file mode 100644 index 00000000..4cd5c50c --- /dev/null +++ b/src/components/input/TeamsButton.tsx @@ -0,0 +1,51 @@ +import { Key } from 'react'; +import { Text, Icon, Button, Popup, Menu, Item, PopupTrigger, Flexbox } from 'react-basics'; +import Icons from 'components/icons'; +import { useLogin, useMessages, useNavigation } from 'components/hooks'; +import Avatar from 'components/common/Avatar'; +import styles from './TeamsButton.module.css'; + +export function TeamsButton({ teamId }: { teamId: string }) { + const { user } = useLogin(); + const { formatMessage, labels } = useMessages(); + const { router } = useNavigation(); + + const handleSelect = (close: () => void, id: Key) => { + if (id !== user.id) { + router.push(`/teams/${id}`); + } else { + router.push('/'); + } + close(); + }; + + return ( + + + + {close => ( + +
{formatMessage(labels.myAccount)}
+ {user.username} +
{formatMessage(labels.team)}
+ {user.teams.map(({ id, name }) => ( + + + + + + {name} + + + ))} +
+ )} +
+
+ ); +} + +export default TeamsButton; diff --git a/src/components/messages.ts b/src/components/messages.ts index 15d2c442..ffa5f0d9 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -201,6 +201,7 @@ export const labels = defineMessages({ defaultMessage: '{x} {x, plural, one {record} other {records}}', }, select: { id: 'label.select', defaultMessage: 'Select' }, + myAccount: { id: 'label.my-account', defaultMessage: 'My account' }, }); export const messages = defineMessages({ diff --git a/src/declaration.d.ts b/src/declaration.d.ts index 2be86264..2f494dc2 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -1,3 +1,4 @@ declare module 'cors'; declare module 'debug'; declare module 'chartjs-adapter-date-fns'; +declare module 'md5'; diff --git a/yarn.lock b/yarn.lock index a49c8003..cfe307cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3226,6 +3226,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + chart.js@^4.2.1: version "4.4.1" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.4.1.tgz#ac5dc0e69a7758909158a96fe80ce43b3bb96a9f" @@ -3488,6 +3493,11 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + css-blank-pseudo@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz#36523b01c12a25d812df343a32c322d2a2324561" @@ -5330,6 +5340,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-builtin-module@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" @@ -6107,6 +6122,15 @@ maxmind@^4.3.6: mmdb-lib "2.1.0" tiny-lru "11.2.5" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" From 099aa7640bbd7461bf2fb7976ea31e6c78bfb901 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 31 Jan 2024 15:09:57 -0800 Subject: [PATCH 048/142] Updated teams button. --- src/app/(main)/NavBar.module.css | 1 + src/components/common/Avatar.tsx | 193 ++++++-------------- src/components/icons.ts | 2 + src/components/input/TeamsButton.module.css | 9 +- src/components/input/TeamsButton.tsx | 26 ++- 5 files changed, 77 insertions(+), 154 deletions(-) diff --git a/src/app/(main)/NavBar.module.css b/src/app/(main)/NavBar.module.css index fd022eca..20db4c62 100644 --- a/src/app/(main)/NavBar.module.css +++ b/src/app/(main)/NavBar.module.css @@ -26,6 +26,7 @@ padding: 0 40px; font-weight: 700; max-height: 60px; + align-items: center; } .links a, diff --git a/src/components/common/Avatar.tsx b/src/components/common/Avatar.tsx index b25b0854..b947704b 100644 --- a/src/components/common/Avatar.tsx +++ b/src/components/common/Avatar.tsx @@ -1,153 +1,66 @@ import md5 from 'md5'; +import { colord, extend } from 'colord'; +import harmoniesPlugin from 'colord/plugins/harmonies'; +import mixPlugin from 'colord/plugins/mix'; -const pallette = [ - ['#ff9a9e', '#fad0c4'], - ['#a18cd1', '#fbc2eb'], - ['#fad0c4', '#ffd1ff'], - ['#ffecd2', '#fcb69f'], - ['#ff9a9e', '#fecfef'], - ['#f6d365', '#fda085'], - ['#fbc2eb', '#a6c1ee'], - ['#fdcbf1', '#e6dee9'], - ['#a1c4fd', '#c2e9fb'], - ['#d4fc79', '#96e6a1'], - ['#84fab0', '#8fd3f4'], - ['#cfd9df', '#e2ebf0'], - ['#a6c0fe', '#f68084'], - ['#fccb90', '#d57eeb'], - ['#e0c3fc', '#8ec5fc'], - ['#f093fb', '#f5576c'], - ['#fdfbfb', '#ebedee'], - ['#4facfe', '#00f2fe'], - ['#43e97b', '#38f9d7'], - ['#fa709a', '#fee140'], - ['#30cfd0', '#330867'], - ['#a8edea', '#fed6e3'], - ['#5ee7df', '#b490ca'], - ['#d299c2', '#fef9d7'], - ['#f5f7fa', '#c3cfe2'], - ['#667eea', '#764ba2'], - ['#fdfcfb', '#e2d1c3'], - ['#89f7fe', '#66a6ff'], - ['#fddb92', '#d1fdff'], - ['#9890e3', '#b1f4cf'], - ['#ebc0fd', '#d9ded8'], - ['#96fbc4', '#f9f586'], - ['#2af598', '#009efd'], - ['#cd9cf2', '#f6f3ff'], - ['#6a11cb', '#2575fc'], - ['#37ecba', '#72afd3'], - ['#ebbba7', '#cfc7f8'], - ['#fff1eb', '#ace0f9'], - ['#c471f5', '#fa71cd'], - ['#48c6ef', '#6f86d6'], - ['#feada6', '#f5efef'], - ['#e6e9f0', '#eef1f5'], - ['#accbee', '#e7f0fd'], - ['#e9defa', '#fbfcdb'], - ['#c1dfc4', '#deecdd'], - ['#0ba360', '#3cba92'], - ['#00c6fb', '#005bea'], - ['#74ebd5', '#9face6'], - ['#6a85b6', '#bac8e0'], - ['#a3bded', '#6991c7'], - ['#9795f0', '#fbc8d4'], - ['#a7a6cb', '#8989ba'], - ['#f43b47', '#453a94'], - ['#0250c5', '#d43f8d'], - ['#88d3ce', '#6e45e2'], - ['#d9afd9', '#97d9e1'], - ['#7028e4', '#e5b2ca'], - ['#13547a', '#80d0c7'], - ['#ff0844', '#ffb199'], - ['#93a5cf', '#e4efe9'], - ['#434343', '#000000'], - ['#93a5cf', '#e4efe9'], - ['#92fe9d', '#00c9ff'], - ['#ff758c', '#ff7eb3'], - ['#868f96', '#596164'], - ['#c79081', '#dfa579'], - ['#8baaaa', '#ae8b9c'], - ['#f83600', '#f9d423'], - ['#b721ff', '#21d4fd'], - ['#6e45e2', '#88d3ce'], - ['#d558c8', '#24d292'], - ['#abecd6', '#fbed96'], - ['#5f72bd', '#9b23ea'], - ['#09203f', '#537895'], - ['#ddd6f3', '#faaca8'], - ['#dcb0ed', '#99c99c'], - ['#f3e7e9', '#e3eeff'], - ['#c71d6f', '#d09693'], - ['#96deda', '#50c9c3'], - ['#f77062', '#fe5196'], - ['#a8caba', '#5d4157'], - ['#29323c', '#485563'], - ['#16a085', '#f4d03f'], - ['#ff5858', '#f09819'], - ['#2b5876', '#4e4376'], - ['#00cdac', '#8ddad5'], - ['#4481eb', '#04befe'], - ['#dad4ec', '#f3e7e9'], - ['#874da2', '#c43a30'], - ['#4481eb', '#04befe'], - ['#e8198b', '#c7eafd'], - ['#f794a4', '#fdd6bd'], - ['#64b3f4', '#c2e59c'], - ['#0fd850', '#f9f047'], - ['#ee9ca7', '#ffdde1'], - ['#209cff', '#68e0cf'], - ['#bdc2e8', '#e6dee9'], - ['#e6b980', '#eacda3'], - ['#1e3c72', '#2a5298'], - ['#9be15d', '#00e3ae'], - ['#ed6ea0', '#ec8c69'], - ['#ffc3a0', '#ffafbd'], - ['#cc208e', '#6713d2'], - ['#b3ffab', '#12fff7'], - ['#243949', '#517fa4'], - ['#fc6076', '#ff9a44'], - ['#dfe9f3', '#ffffff'], - ['#00dbde', '#fc00ff'], - ['#f9d423', '#ff4e50'], - ['#50cc7f', '#f5d100'], - ['#0acffe', '#495aff'], - ['#616161', '#9bc5c3'], - ['#df89b5', '#bfd9fe'], - ['#ed6ea0', '#ec8c69'], - ['#d7d2cc', '#304352'], - ['#e14fad', '#f9d423'], - ['#b224ef', '#7579ff'], - ['#c1c161', '#d4d4b1'], - ['#ec77ab', '#7873f5'], - ['#007adf', '#00ecbc'], - ['#20E2D7', '#F9FEA5'], - ['#A8BFFF', '#884D80'], - ['#B6CEE8', '#F578DC'], - ['#FFFEFF', '#D7FFFE'], - ['#E3FDF5', '#FFE6FA'], - ['#7DE2FC', '#B9B6E5'], - ['#CBBACC', '#2580B3'], - ['#B7F8DB', '#50A7C2'], - ['#007adf', '#00ecbc'], +extend([harmoniesPlugin, mixPlugin]); + +const harmonies = [ + //'analogous', + //'complementary', + 'double-split-complementary', + //'rectangle', + 'split-complementary', + 'tetradic', + //'triadic', ]; +const color = (value: string, invert: boolean = false) => { + const c = colord(value.startsWith('#') ? value : `#${value}`); + + if (invert && c.isDark()) { + return c.invert(); + } + + return c; +}; + +const remix = (hash: string) => { + const a = hash.substring(0, 6); + const b = hash.substring(6, 12); + const c = hash.substring(12, 18); + const d = hash.substring(18, 24); + const e = hash.substring(24, 30); + const f = hash.substring(30, 32); + + const base = [b, c, d, e] + .reduce((acc, val) => { + return acc.mix(color(val), 0.05); + }, color(a)) + .saturate(0.1) + .toHex(); + + const harmony = pick(parseInt(f, 16), harmonies); + + return color(base, true) + .harmonies(harmony) + .map(c => c.toHex()); +}; + +const pick = (num: number, arr: any[]) => { + return arr[num % arr.length]; +}; + export function Avatar({ value }: { value: string }) { const hash = md5(value); - let num = 0; - - for (let i = 0; i < 8; i++) { - num += parseInt(hash.substring(i * 4, i * 4 + 4), 16); - } - - const index = num % pallette.length; + const colors = remix(hash); return ( - - - + + + diff --git a/src/components/icons.ts b/src/components/icons.ts index 01d7caf5..3cbb09d2 100644 --- a/src/components/icons.ts +++ b/src/components/icons.ts @@ -4,6 +4,7 @@ import Bars from 'assets/bars.svg'; import BarChart from 'assets/bar-chart.svg'; import Bolt from 'assets/bolt.svg'; import Calendar from 'assets/calendar.svg'; +import Change from 'assets/change.svg'; import Clock from 'assets/clock.svg'; import Dashboard from 'assets/dashboard.svg'; import Eye from 'assets/eye.svg'; @@ -29,6 +30,7 @@ const icons = { BarChart, Bolt, Calendar, + Change, Clock, Dashboard, Eye, diff --git a/src/components/input/TeamsButton.module.css b/src/components/input/TeamsButton.module.css index 5edee957..46583fbc 100644 --- a/src/components/input/TeamsButton.module.css +++ b/src/components/input/TeamsButton.module.css @@ -1,10 +1,5 @@ -.button { - margin-right: 10px; -} - .menu { background: var(--base50); - right: -10px; } .heading { @@ -15,3 +10,7 @@ text-transform: uppercase; border-bottom: 1px solid var(--base300); } + +.selected { + font-weight: bold; +} diff --git a/src/components/input/TeamsButton.tsx b/src/components/input/TeamsButton.tsx index 4cd5c50c..41235a80 100644 --- a/src/components/input/TeamsButton.tsx +++ b/src/components/input/TeamsButton.tsx @@ -2,13 +2,14 @@ import { Key } from 'react'; import { Text, Icon, Button, Popup, Menu, Item, PopupTrigger, Flexbox } from 'react-basics'; import Icons from 'components/icons'; import { useLogin, useMessages, useNavigation } from 'components/hooks'; -import Avatar from 'components/common/Avatar'; import styles from './TeamsButton.module.css'; +import classNames from 'classnames'; export function TeamsButton({ teamId }: { teamId: string }) { const { user } = useLogin(); const { formatMessage, labels } = useMessages(); const { router } = useNavigation(); + const team = user?.teams?.find(({ id }) => id === teamId); const handleSelect = (close: () => void, id: Key) => { if (id !== user.id) { @@ -21,21 +22,28 @@ export function TeamsButton({ teamId }: { teamId: string }) { return ( -
{formatMessage(labels.myAccount)}
- {user.username} + + + + + + {user.username} + +
{formatMessage(labels.team)}
- {user.teams.map(({ id, name }) => ( - + {user?.teams?.map(({ id, name }) => ( + - - + + {name} From 53a991176bb5e775269501a44f0298bafe3c6ef2 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 31 Jan 2024 15:29:01 -0800 Subject: [PATCH 049/142] Changed icon for view actions. --- src/app/(main)/settings/teams/TeamsTable.tsx | 7 ++++--- src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx | 2 +- .../(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx | 5 +++-- src/app/(main)/settings/websites/WebsiteSettings.tsx | 2 +- src/app/(main)/settings/websites/WebsitesTable.tsx | 2 +- src/assets/bar-chart.svg | 2 +- src/assets/change.svg | 1 + src/assets/magnet.svg | 2 +- src/components/messages.ts | 1 + 9 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 src/assets/change.svg diff --git a/src/app/(main)/settings/teams/TeamsTable.tsx b/src/app/(main)/settings/teams/TeamsTable.tsx index 82ba054d..56bf0f81 100644 --- a/src/app/(main)/settings/teams/TeamsTable.tsx +++ b/src/app/(main)/settings/teams/TeamsTable.tsx @@ -1,7 +1,8 @@ 'use client'; -import { Button, GridColumn, GridTable, Icon, Icons, Text, useBreakpoint } from 'react-basics'; +import { Button, GridColumn, GridTable, Icon, Text, useBreakpoint } from 'react-basics'; import Link from 'next/link'; import { useMessages, useLogin } from 'components/hooks'; +import Icons from 'components/icons'; import { ROLES } from 'lib/constants'; export function TeamsTable({ data = [] }: { data: any[] }) { @@ -42,9 +43,9 @@ export function TeamsTable({ data = [] }: { data: any[] }) { diff --git a/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx b/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx index f0a16604..d26ddc95 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamSettings.tsx @@ -32,7 +32,7 @@ export function TeamSettings({ teamId }: { teamId: string }) { }> - + {formatMessage(labels.view)} diff --git a/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx index 2fb691a2..1a819646 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx @@ -1,6 +1,7 @@ import Link from 'next/link'; -import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics'; +import { Button, GridColumn, GridTable, Icon, Text } from 'react-basics'; import { useMessages } from 'components/hooks'; +import Icons from 'components/icons'; export function TeamWebsitesTable({ data = [], @@ -21,7 +22,7 @@ export function TeamWebsitesTable({ diff --git a/src/app/(main)/settings/websites/WebsiteSettings.tsx b/src/app/(main)/settings/websites/WebsiteSettings.tsx index bceeff01..f1e8f004 100644 --- a/src/app/(main)/settings/websites/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/WebsiteSettings.tsx @@ -30,7 +30,7 @@ export function WebsiteSettings({ websiteId, openExternal = false }) { diff --git a/src/app/(main)/settings/websites/WebsitesTable.tsx b/src/app/(main)/settings/websites/WebsitesTable.tsx index 159d0b5e..a1f0c475 100644 --- a/src/app/(main)/settings/websites/WebsitesTable.tsx +++ b/src/app/(main)/settings/websites/WebsitesTable.tsx @@ -50,7 +50,7 @@ export function WebsitesTable({ diff --git a/src/assets/bar-chart.svg b/src/assets/bar-chart.svg index 25a182a3..ae8b8708 100644 --- a/src/assets/bar-chart.svg +++ b/src/assets/bar-chart.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/change.svg b/src/assets/change.svg new file mode 100644 index 00000000..1b27e85f --- /dev/null +++ b/src/assets/change.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/magnet.svg b/src/assets/magnet.svg index 3c64c3ee..aa778237 100644 --- a/src/assets/magnet.svg +++ b/src/assets/magnet.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/messages.ts b/src/components/messages.ts index ffa5f0d9..7bf9a1f7 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -202,6 +202,7 @@ export const labels = defineMessages({ }, select: { id: 'label.select', defaultMessage: 'Select' }, myAccount: { id: 'label.my-account', defaultMessage: 'My account' }, + switch: { id: 'label.switch', defaultMessage: 'Switch' }, }); export const messages = defineMessages({ From 442919839703b131967374de8292dc8cd9f44c41 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 31 Jan 2024 22:08:48 -0800 Subject: [PATCH 050/142] Renamed id routes for API. --- src/app/(main)/reports/ReportsTable.tsx | 5 ++-- .../teams/[teamId]/TeamWebsitesTable.tsx | 2 +- .../teams/[teamId]/reports/TeamReports.tsx | 5 ++-- src/components/hooks/{index.js => index.ts} | 0 .../hooks/queries/useWebsiteMetrics.ts | 4 ++- src/components/input/DateFilter.tsx | 5 ++-- src/components/metrics/MetricsTable.tsx | 20 +++++++------- src/lib/query.ts | 2 +- src/pages/api/admin/users.ts | 4 +-- src/pages/api/event-data/stats.ts | 2 +- src/pages/api/me/password.ts | 12 +++------ src/pages/api/me/teams.ts | 15 +++-------- src/pages/api/me/websites.ts | 15 +++-------- .../api/realtime/{[id].ts => [websiteId].ts} | 6 ++--- .../api/reports/{[id].ts => [reportId].ts} | 10 +++---- src/pages/api/reports/index.ts | 17 +++++++----- src/pages/api/share/{[id].ts => [shareId].ts} | 8 +++--- .../api/teams/{[id] => [teamId]}/index.ts | 8 +++--- .../{[id] => [teamId]}/users/[userId].ts | 6 ++--- .../teams/{[id] => [teamId]}/users/index.ts | 6 ++--- .../{[id] => [teamId]}/websites/index.ts | 6 ++--- src/pages/api/teams/join.ts | 1 + .../api/users/{[id] => [userId]}/index.ts | 27 ++++++++++--------- .../api/users/{[id] => [userId]}/teams.ts | 0 .../api/users/{[id] => [userId]}/usage.ts | 0 .../api/users/{[id] => [userId]}/websites.ts | 17 +++--------- .../websites/{[id] => [websiteId]}/active.ts | 10 +++---- .../{[id] => [websiteId]}/daterange.ts | 6 ++--- .../websites/{[id] => [websiteId]}/events.ts | 6 ++--- .../websites/{[id] => [websiteId]}/index.ts | 8 +++--- .../websites/{[id] => [websiteId]}/metrics.ts | 6 ++--- .../{[id] => [websiteId]}/pageviews.ts | 19 +++---------- .../websites/{[id] => [websiteId]}/reports.ts | 6 ++--- .../websites/{[id] => [websiteId]}/reset.ts | 6 ++--- .../websites/{[id] => [websiteId]}/stats.ts | 8 +++--- .../websites/{[id] => [websiteId]}/values.ts | 6 ++--- src/pages/api/websites/index.ts | 8 +++--- src/queries/admin/report.ts | 2 +- src/queries/admin/teamUser.ts | 11 ++++++++ src/queries/admin/user.ts | 9 +++---- src/queries/admin/website.ts | 8 +++--- src/queries/analytics/events/saveEvent.ts | 2 +- 42 files changed, 154 insertions(+), 170 deletions(-) rename src/components/hooks/{index.js => index.ts} (100%) rename src/pages/api/realtime/{[id].ts => [websiteId].ts} (91%) rename src/pages/api/reports/{[id].ts => [reportId].ts} (92%) rename src/pages/api/share/{[id].ts => [shareId].ts} (89%) rename src/pages/api/teams/{[id] => [teamId]}/index.ts (92%) rename src/pages/api/teams/{[id] => [teamId]}/users/[userId].ts (94%) rename src/pages/api/teams/{[id] => [teamId]}/users/index.ts (95%) rename src/pages/api/teams/{[id] => [teamId]}/websites/index.ts (94%) rename src/pages/api/users/{[id] => [userId]}/index.ts (80%) rename src/pages/api/users/{[id] => [userId]}/teams.ts (100%) rename src/pages/api/users/{[id] => [userId]}/usage.ts (100%) rename src/pages/api/users/{[id] => [userId]}/websites.ts (67%) rename src/pages/api/websites/{[id] => [websiteId]}/active.ts (77%) rename src/pages/api/websites/{[id] => [websiteId]}/daterange.ts (90%) rename src/pages/api/websites/{[id] => [websiteId]}/events.ts (92%) rename src/pages/api/websites/{[id] => [websiteId]}/index.ts (93%) rename src/pages/api/websites/{[id] => [websiteId]}/metrics.ts (97%) rename src/pages/api/websites/{[id] => [websiteId]}/pageviews.ts (90%) rename src/pages/api/websites/{[id] => [websiteId]}/reports.ts (91%) rename src/pages/api/websites/{[id] => [websiteId]}/reset.ts (89%) rename src/pages/api/websites/{[id] => [websiteId]}/stats.ts (95%) rename src/pages/api/websites/{[id] => [websiteId]}/values.ts (93%) diff --git a/src/app/(main)/reports/ReportsTable.tsx b/src/app/(main)/reports/ReportsTable.tsx index d8283271..09f8b3fc 100644 --- a/src/app/(main)/reports/ReportsTable.tsx +++ b/src/app/(main)/reports/ReportsTable.tsx @@ -1,6 +1,6 @@ import { GridColumn, GridTable, Icon, Icons, Text, useBreakpoint } from 'react-basics'; import LinkButton from 'components/common/LinkButton'; -import { useMessages, useLogin } from 'components/hooks'; +import { useMessages, useLogin, useNavigation } from 'components/hooks'; import { REPORT_TYPES } from 'lib/constants'; import ReportDeleteButton from './ReportDeleteButton'; @@ -8,6 +8,7 @@ export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomai const { formatMessage, labels } = useMessages(); const { user } = useLogin(); const breakpoint = useBreakpoint(); + const { renderTeamUrl } = useNavigation(); return ( @@ -33,7 +34,7 @@ export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomai {(user.id === userId || user.id === website?.userId) && ( )} - + diff --git a/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx index 1a819646..2fe74b65 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx @@ -17,7 +17,7 @@ export function TeamWebsitesTable({ {row => { - const { id: websiteId } = row; + const { websiteId } = row; return ( - - - - - ); -} - -export default TeamReports; diff --git a/src/app/(main)/teams/[teamId]/reports/[reportId]/page.tsx b/src/app/(main)/teams/[teamId]/reports/[reportId]/page.tsx new file mode 100644 index 00000000..0f51aa88 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/[reportId]/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/reports/[reportId]/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/reports/create/page.tsx b/src/app/(main)/teams/[teamId]/reports/create/page.tsx index 77127dfb..c1e77757 100644 --- a/src/app/(main)/teams/[teamId]/reports/create/page.tsx +++ b/src/app/(main)/teams/[teamId]/reports/create/page.tsx @@ -1,10 +1,3 @@ -import { Metadata } from 'next'; -import ReportTemplates from 'app/(main)/reports/create/ReportTemplates'; +import Page from 'app/(main)/reports/create/page'; -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Create Report | umami', -}; +export default Page; diff --git a/src/app/(main)/teams/[teamId]/reports/event-data/page.tsx b/src/app/(main)/teams/[teamId]/reports/event-data/page.tsx new file mode 100644 index 00000000..77a6c44d --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/event-data/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/reports/event-data/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/reports/funnel/page.tsx b/src/app/(main)/teams/[teamId]/reports/funnel/page.tsx new file mode 100644 index 00000000..be91966c --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/funnel/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/reports/funnel/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/reports/insights/page.tsx b/src/app/(main)/teams/[teamId]/reports/insights/page.tsx new file mode 100644 index 00000000..f8a91c65 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/insights/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/reports/insights/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/reports/page.tsx b/src/app/(main)/teams/[teamId]/reports/page.tsx index ad2ea4dd..6eedabb4 100644 --- a/src/app/(main)/teams/[teamId]/reports/page.tsx +++ b/src/app/(main)/teams/[teamId]/reports/page.tsx @@ -1,15 +1,3 @@ -import { Metadata } from 'next'; -import ReportsHeader from 'app/(main)/reports/ReportsHeader'; -import ReportsDataTable from 'app/(main)/reports/ReportsDataTable'; +import Page from 'app/(main)/reports/page'; -export default function ({ params: { teamId } }) { - return ( - <> - - - - ); -} -export const metadata: Metadata = { - title: 'Reports | umami', -}; +export default Page; diff --git a/src/app/(main)/teams/[teamId]/reports/retention/page.tsx b/src/app/(main)/teams/[teamId]/reports/retention/page.tsx new file mode 100644 index 00000000..62f8e5bf --- /dev/null +++ b/src/app/(main)/teams/[teamId]/reports/retention/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/reports/retention/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/settings/layout.tsx b/src/app/(main)/teams/[teamId]/settings/layout.tsx new file mode 100644 index 00000000..f3b1b94b --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/layout.tsx @@ -0,0 +1,3 @@ +import Layout from 'app/(main)/settings/layout'; + +export default Layout; diff --git a/src/app/(main)/teams/[teamId]/settings/members/Members.tsx b/src/app/(main)/teams/[teamId]/settings/members/Members.tsx new file mode 100644 index 00000000..28639981 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/members/Members.tsx @@ -0,0 +1,15 @@ +'use client'; +import TeamMembers from 'app/(main)/settings/teams/[teamId]/TeamMembers'; +import PageHeader from 'components/layout/PageHeader'; +import { useMessages } from 'components/hooks'; + +export default function ({ teamId }: { teamId: string }) { + const { formatMessage, labels } = useMessages(); + + return ( + <> + + + + ); +} diff --git a/src/app/(main)/teams/[teamId]/settings/members/page.tsx b/src/app/(main)/teams/[teamId]/settings/members/page.tsx new file mode 100644 index 00000000..04f89399 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/members/page.tsx @@ -0,0 +1,5 @@ +import Members from './Members'; + +export default function ({ params: { teamId } }) { + return ; +} diff --git a/src/app/(main)/teams/[teamId]/settings/team/Team.tsx b/src/app/(main)/teams/[teamId]/settings/team/Team.tsx new file mode 100644 index 00000000..40a57ce7 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/team/Team.tsx @@ -0,0 +1,26 @@ +'use client'; +import TeamEditForm from 'app/(main)/settings/teams/[teamId]/TeamEditForm'; +import { useLogin, useMessages, useTeam } from 'components/hooks'; +import { Loading } from 'react-basics'; +import PageHeader from 'components/layout/PageHeader'; +import { ROLES } from 'lib/constants'; + +export default function Team({ teamId }: { teamId: string }) { + const { user } = useLogin(); + const { formatMessage, labels } = useMessages(); + const { data: team, isLoading } = useTeam(teamId); + const allowEdit = !!team?.teamUser?.find( + ({ userId, role }) => role === ROLES.teamOwner && userId === user.id, + ); + + if (isLoading) { + return ; + } + + return ( + <> + + + + ); +} diff --git a/src/app/(main)/teams/[teamId]/settings/team/page.tsx b/src/app/(main)/teams/[teamId]/settings/team/page.tsx new file mode 100644 index 00000000..19edd98c --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/team/page.tsx @@ -0,0 +1,5 @@ +import Team from './Team'; + +export default function ({ params: { teamId } }) { + return ; +} diff --git a/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx b/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx new file mode 100644 index 00000000..ad1a97dd --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/settings/websites/[websiteId]/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/settings/websites/page.tsx b/src/app/(main)/teams/[teamId]/settings/websites/page.tsx new file mode 100644 index 00000000..66290215 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/settings/websites/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/settings/websites/page'; + +export default Page; diff --git a/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx b/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx index 1684e740..224ff4d5 100644 --- a/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx +++ b/src/app/(main)/teams/[teamId]/websites/[websiteId]/page.tsx @@ -1,5 +1,3 @@ -import WebsiteDetails from 'app/(main)/websites/[websiteId]/WebsiteDetails'; +import Page from 'app/(main)/websites/[websiteId]/page'; -export default function TeamWebsitePage({ params: { websiteId } }) { - return ; -} +export default Page; diff --git a/src/app/(main)/teams/[teamId]/websites/page.tsx b/src/app/(main)/teams/[teamId]/websites/page.tsx index 1218c620..553c852a 100644 --- a/src/app/(main)/teams/[teamId]/websites/page.tsx +++ b/src/app/(main)/teams/[teamId]/websites/page.tsx @@ -1,11 +1,3 @@ -import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable'; -import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader'; +import Page from 'app/(main)/websites/page'; -export default function TeamWebsitesPage({ params: { teamId } }: { params: { teamId: string } }) { - return ( - <> - - - - ); -} +export default Page; diff --git a/src/app/(main)/websites/WebsitesBrowse.tsx b/src/app/(main)/websites/WebsitesBrowse.tsx index 30e22618..88fa9e5e 100644 --- a/src/app/(main)/websites/WebsitesBrowse.tsx +++ b/src/app/(main)/websites/WebsitesBrowse.tsx @@ -2,11 +2,11 @@ import WebsitesDataTable from '../settings/websites/WebsitesDataTable'; import { useLogin } from 'components/hooks'; -export function WebsitesBrowse() { +export function WebsitesBrowse({ teamId, userId }: { teamId: string; userId: string }) { const { user } = useLogin(); const allowEdit = !process.env.cloudMode; - return ; + return ; } export default WebsitesBrowse; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index eba155c1..c4df6e71 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -5,7 +5,7 @@ import { getDateArray } from 'lib/date'; export function WebsiteChart({ websiteId }: { websiteId: string }) { const [dateRange] = useDateRange(websiteId); - const { startDate, endDate, unit, modified } = dateRange; + const { startDate, endDate, unit } = dateRange; const [timezone] = useTimezone(); const { query: { url, referrer, os, browser, device, country, region, city, title }, @@ -15,7 +15,7 @@ export function WebsiteChart({ websiteId }: { websiteId: string }) { const { data, isLoading } = useQuery({ queryKey: [ 'websites:pageviews', - { websiteId, modified, url, referrer, os, browser, device, country, region, city, title }, + { websiteId, url, referrer, os, browser, device, country, region, city, title }, ], queryFn: () => get(`/websites/${websiteId}/pageviews`, { diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index e40dd11b..3c5c4e9a 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -19,7 +19,7 @@ export function WebsiteMetricsBar({ const { formatMessage, labels } = useMessages(); const { get, useQuery } = useApi(); const [dateRange] = useDateRange(websiteId); - const { startDate, endDate, modified } = dateRange; + const { startDate, endDate } = dateRange; const { ref, isSticky } = useSticky({ enabled: sticky }); const { query: { url, referrer, title, os, browser, device, country, region, city }, @@ -28,7 +28,7 @@ export function WebsiteMetricsBar({ const { data, error, isLoading, isFetched } = useQuery({ queryKey: [ 'websites:stats', - { websiteId, modified, url, referrer, title, os, browser, device, country, region, city }, + { websiteId, url, referrer, title, os, browser, device, country, region, city }, ], queryFn: () => get(`/websites/${websiteId}/stats`, { diff --git a/src/app/(main)/websites/page.tsx b/src/app/(main)/websites/page.tsx index a1542510..a1cc5216 100644 --- a/src/app/(main)/websites/page.tsx +++ b/src/app/(main)/websites/page.tsx @@ -2,15 +2,15 @@ import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader'; import WebsitesBrowse from './WebsitesBrowse'; import { Metadata } from 'next'; -export default function WebsitesPage() { +export default function WebsitesPage({ params: { teamId, userId } }) { return ( <> - + ); } export const metadata: Metadata = { - title: 'Websites | umami', + title: 'Websites | Umami', }; diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 2ac3f724..aa2765c9 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -21,5 +21,5 @@ export default async function LoginPage() { } export const metadata: Metadata = { - title: 'Login | umami', + title: 'Login | Umami', }; diff --git a/src/app/logout/page.tsx b/src/app/logout/page.tsx index 89a3bce9..11ee9b67 100644 --- a/src/app/logout/page.tsx +++ b/src/app/logout/page.tsx @@ -6,5 +6,5 @@ export default function () { } export const metadata: Metadata = { - title: 'Logout | umami', + title: 'Logout | Umami', }; diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index 9e9993c3..23ba94ff 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -25,5 +25,6 @@ export * from './useLocale'; export * from './useMessages'; export * from './useNavigation'; export * from './useSticky'; +export * from './useTeamContext'; export * from './useTheme'; export * from './useTimezone'; diff --git a/src/components/hooks/queries/useLogin.ts b/src/components/hooks/queries/useLogin.ts index af9eba85..c17687b0 100644 --- a/src/components/hooks/queries/useLogin.ts +++ b/src/components/hooks/queries/useLogin.ts @@ -1,9 +1,13 @@ import useStore, { setUser } from 'store/app'; import useApi from './useApi'; +import { UseQueryResult } from '@tanstack/react-query'; const selector = (state: { user: any }) => state.user; -export function useLogin() { +export function useLogin(): { + user: any; + setUser: (data: any) => void; +} & UseQueryResult { const { get, useQuery } = useApi(); const user = useStore(selector); @@ -19,7 +23,7 @@ export function useLogin() { enabled: !user, }); - return { user, ...query }; + return { user, setUser, ...query }; } export default useLogin; diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index 575ef236..5a091123 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -2,14 +2,18 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import useCache from 'store/cache'; -export function useWebsites({ userId, teamId }: { userId?: string; teamId?: string }) { +export function useWebsites( + { userId, teamId }: { userId?: string; teamId?: string }, + params?: { [key: string]: string | number }, +) { const { get } = useApi(); const modified = useCache((state: any) => state?.websites); return useFilterQuery({ - queryKey: ['websites', { userId, teamId, modified }], - queryFn: (params: any) => { + queryKey: ['websites', { userId, teamId, modified, ...params }], + queryFn: (data: any) => { return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId}/websites`, { + ...data, ...params, }); }, diff --git a/src/components/hooks/useNavigation.ts b/src/components/hooks/useNavigation.ts index bf839177..0ff7155a 100644 --- a/src/components/hooks/useNavigation.ts +++ b/src/components/hooks/useNavigation.ts @@ -7,13 +7,10 @@ export function useNavigation(): { query: { [key: string]: string }; router: any; renderUrl: (params: any, reset?: boolean) => string; - renderTeamUrl: (url: string) => string; - teamId?: string; } { const router = useRouter(); const pathname = usePathname(); const params = useSearchParams(); - const [, teamId] = pathname.match(/^\/teams\/([a-f0-9-]+)/) || []; const query = useMemo(() => { const obj = {}; @@ -29,11 +26,7 @@ export function useNavigation(): { return reset ? pathname : buildUrl(pathname, { ...query, ...params }); } - function renderTeamUrl(url: string) { - return teamId ? `/teams/${teamId}${url}` : url; - } - - return { pathname, query, router, renderUrl, renderTeamUrl, teamId }; + return { pathname, query, router, renderUrl }; } export default useNavigation; diff --git a/src/components/hooks/useTeamContext.ts b/src/components/hooks/useTeamContext.ts new file mode 100644 index 00000000..0c0c0a7d --- /dev/null +++ b/src/components/hooks/useTeamContext.ts @@ -0,0 +1,17 @@ +import { usePathname } from 'next/navigation'; + +export function useTeamContext(): { + teamId?: string; + renderTeamUrl: (url: string) => string; +} { + const pathname = usePathname(); + const [, teamId] = pathname.match(/^\/teams\/([a-f0-9-]+)/) || []; + + function renderTeamUrl(url: string) { + return teamId ? `/teams/${teamId}${url}` : url; + } + + return { teamId, renderTeamUrl }; +} + +export default useTeamContext; diff --git a/src/components/input/TeamsButton.module.css b/src/components/input/TeamsButton.module.css index 46583fbc..7b4d8c7b 100644 --- a/src/components/input/TeamsButton.module.css +++ b/src/components/input/TeamsButton.module.css @@ -1,3 +1,7 @@ +.button { + font-weight: 700; +} + .menu { background: var(--base50); } diff --git a/src/components/input/TeamsButton.tsx b/src/components/input/TeamsButton.tsx index 41235a80..a91cdb2f 100644 --- a/src/components/input/TeamsButton.tsx +++ b/src/components/input/TeamsButton.tsx @@ -1,9 +1,9 @@ import { Key } from 'react'; import { Text, Icon, Button, Popup, Menu, Item, PopupTrigger, Flexbox } from 'react-basics'; +import classNames from 'classnames'; import Icons from 'components/icons'; import { useLogin, useMessages, useNavigation } from 'components/hooks'; import styles from './TeamsButton.module.css'; -import classNames from 'classnames'; export function TeamsButton({ teamId }: { teamId: string }) { const { user } = useLogin(); diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index 71f96100..1ea8d392 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -1,30 +1,27 @@ import { useState, Key } from 'react'; import { Dropdown, Item } from 'react-basics'; -import { useApi } from 'components/hooks'; -import { useMessages } from 'components/hooks'; -import styles from './WebsiteSelect.module.css'; +import { useWebsite, useWebsites, useMessages } from 'components/hooks'; import Empty from 'components/common/Empty'; +import styles from './WebsiteSelect.module.css'; export function WebsiteSelect({ websiteId, + teamId, + userId, onSelect, }: { websiteId?: string; + teamId?: string; + userId?: string; onSelect?: (key: any) => void; }) { + const { formatMessage, labels, messages } = useMessages(); const [query, setQuery] = useState(''); const [selectedId, setSelectedId] = useState(websiteId); - const { formatMessage, labels, messages } = useMessages(); - const { get, useQuery } = useApi(); - const { data: websites, isLoading } = useQuery({ - queryKey: ['websites:me', { query }], - queryFn: () => get('/me/websites', { query, pageSize: 5 }), - }); - const { data: website } = useQuery({ - queryKey: ['websites', { selectedId }], - queryFn: () => get(`/websites/${selectedId}`), - enabled: !!selectedId, - }); + + const { data: website } = useWebsite(selectedId as string); + + const queryResult = useWebsites({ teamId, userId }, { query, pageSize: 5 }); const renderValue = () => { return website?.name; @@ -46,7 +43,7 @@ export function WebsiteSelect({ return ( {({ id, name }) => {name}} diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index ea2d849e..ad8e45a9 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -176,12 +176,13 @@ async function rawQuery(sql: string, data: object): Promise { } async function pagedQuery(model: string, criteria: T, filters: SearchFilter) { - const { page = 1, pageSize = DEFAULT_PAGE_SIZE, orderBy, sortDescending = false } = filters || {}; + const { page = 1, pageSize, orderBy, sortDescending = false } = filters || {}; + const size = +pageSize || DEFAULT_PAGE_SIZE; const data = await prisma.client[model].findMany({ ...criteria, ...{ - ...(pageSize > 0 && { take: +pageSize, skip: +pageSize * (page - 1) }), + ...(size > 0 && { take: +size, skip: +size * (page - 1) }), ...(orderBy && { orderBy: [ { diff --git a/src/pages/api/teams/[teamId]/users/index.ts b/src/pages/api/teams/[teamId]/users/index.ts index b79df943..53f0dd0a 100644 --- a/src/pages/api/teams/[teamId]/users/index.ts +++ b/src/pages/api/teams/[teamId]/users/index.ts @@ -46,11 +46,24 @@ export default async ( const { query, page, pageSize } = req.query; - const users = await getTeamUsers(teamId, { - query, - page, - pageSize: +pageSize || undefined, - }); + const users = await getTeamUsers( + { + where: { teamId }, + include: { + user: { + select: { + id: true, + username: true, + }, + }, + }, + }, + { + query, + page, + pageSize, + }, + ); return ok(res, users); } diff --git a/src/queries/admin/teamUser.ts b/src/queries/admin/teamUser.ts index e082c94c..34e4a1a5 100644 --- a/src/queries/admin/teamUser.ts +++ b/src/queries/admin/teamUser.ts @@ -1,7 +1,8 @@ -import { TeamUser } from '@prisma/client'; +import { Prisma, TeamUser } from '@prisma/client'; import { uuid } from 'lib/crypto'; import prisma from 'lib/prisma'; import { FilterResult, TeamUserSearchFilter } from 'lib/types'; +import TeamUserFindManyArgs = Prisma.TeamUserFindManyArgs; export async function getTeamUser(teamId: string, userId: string): Promise { return prisma.client.teamUser.findFirst({ @@ -13,23 +14,29 @@ export async function getTeamUser(teamId: string, userId: string): Promise> { + const { query } = filters; + const mode = prisma.getQueryMode(); + + const where: Prisma.TeamUserWhereInput = { + ...criteria.where, + user: { + username: query + ? { + contains: query, + mode, + } + : undefined, + }, + }; + return prisma.pagedQuery( 'teamUser', { - where: { - teamId, - }, - include: { - user: { - select: { - id: true, - username: true, - }, - }, - }, + ...criteria, + where, }, filters, ); diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 984770ae..ab63d255 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -28,37 +28,23 @@ export async function getWebsites( criteria: WebsiteFindManyArgs, filters: WebsiteSearchFilter, ): Promise> { - const { userId, teamId, query } = filters; + const { query } = filters; const mode = prisma.getQueryMode(); const where: Prisma.WebsiteWhereInput = { ...criteria.where, - AND: [ - { - OR: [ - { - ...(userId && { userId }), - ...(teamId && { teamId }), - }, - ], - }, - { - OR: query - ? [ - { - name: { contains: query, mode }, - }, - { - domain: { contains: query, mode }, - }, - ] - : [], - }, - ], + name: { + contains: query ? query : undefined, + mode, + }, + domain: { + contains: query ? query : undefined, + mode, + }, deletedAt: null, }; - return prisma.pagedQuery('website', { where }, filters); + return prisma.pagedQuery('website', { ...criteria, where }, filters); } export async function getAllWebsites(userId: string) { From 400657d59e56071a4268a7ab198ba7c0303d9577 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 2 Feb 2024 21:06:55 -0800 Subject: [PATCH 055/142] Updated profile menu. Fixed dashboard. --- next.config.js | 2 +- src/app/(main)/dashboard/Dashboard.tsx | 33 ++++++------- src/app/(main)/dashboard/DashboardEdit.tsx | 31 +++++++------ src/app/(main)/layout.module.css | 1 - .../reports/[reportId]/BaseParameters.tsx | 10 +--- src/app/(main)/settings/layout.tsx | 2 +- .../(main)/teams/[teamId]/dashboard/page.tsx | 3 ++ src/assets/change.svg | 2 +- src/assets/magnet.svg | 2 +- src/assets/visitor.svg | 2 +- src/components/hooks/queries/useWebsites.ts | 9 ++-- src/components/input/ProfileButton.tsx | 46 +++++++++++-------- 12 files changed, 73 insertions(+), 70 deletions(-) create mode 100644 src/app/(main)/teams/[teamId]/dashboard/page.tsx diff --git a/next.config.js b/next.config.js index d0336b10..f353b1f9 100644 --- a/next.config.js +++ b/next.config.js @@ -75,7 +75,7 @@ const redirects = [ }, { source: '/teams/:id', - destination: '/teams/:id/websites', + destination: '/teams/:id/dashboard', permanent: true, }, { diff --git a/src/app/(main)/dashboard/Dashboard.tsx b/src/app/(main)/dashboard/Dashboard.tsx index 202f88f6..ed976f43 100644 --- a/src/app/(main)/dashboard/Dashboard.tsx +++ b/src/app/(main)/dashboard/Dashboard.tsx @@ -7,39 +7,30 @@ import WebsiteChartList from '../websites/[websiteId]/WebsiteChartList'; import DashboardSettingsButton from 'app/(main)/dashboard/DashboardSettingsButton'; import DashboardEdit from 'app/(main)/dashboard/DashboardEdit'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; -import { useApi } from 'components/hooks'; +import { useMessages, useLocale, useTeamContext, useWebsites } from 'components/hooks'; import useDashboard from 'store/dashboard'; -import { useMessages, useLocale, useLogin, useFilterQuery } from 'components/hooks'; export function Dashboard() { const { formatMessage, labels, messages } = useMessages(); - const { user } = useLogin(); + const { teamId } = useTeamContext(); const { showCharts, editing } = useDashboard(); const { dir } = useLocale(); - const { get } = useApi(); const pageSize = 10; - const { query, params, setParams, result } = useFilterQuery({ - queryKey: ['dashboard:websites'], - queryFn: (params: any) => { - return get(`/users/${user.id}/websites`, { ...params, includeTeams: true, pageSize }); - }, - }); + const { result, query, params, setParams } = useWebsites({}, { pageSize }); + const { page } = params; + const hasData = !!result?.data; const handlePageChange = (page: number) => { setParams({ ...params, page }); }; - const { data, count } = result || {}; - const hasData = !!(data as any)?.length; - const { page } = params; - if (query.isLoading) { return ; } return ( - <> +
{!editing && hasData && } @@ -57,21 +48,25 @@ export function Dashboard() { )} {hasData && ( <> - {editing && } + {editing && } {!editing && ( <> - + )} )} - +
); } diff --git a/src/app/(main)/dashboard/DashboardEdit.tsx b/src/app/(main)/dashboard/DashboardEdit.tsx index fd94c767..d934bf04 100644 --- a/src/app/(main)/dashboard/DashboardEdit.tsx +++ b/src/app/(main)/dashboard/DashboardEdit.tsx @@ -2,31 +2,30 @@ import { useState, useMemo } from 'react'; import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; import classNames from 'classnames'; -import { Button } from 'react-basics'; +import { Button, Loading } from 'react-basics'; import { firstBy } from 'thenby'; import useDashboard, { saveDashboard } from 'store/dashboard'; -import { useMessages } from 'components/hooks'; -import { useApi } from 'components/hooks'; +import { useMessages, useWebsites } from 'components/hooks'; import styles from './DashboardEdit.module.css'; -const dragId = 'dashboard-website-ordering'; +const DRAG_ID = 'dashboard-website-ordering'; -export function DashboardEdit() { +export function DashboardEdit({ teamId }: { teamId: string }) { const settings = useDashboard(); const { websiteOrder } = settings; const { formatMessage, labels } = useMessages(); const [order, setOrder] = useState(websiteOrder || []); - const { get, useQuery } = useApi(); - const { data: result } = useQuery({ - queryKey: ['websites'], - queryFn: () => get('/websites'), - }); - const { data: websites } = result || {}; + const { + result, + query: { isLoading }, + } = useWebsites({ teamId }); + + const websites = result?.data; const ordered = useMemo(() => { if (websites) { return websites - .map(website => ({ ...website, order: order.indexOf(website.id) })) + .map((website: { id: any }) => ({ ...website, order: order.indexOf(website.id) })) .sort(firstBy('order')); } return []; @@ -57,6 +56,10 @@ export function DashboardEdit() { setOrder([]); } + if (isLoading) { + return ; + } + return ( <>
@@ -72,7 +75,7 @@ export function DashboardEdit() {
- + {(provided, snapshot) => (
{ordered.map(({ id, name, domain }, index) => ( - + {(provided, snapshot) => (
{allowWebsiteSelect && ( - + )} )} diff --git a/src/app/(main)/settings/layout.tsx b/src/app/(main)/settings/layout.tsx index f8d0d1f0..72e979b7 100644 --- a/src/app/(main)/settings/layout.tsx +++ b/src/app/(main)/settings/layout.tsx @@ -12,7 +12,7 @@ export default function SettingsLayout({ children }) { const { teamId, renderTeamUrl } = useTeamContext(); const items = [ - { + teamId && { key: 'team', label: formatMessage(labels.team), url: renderTeamUrl('/settings/team'), diff --git a/src/app/(main)/teams/[teamId]/dashboard/page.tsx b/src/app/(main)/teams/[teamId]/dashboard/page.tsx new file mode 100644 index 00000000..bf8f2fed --- /dev/null +++ b/src/app/(main)/teams/[teamId]/dashboard/page.tsx @@ -0,0 +1,3 @@ +import Page from 'app/(main)/dashboard/page'; + +export default Page; diff --git a/src/assets/change.svg b/src/assets/change.svg index 1b27e85f..bf907e68 100644 --- a/src/assets/change.svg +++ b/src/assets/change.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/magnet.svg b/src/assets/magnet.svg index aa778237..67007a01 100644 --- a/src/assets/magnet.svg +++ b/src/assets/magnet.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/visitor.svg b/src/assets/visitor.svg index 591873a5..4aeceafc 100644 --- a/src/assets/visitor.svg +++ b/src/assets/visitor.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index 5a091123..4f2681a0 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -1,5 +1,6 @@ -import useApi from './useApi'; -import useFilterQuery from './useFilterQuery'; +import { useApi } from './useApi'; +import { useFilterQuery } from './useFilterQuery'; +import { useLogin } from './useLogin'; import useCache from 'store/cache'; export function useWebsites( @@ -7,17 +8,17 @@ export function useWebsites( params?: { [key: string]: string | number }, ) { const { get } = useApi(); + const { user } = useLogin(); const modified = useCache((state: any) => state?.websites); return useFilterQuery({ queryKey: ['websites', { userId, teamId, modified, ...params }], queryFn: (data: any) => { - return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId}/websites`, { + return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId || user.id}/websites`, { ...data, ...params, }); }, - enabled: !!(userId || teamId), }); } diff --git a/src/components/input/ProfileButton.tsx b/src/components/input/ProfileButton.tsx index 11d95a7b..ec0deb3b 100644 --- a/src/components/input/ProfileButton.tsx +++ b/src/components/input/ProfileButton.tsx @@ -1,3 +1,4 @@ +import { Key } from 'react'; import { Icon, Button, PopupTrigger, Popup, Menu, Item, Text } from 'react-basics'; import { useRouter } from 'next/navigation'; import Icons from 'components/icons'; @@ -6,6 +7,7 @@ import { useLogin } from 'components/hooks'; import { useLocale } from 'components/hooks'; import { CURRENT_VERSION } from 'lib/constants'; import styles from './ProfileButton.module.css'; +import Avatar from 'components/common/Avatar'; export function ProfileButton() { const { formatMessage, labels } = useMessages(); @@ -14,13 +16,14 @@ export function ProfileButton() { const { dir } = useLocale(); const cloudMode = Boolean(process.env.cloudMode); - const handleSelect = key => { + const handleSelect = (key: Key, close: () => void) => { if (key === 'profile') { router.push('/settings/profile'); } if (key === 'logout') { router.push('/logout'); } + close(); }; return ( @@ -31,26 +34,31 @@ export function ProfileButton() { - - - {user.username} - - - - - - {formatMessage(labels.profile)} - - {!cloudMode && ( - - - + {(close: () => void) => ( + handleSelect(key, close)} className={styles.menu}> + + + - {formatMessage(labels.logout)} + {user.username} - )} -
{`v${CURRENT_VERSION}`}
-
+ + + + + {formatMessage(labels.profile)} + + {!cloudMode && ( + + + + + {formatMessage(labels.logout)} + + )} +
{`v${CURRENT_VERSION}`}
+
+ )}
); From 238e6efee248bc501f61b23b7956acc54a3c2e2a Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 2 Feb 2024 22:20:13 -0800 Subject: [PATCH 056/142] Added "use client" to hooks. --- .eslintrc.json | 1 + .../(main)/reports/[reportId]/FieldAddForm.tsx | 1 + src/components/hooks/queries/useApi.ts | 1 + src/components/hooks/queries/useConfig.ts | 1 + src/components/hooks/queries/useFilterQuery.ts | 1 + src/components/hooks/queries/useLogin.ts | 1 + src/components/hooks/queries/useReport.ts | 1 + src/components/hooks/queries/useReports.ts | 1 + src/components/hooks/queries/useShareToken.ts | 1 + src/components/hooks/queries/useTeam.ts | 1 + src/components/hooks/queries/useTeamMembers.ts | 1 + .../hooks/queries/useTeamWebsites.ts | 1 + src/components/hooks/queries/useUser.ts | 1 + src/components/hooks/queries/useUsers.ts | 1 + src/components/hooks/queries/useWebsite.ts | 1 + .../hooks/queries/useWebsiteEvents.ts | 1 + .../hooks/queries/useWebsiteMetrics.ts | 1 + src/components/hooks/queries/useWebsites.ts | 1 + src/components/hooks/useCountryNames.ts | 1 + src/components/hooks/useDateRange.ts | 1 + src/components/hooks/useDocumentClick.ts | 1 + src/components/hooks/useEscapeKey.ts | 1 + src/components/hooks/useFilters.ts | 1 + src/components/hooks/useForceUpdate.ts | 1 + src/components/hooks/useFormat.ts | 1 + src/components/hooks/useLanguageNames.ts | 1 + src/components/hooks/useLocale.ts | 1 + src/components/hooks/useMessages.ts | 18 ++++++++---------- src/components/hooks/useNavigation.ts | 1 + src/components/hooks/useSticky.ts | 1 + src/components/hooks/useTeamContext.ts | 1 + src/components/hooks/useTheme.ts | 1 + src/components/hooks/useTimezone.ts | 1 + 33 files changed, 40 insertions(+), 10 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 7f3665ff..cabeaf06 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -30,6 +30,7 @@ "rules": { "no-console": "error", "react/display-name": "off", + "react-hooks/exhaustive-deps": "off", "react/react-in-jsx-scope": "off", "react/prop-types": "off", "import/no-anonymous-default-export": "off", diff --git a/src/app/(main)/reports/[reportId]/FieldAddForm.tsx b/src/app/(main)/reports/[reportId]/FieldAddForm.tsx index 9db472d8..ac7bff5b 100644 --- a/src/app/(main)/reports/[reportId]/FieldAddForm.tsx +++ b/src/app/(main)/reports/[reportId]/FieldAddForm.tsx @@ -1,3 +1,4 @@ +'use client'; import { useState } from 'react'; import { createPortal } from 'react-dom'; import { REPORT_PARAMETERS } from 'lib/constants'; diff --git a/src/components/hooks/queries/useApi.ts b/src/components/hooks/queries/useApi.ts index e806d37e..88427bc7 100644 --- a/src/components/hooks/queries/useApi.ts +++ b/src/components/hooks/queries/useApi.ts @@ -1,3 +1,4 @@ +'use client'; import * as reactQuery from '@tanstack/react-query'; import { useApi as nextUseApi } from 'next-basics'; import { getClientAuthToken } from 'lib/client'; diff --git a/src/components/hooks/queries/useConfig.ts b/src/components/hooks/queries/useConfig.ts index 72fe095d..505a93f3 100644 --- a/src/components/hooks/queries/useConfig.ts +++ b/src/components/hooks/queries/useConfig.ts @@ -1,3 +1,4 @@ +'use client'; import { useEffect } from 'react'; import useStore, { setConfig } from 'store/app'; import { useApi } from './useApi'; diff --git a/src/components/hooks/queries/useFilterQuery.ts b/src/components/hooks/queries/useFilterQuery.ts index 7e4c9a86..5d86c724 100644 --- a/src/components/hooks/queries/useFilterQuery.ts +++ b/src/components/hooks/queries/useFilterQuery.ts @@ -1,3 +1,4 @@ +'use client'; import { UseQueryOptions } from '@tanstack/react-query'; import { useState, Dispatch, SetStateAction } from 'react'; import { useApi } from './useApi'; diff --git a/src/components/hooks/queries/useLogin.ts b/src/components/hooks/queries/useLogin.ts index c17687b0..2f777a77 100644 --- a/src/components/hooks/queries/useLogin.ts +++ b/src/components/hooks/queries/useLogin.ts @@ -1,3 +1,4 @@ +'use client'; import useStore, { setUser } from 'store/app'; import useApi from './useApi'; import { UseQueryResult } from '@tanstack/react-query'; diff --git a/src/components/hooks/queries/useReport.ts b/src/components/hooks/queries/useReport.ts index 38061761..332ba755 100644 --- a/src/components/hooks/queries/useReport.ts +++ b/src/components/hooks/queries/useReport.ts @@ -1,3 +1,4 @@ +'use client'; import { produce } from 'immer'; import { useCallback, useEffect, useState } from 'react'; import { useApi } from './useApi'; diff --git a/src/components/hooks/queries/useReports.ts b/src/components/hooks/queries/useReports.ts index 2176411f..99054dfd 100644 --- a/src/components/hooks/queries/useReports.ts +++ b/src/components/hooks/queries/useReports.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import useCache from 'store/cache'; diff --git a/src/components/hooks/queries/useShareToken.ts b/src/components/hooks/queries/useShareToken.ts index 189657be..8197fe66 100644 --- a/src/components/hooks/queries/useShareToken.ts +++ b/src/components/hooks/queries/useShareToken.ts @@ -1,3 +1,4 @@ +'use client'; import useStore, { setShareToken } from 'store/app'; import useApi from './useApi'; diff --git a/src/components/hooks/queries/useTeam.ts b/src/components/hooks/queries/useTeam.ts index e348531c..1a8ccc54 100644 --- a/src/components/hooks/queries/useTeam.ts +++ b/src/components/hooks/queries/useTeam.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; export function useTeam(teamId: string) { diff --git a/src/components/hooks/queries/useTeamMembers.ts b/src/components/hooks/queries/useTeamMembers.ts index 064231d1..ccfd6c9b 100644 --- a/src/components/hooks/queries/useTeamMembers.ts +++ b/src/components/hooks/queries/useTeamMembers.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; diff --git a/src/components/hooks/queries/useTeamWebsites.ts b/src/components/hooks/queries/useTeamWebsites.ts index 19bcdf76..036d715b 100644 --- a/src/components/hooks/queries/useTeamWebsites.ts +++ b/src/components/hooks/queries/useTeamWebsites.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; diff --git a/src/components/hooks/queries/useUser.ts b/src/components/hooks/queries/useUser.ts index 61c22ecd..7ff73dac 100644 --- a/src/components/hooks/queries/useUser.ts +++ b/src/components/hooks/queries/useUser.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; export function useUser(userId: string, options?: { [key: string]: any }) { diff --git a/src/components/hooks/queries/useUsers.ts b/src/components/hooks/queries/useUsers.ts index b1273814..d7bc8074 100644 --- a/src/components/hooks/queries/useUsers.ts +++ b/src/components/hooks/queries/useUsers.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import useCache from 'store/cache'; diff --git a/src/components/hooks/queries/useWebsite.ts b/src/components/hooks/queries/useWebsite.ts index 386607eb..c29a6cd0 100644 --- a/src/components/hooks/queries/useWebsite.ts +++ b/src/components/hooks/queries/useWebsite.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; export function useWebsite(websiteId: string, options?: { [key: string]: any }) { diff --git a/src/components/hooks/queries/useWebsiteEvents.ts b/src/components/hooks/queries/useWebsiteEvents.ts index de18a1f9..613788e2 100644 --- a/src/components/hooks/queries/useWebsiteEvents.ts +++ b/src/components/hooks/queries/useWebsiteEvents.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; import { UseQueryOptions } from '@tanstack/react-query'; diff --git a/src/components/hooks/queries/useWebsiteMetrics.ts b/src/components/hooks/queries/useWebsiteMetrics.ts index 8e7d00db..300e526d 100644 --- a/src/components/hooks/queries/useWebsiteMetrics.ts +++ b/src/components/hooks/queries/useWebsiteMetrics.ts @@ -1,3 +1,4 @@ +'use client'; import useApi from './useApi'; import { UseQueryOptions } from '@tanstack/react-query'; diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index 4f2681a0..ed34193f 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -1,3 +1,4 @@ +'use client'; import { useApi } from './useApi'; import { useFilterQuery } from './useFilterQuery'; import { useLogin } from './useLogin'; diff --git a/src/components/hooks/useCountryNames.ts b/src/components/hooks/useCountryNames.ts index acfada44..47716449 100644 --- a/src/components/hooks/useCountryNames.ts +++ b/src/components/hooks/useCountryNames.ts @@ -1,3 +1,4 @@ +'use client'; import { useState, useEffect } from 'react'; import { httpGet } from 'next-basics'; import enUS from '../../../public/intl/country/en-US.json'; diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts index e022d960..8d7cf57c 100644 --- a/src/components/hooks/useDateRange.ts +++ b/src/components/hooks/useDateRange.ts @@ -1,3 +1,4 @@ +'use client'; import { getMinimumUnit, parseDateRange } from 'lib/date'; import { setItem } from 'next-basics'; import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE } from 'lib/constants'; diff --git a/src/components/hooks/useDocumentClick.ts b/src/components/hooks/useDocumentClick.ts index eefd9366..dce9e106 100644 --- a/src/components/hooks/useDocumentClick.ts +++ b/src/components/hooks/useDocumentClick.ts @@ -1,3 +1,4 @@ +'use client'; import { useEffect } from 'react'; export function useDocumentClick(handler: (event: MouseEvent) => any) { diff --git a/src/components/hooks/useEscapeKey.ts b/src/components/hooks/useEscapeKey.ts index 5c3350e7..567878b0 100644 --- a/src/components/hooks/useEscapeKey.ts +++ b/src/components/hooks/useEscapeKey.ts @@ -1,3 +1,4 @@ +'use client'; import { useEffect, useCallback, KeyboardEvent } from 'react'; export function useEscapeKey(handler: (event: KeyboardEvent) => void) { diff --git a/src/components/hooks/useFilters.ts b/src/components/hooks/useFilters.ts index e1a9a885..51a5d972 100644 --- a/src/components/hooks/useFilters.ts +++ b/src/components/hooks/useFilters.ts @@ -1,3 +1,4 @@ +'use client'; import { useMessages } from './useMessages'; import { OPERATORS } from 'lib/constants'; diff --git a/src/components/hooks/useForceUpdate.ts b/src/components/hooks/useForceUpdate.ts index 35f7fe16..1798cdd8 100644 --- a/src/components/hooks/useForceUpdate.ts +++ b/src/components/hooks/useForceUpdate.ts @@ -1,3 +1,4 @@ +'use client'; import { useCallback, useState } from 'react'; export function useForceUpdate() { diff --git a/src/components/hooks/useFormat.ts b/src/components/hooks/useFormat.ts index 3057e9d8..4d8994fc 100644 --- a/src/components/hooks/useFormat.ts +++ b/src/components/hooks/useFormat.ts @@ -1,3 +1,4 @@ +'use client'; import useMessages from './useMessages'; import { BROWSERS } from 'lib/constants'; import useLocale from './useLocale'; diff --git a/src/components/hooks/useLanguageNames.ts b/src/components/hooks/useLanguageNames.ts index d4bfbf2f..95b1a97f 100644 --- a/src/components/hooks/useLanguageNames.ts +++ b/src/components/hooks/useLanguageNames.ts @@ -1,3 +1,4 @@ +'use client'; import { useState, useEffect } from 'react'; import { httpGet } from 'next-basics'; import enUS from '../../../public/intl/language/en-US.json'; diff --git a/src/components/hooks/useLocale.ts b/src/components/hooks/useLocale.ts index 8facb2bd..356e525b 100644 --- a/src/components/hooks/useLocale.ts +++ b/src/components/hooks/useLocale.ts @@ -1,3 +1,4 @@ +'use client'; import { useEffect } from 'react'; import { httpGet, setItem } from 'next-basics'; import { LOCALE_CONFIG } from 'lib/constants'; diff --git a/src/components/hooks/useMessages.ts b/src/components/hooks/useMessages.ts index 594a3c61..8b82dd57 100644 --- a/src/components/hooks/useMessages.ts +++ b/src/components/hooks/useMessages.ts @@ -1,6 +1,6 @@ -import { useIntl, FormattedMessage, MessageDescriptor, PrimitiveType } from 'react-intl'; +'use client'; +import { useIntl, FormattedMessage } from 'react-intl'; import { messages, labels } from 'components/messages'; -import { FormatXMLElementFn, Options } from 'intl-messageformat'; export function useMessages(): any { const intl = useIntl(); @@ -12,14 +12,12 @@ export function useMessages(): any { }; const formatMessage = ( - descriptor: - | MessageDescriptor - | { - id: string; - defaultMessage: string; - }, - values?: Record>, - opts?: Options, + descriptor: { + id: string; + defaultMessage: string; + }, + values?: { [key: string]: string }, + opts?: any, ) => { return descriptor ? intl.formatMessage(descriptor, values, opts) : null; }; diff --git a/src/components/hooks/useNavigation.ts b/src/components/hooks/useNavigation.ts index 0ff7155a..59731c3e 100644 --- a/src/components/hooks/useNavigation.ts +++ b/src/components/hooks/useNavigation.ts @@ -1,3 +1,4 @@ +'use client'; import { useMemo } from 'react'; import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { buildUrl } from 'next-basics'; diff --git a/src/components/hooks/useSticky.ts b/src/components/hooks/useSticky.ts index 459c489a..39c57f6e 100644 --- a/src/components/hooks/useSticky.ts +++ b/src/components/hooks/useSticky.ts @@ -1,3 +1,4 @@ +'use client'; import { useState, useEffect, useRef } from 'react'; export function useSticky({ enabled = true, threshold = 1 }) { diff --git a/src/components/hooks/useTeamContext.ts b/src/components/hooks/useTeamContext.ts index 0c0c0a7d..001c9cd1 100644 --- a/src/components/hooks/useTeamContext.ts +++ b/src/components/hooks/useTeamContext.ts @@ -1,3 +1,4 @@ +'use client'; import { usePathname } from 'next/navigation'; export function useTeamContext(): { diff --git a/src/components/hooks/useTheme.ts b/src/components/hooks/useTheme.ts index 099bf962..cd19f702 100644 --- a/src/components/hooks/useTheme.ts +++ b/src/components/hooks/useTheme.ts @@ -1,3 +1,4 @@ +'use client'; import { useEffect } from 'react'; import useStore, { setTheme } from 'store/app'; import { getItem, setItem } from 'next-basics'; diff --git a/src/components/hooks/useTimezone.ts b/src/components/hooks/useTimezone.ts index 3dbb52b3..0f5f8dbc 100644 --- a/src/components/hooks/useTimezone.ts +++ b/src/components/hooks/useTimezone.ts @@ -1,3 +1,4 @@ +'use client'; import { useState, useCallback } from 'react'; import { getTimezone } from 'lib/date'; import { getItem, setItem } from 'next-basics'; From bb0504065b59b29c604c7b73c45d940835d029c5 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 2 Feb 2024 22:30:01 -0800 Subject: [PATCH 057/142] Handle when team not found. --- src/app/(main)/teams/[teamId]/Team.tsx | 21 +++++++++++++++++++++ src/app/(main)/teams/[teamId]/layout.tsx | 5 +++++ 2 files changed, 26 insertions(+) create mode 100644 src/app/(main)/teams/[teamId]/Team.tsx create mode 100644 src/app/(main)/teams/[teamId]/layout.tsx diff --git a/src/app/(main)/teams/[teamId]/Team.tsx b/src/app/(main)/teams/[teamId]/Team.tsx new file mode 100644 index 00000000..631fdaf1 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/Team.tsx @@ -0,0 +1,21 @@ +'use client'; +import { useTeam, useTeamContext } from 'components/hooks'; +import { Loading } from 'react-basics'; +import notFound from 'app/not-found'; + +export function Team({ children }) { + const { teamId } = useTeamContext(); + const { data: team, isLoading } = useTeam(teamId); + + if (isLoading) { + return ; + } + + if (!team) { + return notFound(); + } + + return children; +} + +export default Team; diff --git a/src/app/(main)/teams/[teamId]/layout.tsx b/src/app/(main)/teams/[teamId]/layout.tsx new file mode 100644 index 00000000..1f887ce8 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/layout.tsx @@ -0,0 +1,5 @@ +import Team from './Team'; + +export default function ({ children }) { + return {children}; +} From ecb3af284f55c025fdb5cc6483b9787b1d7b56a1 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 2 Feb 2024 22:35:46 -0800 Subject: [PATCH 058/142] Missing 'use client'. --- src/components/hooks/useLocale.ts | 2 +- src/components/input/DateFilter.tsx | 4 ++-- src/components/input/WebsiteSelect.tsx | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/hooks/useLocale.ts b/src/components/hooks/useLocale.ts index 356e525b..00998ba4 100644 --- a/src/components/hooks/useLocale.ts +++ b/src/components/hooks/useLocale.ts @@ -4,7 +4,7 @@ import { httpGet, setItem } from 'next-basics'; import { LOCALE_CONFIG } from 'lib/constants'; import { getDateLocale, getTextDirection } from 'lib/lang'; import useStore, { setLocale } from 'store/app'; -import { useForceUpdate } from 'components/hooks'; +import { useForceUpdate } from './useForceUpdate'; import enUS from '../../../public/intl/country/en-US.json'; const messages = { diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx index 847a3218..34c80b5b 100644 --- a/src/components/input/DateFilter.tsx +++ b/src/components/input/DateFilter.tsx @@ -1,9 +1,9 @@ +'use client'; import { useState } from 'react'; import { Icon, Modal, Dropdown, Item, Text, Flexbox } from 'react-basics'; import { endOfYear, isSameDay } from 'date-fns'; import DatePickerForm from 'components/metrics/DatePickerForm'; -import { useLocale } from 'components/hooks'; -import { useMessages } from 'components/hooks'; +import { useLocale, useMessages } from 'components/hooks'; import Icons from 'components/icons'; import { formatDate, parseDateValue } from 'lib/date'; diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index 1ea8d392..6adeb214 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -1,3 +1,4 @@ +'use client'; import { useState, Key } from 'react'; import { Dropdown, Item } from 'react-basics'; import { useWebsite, useWebsites, useMessages } from 'components/hooks'; From 80a58cbdd1a97185c2723f1f5decc993fb0fb339 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 2 Feb 2024 22:48:03 -0800 Subject: [PATCH 059/142] Fixed type. --- src/app/(main)/settings/websites/WebsiteAddForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(main)/settings/websites/WebsiteAddForm.tsx b/src/app/(main)/settings/websites/WebsiteAddForm.tsx index fe8420f9..88cbb4ff 100644 --- a/src/app/(main)/settings/websites/WebsiteAddForm.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddForm.tsx @@ -16,7 +16,7 @@ export function WebsiteAddForm({ onSave, onClose, }: { - teamId: string; + teamId?: string; onSave?: () => void; onClose?: () => void; }) { From e971f2533d6c9de1a03118f11751bf9d281c372a Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 3 Feb 2024 23:19:29 -0800 Subject: [PATCH 060/142] Updated search queries. --- src/app/(main)/dashboard/Dashboard.tsx | 8 +-- src/app/(main)/settings/websites/Websites.tsx | 2 +- src/app/(main)/websites/page.tsx | 2 +- src/components/input/ProfileButton.tsx | 2 +- src/index.ts | 4 ++ src/lib/db.ts | 18 ++--- src/lib/prisma.ts | 44 +++++++++--- src/pages/api/reports/index.ts | 16 +++-- src/queries/admin/report.ts | 72 +++++-------------- src/queries/admin/team.ts | 35 +-------- src/queries/admin/teamUser.ts | 10 +-- src/queries/admin/user.ts | 24 +------ 12 files changed, 90 insertions(+), 147 deletions(-) diff --git a/src/app/(main)/dashboard/Dashboard.tsx b/src/app/(main)/dashboard/Dashboard.tsx index ed976f43..cf6cc210 100644 --- a/src/app/(main)/dashboard/Dashboard.tsx +++ b/src/app/(main)/dashboard/Dashboard.tsx @@ -12,14 +12,14 @@ import useDashboard from 'store/dashboard'; export function Dashboard() { const { formatMessage, labels, messages } = useMessages(); - const { teamId } = useTeamContext(); + const { teamId, renderTeamUrl } = useTeamContext(); const { showCharts, editing } = useDashboard(); const { dir } = useLocale(); const pageSize = 10; - const { result, query, params, setParams } = useWebsites({}, { pageSize }); + const { result, query, params, setParams } = useWebsites({ teamId }, { pageSize }); const { page } = params; - const hasData = !!result?.data; + const hasData = !!result?.data?.length; const handlePageChange = (page: number) => { setParams({ ...params, page }); @@ -36,7 +36,7 @@ export function Dashboard() { {!hasData && ( - + - + + + + + {formatMessage(messages.goToSettings)} + )} {hasData && ( diff --git a/src/app/(main)/reports/ReportsHeader.tsx b/src/app/(main)/reports/ReportsHeader.tsx index 76e9b343..e0b0c10a 100644 --- a/src/app/(main)/reports/ReportsHeader.tsx +++ b/src/app/(main)/reports/ReportsHeader.tsx @@ -1,12 +1,12 @@ 'use client'; import PageHeader from 'components/layout/PageHeader'; import { Icon, Icons, Text } from 'react-basics'; -import { useMessages, useTeamContext } from 'components/hooks'; +import { useMessages, useTeamUrl } from 'components/hooks'; import LinkButton from 'components/common/LinkButton'; export function ReportsHeader() { const { formatMessage, labels } = useMessages(); - const { renderTeamUrl } = useTeamContext(); + const { renderTeamUrl } = useTeamUrl(); return ( diff --git a/src/app/(main)/reports/ReportsTable.tsx b/src/app/(main)/reports/ReportsTable.tsx index 91ba402b..184fb43f 100644 --- a/src/app/(main)/reports/ReportsTable.tsx +++ b/src/app/(main)/reports/ReportsTable.tsx @@ -1,7 +1,7 @@ 'use client'; import { GridColumn, GridTable, Icon, Icons, Text, useBreakpoint } from 'react-basics'; import LinkButton from 'components/common/LinkButton'; -import { useMessages, useLogin, useTeamContext } from 'components/hooks'; +import { useMessages, useLogin, useTeamUrl } from 'components/hooks'; import { REPORT_TYPES } from 'lib/constants'; import ReportDeleteButton from './ReportDeleteButton'; @@ -9,7 +9,7 @@ export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomai const { formatMessage, labels } = useMessages(); const { user } = useLogin(); const breakpoint = useBreakpoint(); - const { renderTeamUrl } = useTeamContext(); + const { renderTeamUrl } = useTeamUrl(); return ( diff --git a/src/app/(main)/reports/[reportId]/BaseParameters.tsx b/src/app/(main)/reports/[reportId]/BaseParameters.tsx index 2ccfbef7..3f02fab8 100644 --- a/src/app/(main)/reports/[reportId]/BaseParameters.tsx +++ b/src/app/(main)/reports/[reportId]/BaseParameters.tsx @@ -4,7 +4,7 @@ import { FormRow } from 'react-basics'; import { parseDateRange } from 'lib/date'; import DateFilter from 'components/input/DateFilter'; import WebsiteSelect from 'components/input/WebsiteSelect'; -import { useMessages, useTeamContext } from 'components/hooks'; +import { useMessages, useTeamUrl } from 'components/hooks'; import { ReportContext } from './Report'; export interface BaseParametersProps { @@ -22,7 +22,7 @@ export function BaseParameters({ }: BaseParametersProps) { const { report, updateReport } = useContext(ReportContext); const { formatMessage, labels } = useMessages(); - const { teamId } = useTeamContext(); + const { teamId } = useTeamUrl(); const { parameters } = report || {}; const { websiteId, dateRange } = parameters || {}; diff --git a/src/app/(main)/reports/[reportId]/ReportHeader.tsx b/src/app/(main)/reports/[reportId]/ReportHeader.tsx index 41e6af70..90b776b0 100644 --- a/src/app/(main)/reports/[reportId]/ReportHeader.tsx +++ b/src/app/(main)/reports/[reportId]/ReportHeader.tsx @@ -1,7 +1,7 @@ 'use client'; import { useContext } from 'react'; import { Icon, LoadingButton, InlineEditField, useToasts } from 'react-basics'; -import { useMessages, useApi, useNavigation, useTeamContext } from 'components/hooks'; +import { useMessages, useApi, useNavigation, useTeamUrl } from 'components/hooks'; import { ReportContext } from './Report'; import styles from './ReportHeader.module.css'; import { REPORT_TYPES } from 'lib/constants'; @@ -11,7 +11,7 @@ export function ReportHeader({ icon }) { const { formatMessage, labels, messages } = useMessages(); const { showToast } = useToasts(); const { router } = useNavigation(); - const { renderTeamUrl } = useTeamContext(); + const { renderTeamUrl } = useTeamUrl(); const { post, useMutation } = useApi(); const { mutate: create, isPending: isCreating } = useMutation({ diff --git a/src/app/(main)/reports/create/ReportTemplates.tsx b/src/app/(main)/reports/create/ReportTemplates.tsx index 5abdb9fb..3fa58b50 100644 --- a/src/app/(main)/reports/create/ReportTemplates.tsx +++ b/src/app/(main)/reports/create/ReportTemplates.tsx @@ -6,7 +6,7 @@ import Funnel from 'assets/funnel.svg'; import Lightbulb from 'assets/lightbulb.svg'; import Magnet from 'assets/magnet.svg'; import styles from './ReportTemplates.module.css'; -import { useMessages, useTeamContext } from 'components/hooks'; +import { useMessages, useTeamUrl } from 'components/hooks'; function ReportItem({ title, description, url, icon }) { const { formatMessage, labels } = useMessages(); @@ -34,7 +34,7 @@ function ReportItem({ title, description, url, icon }) { export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) { const { formatMessage, labels } = useMessages(); - const { renderTeamUrl } = useTeamContext(); + const { renderTeamUrl } = useTeamUrl(); const reports = [ { diff --git a/src/app/(main)/settings/layout.tsx b/src/app/(main)/settings/layout.tsx index 72e979b7..6eb81d68 100644 --- a/src/app/(main)/settings/layout.tsx +++ b/src/app/(main)/settings/layout.tsx @@ -1,6 +1,6 @@ 'use client'; import { usePathname } from 'next/navigation'; -import { useLogin, useMessages, useTeamContext } from 'components/hooks'; +import { useLogin, useMessages, useTeamUrl } from 'components/hooks'; import SideNav from 'components/layout/SideNav'; import styles from './layout.module.css'; @@ -9,7 +9,7 @@ export default function SettingsLayout({ children }) { const pathname = usePathname(); const { formatMessage, labels } = useMessages(); const cloudMode = !!process.env.cloudMode; - const { teamId, renderTeamUrl } = useTeamContext(); + const { teamId, renderTeamUrl } = useTeamUrl(); const items = [ teamId && { diff --git a/src/app/(main)/settings/teams/TeamsDataTable.tsx b/src/app/(main)/settings/teams/TeamsDataTable.tsx index ea8bab37..e7c9fc3a 100644 --- a/src/app/(main)/settings/teams/TeamsDataTable.tsx +++ b/src/app/(main)/settings/teams/TeamsDataTable.tsx @@ -1,20 +1,10 @@ 'use client'; import DataTable from 'components/common/DataTable'; import TeamsTable from 'app/(main)/settings/teams/TeamsTable'; -import { useApi, useFilterQuery } from 'components/hooks'; -import useCache from 'store/cache'; +import { useTeams } from 'components/hooks'; export function TeamsDataTable() { - const { get } = useApi(); - const modified = useCache((state: any) => state?.teams); - const queryResult = useFilterQuery({ - queryKey: ['teams', { modified }], - queryFn: (params: any) => { - return get(`/teams`, { - ...params, - }); - }, - }); + const queryResult = useTeams(); return ( diff --git a/src/app/(main)/settings/teams/TeamsTable.tsx b/src/app/(main)/settings/teams/TeamsTable.tsx index 56bf0f81..e35d0412 100644 --- a/src/app/(main)/settings/teams/TeamsTable.tsx +++ b/src/app/(main)/settings/teams/TeamsTable.tsx @@ -1,9 +1,9 @@ 'use client'; -import { Button, GridColumn, GridTable, Icon, Text, useBreakpoint } from 'react-basics'; -import Link from 'next/link'; +import { GridColumn, GridTable, Icon, Text, useBreakpoint } from 'react-basics'; import { useMessages, useLogin } from 'components/hooks'; import Icons from 'components/icons'; import { ROLES } from 'lib/constants'; +import LinkButton from 'components/common/LinkButton'; export function TeamsTable({ data = [] }: { data: any[] }) { const { formatMessage, labels } = useMessages(); @@ -31,23 +31,19 @@ export function TeamsTable({ data = [] }: { data: any[] }) { return ( <> {isOwner && ( - - - - )} - - - + {formatMessage(labels.edit)} + + )} + + + + + {formatMessage(labels.switch)} + ); }} diff --git a/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx index c56511f9..1fedc55f 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamMembers.tsx @@ -1,7 +1,7 @@ 'use client'; import DataTable from 'components/common/DataTable'; import TeamMembersTable from './TeamMembersTable'; -import useTeamMembers from 'components/hooks/queries/useTeamMembers'; +import { useTeamMembers } from 'components/hooks'; export function TeamMembers({ teamId, allowEdit }: { teamId: string; allowEdit: boolean }) { const queryResult = useTeamMembers(teamId); diff --git a/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx index 1fce8c23..0bd49883 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamWebsites.tsx @@ -1,8 +1,16 @@ 'use client'; -import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable'; +import DataTable from 'components/common/DataTable'; +import { useTeamWebsites } from 'components/hooks'; +import TeamWebsitesTable from './TeamWebsitesTable'; export function TeamWebsites({ teamId, allowEdit }: { teamId: string; allowEdit: boolean }) { - return ; + const queryResult = useTeamWebsites(teamId); + + return ( + + {({ data }) => } + + ); } export default TeamWebsites; diff --git a/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx index fe08c059..fdd0169a 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamWebsitesTable.tsx @@ -1,16 +1,20 @@ 'use client'; -import Link from 'next/link'; -import { Button, GridColumn, GridTable, Icon, Text } from 'react-basics'; -import { useMessages } from 'components/hooks'; +import { GridColumn, GridTable, Icon, Text } from 'react-basics'; +import { useLogin, useMessages } from 'components/hooks'; import Icons from 'components/icons'; +import LinkButton from 'components/common/LinkButton'; export function TeamWebsitesTable({ + teamId, data = [], + allowEdit, }: { + teamId: string; data: any[]; - readOnly: boolean; - onRemove: () => void; + allowEdit?: boolean; }) { + const { user } = useLogin(); + const { formatMessage, labels } = useMessages(); return ( @@ -20,14 +24,22 @@ export function TeamWebsitesTable({ {row => { const { websiteId } = row; return ( - - - + + ); }} diff --git a/src/app/(main)/settings/users/UsersTable.tsx b/src/app/(main)/settings/users/UsersTable.tsx index 7b43c007..523bd01c 100644 --- a/src/app/(main)/settings/users/UsersTable.tsx +++ b/src/app/(main)/settings/users/UsersTable.tsx @@ -1,10 +1,10 @@ 'use client'; -import { Button, Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; +import { Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; import { formatDistance } from 'date-fns'; -import Link from 'next/link'; import { ROLES } from 'lib/constants'; import { useMessages, useLocale } from 'components/hooks'; import UserDeleteButton from './UserDeleteButton'; +import LinkButton from 'components/common/LinkButton'; export function UsersTable({ data = [], @@ -45,14 +45,12 @@ export function UsersTable({ return ( <> - - - + + + + + {formatMessage(labels.edit)} + ); }} diff --git a/src/app/(main)/settings/websites/WebsiteSettings.tsx b/src/app/(main)/settings/websites/WebsiteSettings.tsx index f1e8f004..271ff5d2 100644 --- a/src/app/(main)/settings/websites/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/WebsiteSettings.tsx @@ -4,16 +4,16 @@ import { Item, Tabs, Button, Text, Icon, Loading } from 'react-basics'; import Link from 'next/link'; import Icons from 'components/icons'; import PageHeader from 'components/layout/PageHeader'; +import WebsiteContext from 'app/(main)/websites/[websiteId]/WebsiteContext'; import WebsiteEditForm from './[websiteId]/WebsiteEditForm'; import WebsiteData from './[websiteId]/WebsiteData'; import TrackingCode from './[websiteId]/TrackingCode'; import ShareUrl from './[websiteId]/ShareUrl'; import { useWebsite, useMessages } from 'components/hooks'; -import WebsiteContext from '../../websites/[websiteId]/WebsiteContext'; export function WebsiteSettings({ websiteId, openExternal = false }) { const { formatMessage, labels } = useMessages(); - const { data: website, isLoading, refetch } = useWebsite(websiteId, { gcTime: 0 }); + const { data: website, isLoading, refetch } = useWebsite(websiteId); const [tab, setTab] = useState('details'); const handleSave = () => { diff --git a/src/app/(main)/settings/websites/WebsitesTable.tsx b/src/app/(main)/settings/websites/WebsitesTable.tsx index 4a274e36..6486babe 100644 --- a/src/app/(main)/settings/websites/WebsitesTable.tsx +++ b/src/app/(main)/settings/websites/WebsitesTable.tsx @@ -1,8 +1,8 @@ 'use client'; import { ReactNode } from 'react'; -import Link from 'next/link'; -import { Button, Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; -import { useMessages, useLogin, useTeamContext } from 'components/hooks'; +import { Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; +import { useMessages, useLogin, useTeamUrl } from 'components/hooks'; +import LinkButton from 'components/common/LinkButton'; export interface WebsitesTableProps { data: any[]; @@ -24,7 +24,7 @@ export function WebsitesTable({ const { formatMessage, labels } = useMessages(); const { user } = useLogin(); const breakpoint = useBreakpoint(); - const { renderTeamUrl } = useTeamContext(); + const { renderTeamUrl } = useTeamUrl(); return ( @@ -33,29 +33,25 @@ export function WebsitesTable({ {showActions && ( {row => { - const { id } = row; + const { id: websiteId } = row; return ( <> {allowEdit && (teamId || user.isAdmin) && ( - - - + + + + + {formatMessage(labels.edit)} + )} {allowView && ( - - - + + + + + {formatMessage(labels.view)} + )} ); diff --git a/src/app/(main)/teams/[teamId]/Team.tsx b/src/app/(main)/teams/[teamId]/Team.tsx index 631fdaf1..3e0ae852 100644 --- a/src/app/(main)/teams/[teamId]/Team.tsx +++ b/src/app/(main)/teams/[teamId]/Team.tsx @@ -1,10 +1,10 @@ 'use client'; -import { useTeam, useTeamContext } from 'components/hooks'; +import { useTeam, useTeamUrl } from 'components/hooks'; import { Loading } from 'react-basics'; -import notFound from 'app/not-found'; +import TeamContext from './TeamContext'; export function Team({ children }) { - const { teamId } = useTeamContext(); + const { teamId } = useTeamUrl(); const { data: team, isLoading } = useTeam(teamId); if (isLoading) { @@ -12,10 +12,10 @@ export function Team({ children }) { } if (!team) { - return notFound(); + return null; } - return children; + return {children}; } export default Team; diff --git a/src/app/(main)/teams/[teamId]/TeamContext.tsx b/src/app/(main)/teams/[teamId]/TeamContext.tsx new file mode 100644 index 00000000..fe1ec9c1 --- /dev/null +++ b/src/app/(main)/teams/[teamId]/TeamContext.tsx @@ -0,0 +1,6 @@ +'use client'; +import { createContext } from 'react'; + +export const TeamContext = createContext(null); + +export default TeamContext; diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx index 793c3ab2..8b7c8070 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx @@ -1,11 +1,11 @@ 'use client'; -import { GridTable, GridColumn, Button, Icon, Text } from 'react-basics'; +import { GridTable, GridColumn, Icon, Text } from 'react-basics'; import { useMessages, useNavigation } from 'components/hooks'; -import Link from 'next/link'; import Icons from 'components/icons'; import PageHeader from 'components/layout/PageHeader'; import Empty from 'components/common/Empty'; import { DATA_TYPES } from 'lib/constants'; +import LinkButton from 'components/common/LinkButton'; export function EventDataValueTable({ data = [], event }: { data: any[]; event: string }) { const { formatMessage, labels } = useMessages(); @@ -14,14 +14,12 @@ export function EventDataValueTable({ data = [], event }: { data: any[]; event: const Title = () => { return ( <> - - - + + + + + {formatMessage(labels.back)} + {event} ); diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index 23ba94ff..79cefcfd 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -6,7 +6,9 @@ export * from './queries/useReport'; export * from './queries/useReports'; export * from './queries/useShareToken'; export * from './queries/useTeam'; +export * from './queries/useTeams'; export * from './queries/useTeamWebsites'; +export * from './queries/useTeamMembers'; export * from './queries/useUser'; export * from './queries/useUsers'; export * from './queries/useWebsite'; @@ -25,6 +27,6 @@ export * from './useLocale'; export * from './useMessages'; export * from './useNavigation'; export * from './useSticky'; -export * from './useTeamContext'; +export * from './useTeamUrl'; export * from './useTheme'; export * from './useTimezone'; diff --git a/src/components/hooks/queries/useReports.ts b/src/components/hooks/queries/useReports.ts index 99054dfd..77ebdbe9 100644 --- a/src/components/hooks/queries/useReports.ts +++ b/src/components/hooks/queries/useReports.ts @@ -1,10 +1,10 @@ 'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import useCache from 'store/cache'; +import useModified from 'store/modified'; export function useReports({ websiteId, teamId }: { websiteId?: string; teamId?: string }) { - const modified = useCache((state: any) => state?.reports); + const modified = useModified((state: any) => state?.reports); const { get, del, useMutation } = useApi(); const queryResult = useFilterQuery({ queryKey: ['reports', { websiteId, teamId, modified }], diff --git a/src/components/hooks/queries/useTeams.ts b/src/components/hooks/queries/useTeams.ts new file mode 100644 index 00000000..7628887f --- /dev/null +++ b/src/components/hooks/queries/useTeams.ts @@ -0,0 +1,18 @@ +'use client'; +import useApi from './useApi'; +import useFilterQuery from './useFilterQuery'; +import { useLogin } from 'components/hooks'; + +export function useTeams(userId?: string) { + const { get } = useApi(); + const { user } = useLogin(); + + return useFilterQuery({ + queryKey: ['teams', { userId: userId || user?.id }], + queryFn: (params: any) => { + return get(`/teams`, params); + }, + }); +} + +export default useTeams; diff --git a/src/components/hooks/queries/useUsers.ts b/src/components/hooks/queries/useUsers.ts index d7bc8074..05f273d8 100644 --- a/src/components/hooks/queries/useUsers.ts +++ b/src/components/hooks/queries/useUsers.ts @@ -1,11 +1,11 @@ 'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import useCache from 'store/cache'; +import useModified from 'store/modified'; export function useUsers() { const { get } = useApi(); - const modified = useCache((state: any) => state?.users); + const modified = useModified((state: any) => state?.users); return useFilterQuery({ queryKey: ['users', { modified }], diff --git a/src/components/hooks/queries/useWebsite.ts b/src/components/hooks/queries/useWebsite.ts index c29a6cd0..58b93ebb 100644 --- a/src/components/hooks/queries/useWebsite.ts +++ b/src/components/hooks/queries/useWebsite.ts @@ -3,8 +3,9 @@ import useApi from './useApi'; export function useWebsite(websiteId: string, options?: { [key: string]: any }) { const { get, useQuery } = useApi(); + return useQuery({ - queryKey: ['websites', websiteId], + queryKey: ['websites', { websiteId }], queryFn: () => get(`/websites/${websiteId}`), enabled: !!websiteId, ...options, diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index ed34193f..9449acc7 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -2,7 +2,9 @@ import { useApi } from './useApi'; import { useFilterQuery } from './useFilterQuery'; import { useLogin } from './useLogin'; -import useCache from 'store/cache'; +import useModified from 'store/modified'; + +const selector = (state: any) => state?.websites; export function useWebsites( { userId, teamId }: { userId?: string; teamId?: string }, @@ -10,7 +12,7 @@ export function useWebsites( ) { const { get } = useApi(); const { user } = useLogin(); - const modified = useCache((state: any) => state?.websites); + const modified = useModified(selector); return useFilterQuery({ queryKey: ['websites', { userId, teamId, modified, ...params }], diff --git a/src/components/hooks/useTeamContext.ts b/src/components/hooks/useTeamUrl.ts similarity index 84% rename from src/components/hooks/useTeamContext.ts rename to src/components/hooks/useTeamUrl.ts index 001c9cd1..3e1c3972 100644 --- a/src/components/hooks/useTeamContext.ts +++ b/src/components/hooks/useTeamUrl.ts @@ -1,7 +1,7 @@ 'use client'; import { usePathname } from 'next/navigation'; -export function useTeamContext(): { +export function useTeamUrl(): { teamId?: string; renderTeamUrl: (url: string) => string; } { @@ -15,4 +15,4 @@ export function useTeamContext(): { return { teamId, renderTeamUrl }; } -export default useTeamContext; +export default useTeamUrl; diff --git a/src/index.ts b/src/index.ts index 1c00d3f0..181fb49b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,33 +1,13 @@ -export * from 'components/hooks/queries/useApi'; -export * from 'components/hooks/queries/useConfig'; -export * from 'components/hooks/queries/useFilterQuery'; -export * from 'components/hooks/queries/useLogin'; -export * from 'components/hooks/queries/useShareToken'; -export * from 'components/hooks/queries/useUser'; -export * from 'components/hooks/queries/useWebsite'; +export * from 'components/hooks'; -export * from 'components/hooks/useDateRange'; -export * from 'components/hooks/useDocumentClick'; -export * from 'components/hooks/useEscapeKey'; -export * from 'components/hooks/useFilters'; -export * from 'components/hooks/useForceUpdate'; -export * from 'components/hooks/useFormat'; -export * from 'components/hooks/useLocale'; -export * from 'components/hooks/useMessages'; -export * from 'components/hooks/useNavigation'; -export * from 'components/hooks/useSticky'; -export * from 'components/hooks/useTheme'; -export * from 'components/hooks/useTeamContext'; -export * from 'components/hooks/useTimezone'; - -export * from './app/(main)/settings/teams/[teamId]/TeamEditForm'; -export * from './app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton'; -export * from './app/(main)/settings/teams/[teamId]/TeamMembers'; -export * from './app/(main)/settings/teams/[teamId]/TeamMembersTable'; -export * from './app/(main)/settings/teams/[teamId]/TeamSettings'; -export * from './app/(main)/settings/teams/[teamId]/TeamWebsiteRemoveButton'; -export * from './app/(main)/settings/teams/[teamId]/TeamWebsites'; -export * from './app/(main)/settings/teams/[teamId]/TeamWebsitesTable'; +export * from 'app/(main)/settings/teams/[teamId]/TeamEditForm'; +export * from 'app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton'; +export * from 'app/(main)/settings/teams/[teamId]/TeamMembers'; +export * from 'app/(main)/settings/teams/[teamId]/TeamMembersTable'; +export * from 'app/(main)/settings/teams/[teamId]/TeamSettings'; +export * from 'app/(main)/settings/teams/[teamId]/TeamWebsiteRemoveButton'; +export * from 'app/(main)/settings/teams/[teamId]/TeamWebsites'; +export * from 'app/(main)/settings/teams/[teamId]/TeamWebsitesTable'; export * from 'app/(main)/settings/teams/TeamAddForm'; export * from 'app/(main)/settings/teams/TeamDeleteForm'; export * from 'app/(main)/settings/teams/TeamsHeader'; @@ -37,11 +17,11 @@ export * from 'app/(main)/settings/teams/TeamsDataTable'; export * from 'app/(main)/settings/teams/TeamsTable'; export * from 'app/(main)/settings/teams/WebsiteTags'; -export * from './app/(main)/settings/websites/[websiteId]/ShareUrl'; -export * from './app/(main)/settings/websites/[websiteId]/TrackingCode'; -export * from './app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm'; -export * from './app/(main)/settings/websites/[websiteId]/WebsiteEditForm'; -export * from './app/(main)/settings/websites/[websiteId]/WebsiteResetForm'; +export * from 'app/(main)/settings/websites/[websiteId]/ShareUrl'; +export * from 'app/(main)/settings/websites/[websiteId]/TrackingCode'; +export * from 'app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm'; +export * from 'app/(main)/settings/websites/[websiteId]/WebsiteEditForm'; +export * from 'app/(main)/settings/websites/[websiteId]/WebsiteResetForm'; export * from 'app/(main)/settings/websites/WebsiteAddForm'; export * from 'app/(main)/settings/websites/WebsitesHeader'; diff --git a/src/store/modified.ts b/src/store/modified.ts new file mode 100644 index 00000000..272412eb --- /dev/null +++ b/src/store/modified.ts @@ -0,0 +1,9 @@ +import { create } from 'zustand'; + +const store = create(() => ({})); + +export function touch(key: string) { + store.setState({ [key]: Date.now() }); +} + +export default store; From cc273092d511ec22c6430c30b813eb3a6ae43781 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 4 Feb 2024 19:53:06 -0800 Subject: [PATCH 065/142] Added website and team providers. --- src/app/(main)/reports/ReportDeleteButton.tsx | 2 +- src/app/(main)/settings/teams/TeamAddForm.tsx | 2 +- .../(main)/settings/teams/TeamDeleteForm.tsx | 2 +- .../(main)/settings/teams/TeamJoinForm.tsx | 2 +- .../(main)/settings/teams/TeamLeaveForm.tsx | 2 +- .../teams/[teamId]/TeamMemberRemoveButton.tsx | 2 +- .../(main)/settings/users/UserAddButton.tsx | 2 +- .../(main)/settings/users/UserDeleteForm.tsx | 2 +- .../settings/websites/WebsiteAddButton.tsx | 2 +- .../websites/[websiteId]/ShareUrl.tsx | 13 ++++--- .../websites/[websiteId]/WebsiteData.tsx | 2 +- .../websites/[websiteId]/WebsiteEditForm.tsx | 17 +++++----- .../{ => [websiteId]}/WebsiteSettings.tsx | 34 +++++++------------ .../settings/websites/[websiteId]/page.tsx | 9 +++-- src/app/(main)/teams/[teamId]/Team.tsx | 21 ------------ src/app/(main)/teams/[teamId]/TeamContext.tsx | 6 ---- .../(main)/teams/[teamId]/TeamProvider.tsx | 30 ++++++++++++++++ src/app/(main)/teams/[teamId]/layout.tsx | 4 +-- .../websites/[websiteId]/WebsiteContext.tsx | 6 ---- .../websites/[websiteId]/WebsiteProvider.tsx | 32 +++++++++++++++++ src/components/hooks/queries/useWebsite.ts | 2 +- src/index.ts | 5 ++- src/pages/api/websites/[websiteId]/index.ts | 10 +++--- src/queries/admin/website.ts | 8 ++--- src/store/cache.ts | 4 --- 25 files changed, 123 insertions(+), 98 deletions(-) rename src/app/(main)/settings/websites/{ => [websiteId]}/WebsiteSettings.tsx (57%) delete mode 100644 src/app/(main)/teams/[teamId]/Team.tsx delete mode 100644 src/app/(main)/teams/[teamId]/TeamContext.tsx create mode 100644 src/app/(main)/teams/[teamId]/TeamProvider.tsx delete mode 100644 src/app/(main)/websites/[websiteId]/WebsiteContext.tsx create mode 100644 src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx diff --git a/src/app/(main)/reports/ReportDeleteButton.tsx b/src/app/(main)/reports/ReportDeleteButton.tsx index ce3958e5..c0f16469 100644 --- a/src/app/(main)/reports/ReportDeleteButton.tsx +++ b/src/app/(main)/reports/ReportDeleteButton.tsx @@ -1,7 +1,7 @@ 'use client'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; import ConfirmationForm from 'components/common/ConfirmationForm'; export function ReportDeleteButton({ diff --git a/src/app/(main)/settings/teams/TeamAddForm.tsx b/src/app/(main)/settings/teams/TeamAddForm.tsx index 53220b8f..a3caf25f 100644 --- a/src/app/(main)/settings/teams/TeamAddForm.tsx +++ b/src/app/(main)/settings/teams/TeamAddForm.tsx @@ -8,7 +8,7 @@ import { Button, SubmitButton, } from 'react-basics'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; import { useApi, useMessages } from 'components/hooks'; export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) { diff --git a/src/app/(main)/settings/teams/TeamDeleteForm.tsx b/src/app/(main)/settings/teams/TeamDeleteForm.tsx index f6f40557..aa2b1d3f 100644 --- a/src/app/(main)/settings/teams/TeamDeleteForm.tsx +++ b/src/app/(main)/settings/teams/TeamDeleteForm.tsx @@ -1,6 +1,6 @@ 'use client'; import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; import TypeConfirmationForm from 'components/common/TypeConfirmationForm'; const CONFIRM_VALUE = 'DELETE'; diff --git a/src/app/(main)/settings/teams/TeamJoinForm.tsx b/src/app/(main)/settings/teams/TeamJoinForm.tsx index 1510b6ef..b448a368 100644 --- a/src/app/(main)/settings/teams/TeamJoinForm.tsx +++ b/src/app/(main)/settings/teams/TeamJoinForm.tsx @@ -10,7 +10,7 @@ import { SubmitButton, } from 'react-basics'; import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) { const { formatMessage, labels, getMessage } = useMessages(); diff --git a/src/app/(main)/settings/teams/TeamLeaveForm.tsx b/src/app/(main)/settings/teams/TeamLeaveForm.tsx index 4e853702..eba448f1 100644 --- a/src/app/(main)/settings/teams/TeamLeaveForm.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveForm.tsx @@ -1,6 +1,6 @@ 'use client'; import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; import ConfirmationForm from 'components/common/ConfirmationForm'; export function TeamLeaveForm({ diff --git a/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx index 581b97a2..bae0e723 100644 --- a/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/TeamMemberRemoveButton.tsx @@ -1,7 +1,7 @@ 'use client'; import { useApi, useMessages } from 'components/hooks'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; export function TeamMemberRemoveButton({ teamId, diff --git a/src/app/(main)/settings/users/UserAddButton.tsx b/src/app/(main)/settings/users/UserAddButton.tsx index b97571c1..57f2ebc5 100644 --- a/src/app/(main)/settings/users/UserAddButton.tsx +++ b/src/app/(main)/settings/users/UserAddButton.tsx @@ -2,7 +2,7 @@ import { Button, Icon, Text, Modal, Icons, ModalTrigger, useToasts } from 'react-basics'; import UserAddForm from './UserAddForm'; import { useMessages } from 'components/hooks'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; export function UserAddButton({ onSave }: { onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/src/app/(main)/settings/users/UserDeleteForm.tsx b/src/app/(main)/settings/users/UserDeleteForm.tsx index 5fed5fbb..0cce8d6d 100644 --- a/src/app/(main)/settings/users/UserDeleteForm.tsx +++ b/src/app/(main)/settings/users/UserDeleteForm.tsx @@ -1,7 +1,7 @@ 'use client'; import { useApi, useMessages } from 'components/hooks'; import ConfirmationForm from 'components/common/ConfirmationForm'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; export function UserDeleteForm({ userId, username, onSave, onClose }) { const { FormattedMessage, messages, labels, formatMessage } = useMessages(); diff --git a/src/app/(main)/settings/websites/WebsiteAddButton.tsx b/src/app/(main)/settings/websites/WebsiteAddButton.tsx index 9fd06a1a..90fc15b1 100644 --- a/src/app/(main)/settings/websites/WebsiteAddButton.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddButton.tsx @@ -2,7 +2,7 @@ import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import WebsiteAddForm from './WebsiteAddForm'; import { useMessages } from 'components/hooks'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; export function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx index 50e1ad1d..13c07dd1 100644 --- a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx @@ -1,5 +1,4 @@ 'use client'; -import { Website } from '@prisma/client'; import { Form, FormRow, @@ -11,21 +10,22 @@ import { LoadingButton, useToasts, } from 'react-basics'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { getRandomChars } from 'next-basics'; import { useApi, useMessages } from 'components/hooks'; +import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; +import { touch } from 'store/modified'; const generateId = () => getRandomChars(16); export function ShareUrl({ - website, hostUrl, - onSave, }: { - website: Website; + websiteId: string; hostUrl?: string; onSave?: () => void; }) { + const website = useContext(WebsiteContext); const { domain, shareId } = website; const { formatMessage, labels, messages } = useMessages(); const [id, setId] = useState(shareId); @@ -47,7 +47,6 @@ export function ShareUrl({ const data = { shareId: checked ? generateId() : null }; mutate(data, { onSuccess: async () => { - onSave?.(); showToast({ message: formatMessage(messages.saved), variant: 'success' }); }, }); @@ -60,7 +59,7 @@ export function ShareUrl({ { onSuccess: async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); - onSave?.(); + touch(`website:${website?.id}`); }, }, ); diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx index 5607ad23..d22c0608 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx @@ -4,7 +4,7 @@ import { useRouter } from 'next/navigation'; import { useMessages } from 'components/hooks'; import WebsiteDeleteForm from './WebsiteDeleteForm'; import WebsiteResetForm from './WebsiteResetForm'; -import { touch } from 'store/cache'; +import { touch } from 'store/modified'; export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx index 838a6cd6..cd4fb5d7 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx @@ -1,6 +1,5 @@ 'use client'; -import { Website } from '@prisma/client'; -import { useRef } from 'react'; +import { useContext, useRef } from 'react'; import { SubmitButton, Form, @@ -12,18 +11,20 @@ import { } from 'react-basics'; import { useApi, useMessages } from 'components/hooks'; import { DOMAIN_REGEX } from 'lib/constants'; +import { touch } from 'store/modified'; +import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; export function WebsiteEditForm({ - website, - onSave, + websiteId, }: { - website: Website; + websiteId: string; onSave?: (data: any) => void; }) { + const website = useContext(WebsiteContext); const { formatMessage, labels, messages } = useMessages(); const { post, useMutation } = useApi(); const { mutate, error } = useMutation({ - mutationFn: (data: any) => post(`/websites/${website.id}`, data), + mutationFn: (data: any) => post(`/websites/${websiteId}`, data), }); const ref = useRef(null); const { showToast } = useToasts(); @@ -33,7 +34,7 @@ export function WebsiteEditForm({ onSuccess: async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); ref.current.reset(data); - onSave?.(data); + touch(`website:${website?.id}`); }, }); }; @@ -41,7 +42,7 @@ export function WebsiteEditForm({ return (
- + diff --git a/src/app/(main)/settings/websites/WebsiteSettings.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx similarity index 57% rename from src/app/(main)/settings/websites/WebsiteSettings.tsx rename to src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx index 271ff5d2..fcb6316b 100644 --- a/src/app/(main)/settings/websites/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx @@ -1,31 +1,23 @@ 'use client'; -import { useState, Key } from 'react'; -import { Item, Tabs, Button, Text, Icon, Loading } from 'react-basics'; +import { useState, Key, useContext } from 'react'; +import { Item, Tabs, Button, Text, Icon } from 'react-basics'; import Link from 'next/link'; import Icons from 'components/icons'; import PageHeader from 'components/layout/PageHeader'; -import WebsiteContext from 'app/(main)/websites/[websiteId]/WebsiteContext'; -import WebsiteEditForm from './[websiteId]/WebsiteEditForm'; -import WebsiteData from './[websiteId]/WebsiteData'; -import TrackingCode from './[websiteId]/TrackingCode'; -import ShareUrl from './[websiteId]/ShareUrl'; -import { useWebsite, useMessages } from 'components/hooks'; +import WebsiteEditForm from './WebsiteEditForm'; +import WebsiteData from './WebsiteData'; +import TrackingCode from './TrackingCode'; +import ShareUrl from './ShareUrl'; +import { useMessages } from 'components/hooks'; +import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; export function WebsiteSettings({ websiteId, openExternal = false }) { + const website = useContext(WebsiteContext); const { formatMessage, labels } = useMessages(); - const { data: website, isLoading, refetch } = useWebsite(websiteId); const [tab, setTab] = useState('details'); - const handleSave = () => { - refetch(); - }; - - if (isLoading) { - return ; - } - return ( - + <> }> - -
-
- ); -} - export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) { const { formatMessage, labels } = useMessages(); const { renderTeamUrl } = useTeamUrl(); @@ -71,4 +46,28 @@ export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) ); } +function ReportItem({ title, description, url, icon }) { + const { formatMessage, labels } = useMessages(); + + return ( +
+
+ {icon} + {title} +
+
{description}
+
+ + + +
+
+ ); +} + export default ReportTemplates; diff --git a/src/app/(main)/reports/create/page.tsx b/src/app/(main)/reports/create/page.tsx index 8726f435..4a592845 100644 --- a/src/app/(main)/reports/create/page.tsx +++ b/src/app/(main)/reports/create/page.tsx @@ -1,8 +1,8 @@ -import ReportTemplates from './ReportTemplates'; +import ReportCreatePage from './ReportCreatePage'; import { Metadata } from 'next'; -export default function ReportsCreatePage() { - return ; +export default function () { + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/reports/event-data/EventDataParameters.tsx b/src/app/(main)/reports/event-data/EventDataParameters.tsx index 44f3e8e3..4d95088f 100644 --- a/src/app/(main)/reports/event-data/EventDataParameters.tsx +++ b/src/app/(main)/reports/event-data/EventDataParameters.tsx @@ -1,11 +1,10 @@ -'use client'; import { useContext } from 'react'; import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics'; import Empty from 'components/common/Empty'; import Icons from 'components/icons'; import { useApi, useMessages } from 'components/hooks'; import { DATA_TYPES, REPORT_PARAMETERS } from 'lib/constants'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import FieldAddForm from '../[reportId]/FieldAddForm'; import ParameterList from '../[reportId]/ParameterList'; import BaseParameters from '../[reportId]/BaseParameters'; diff --git a/src/app/(main)/reports/event-data/EventDataReport.tsx b/src/app/(main)/reports/event-data/EventDataReport.tsx index f4d674e5..9d761f22 100644 --- a/src/app/(main)/reports/event-data/EventDataReport.tsx +++ b/src/app/(main)/reports/event-data/EventDataReport.tsx @@ -1,5 +1,4 @@ -'use client'; -import Report from '../[reportId]/Report'; +import ReportPage from '../[reportId]/ReportPage'; import ReportHeader from '../[reportId]/ReportHeader'; import ReportMenu from '../[reportId]/ReportMenu'; import ReportBody from '../[reportId]/ReportBody'; @@ -14,7 +13,7 @@ const defaultParameters = { export default function EventDataReport({ reportId }: { reportId?: string }) { return ( - + } /> @@ -22,6 +21,6 @@ export default function EventDataReport({ reportId }: { reportId?: string }) { - + ); } diff --git a/src/app/(main)/reports/event-data/EventDataReportPage.tsx b/src/app/(main)/reports/event-data/EventDataReportPage.tsx new file mode 100644 index 00000000..8276acfb --- /dev/null +++ b/src/app/(main)/reports/event-data/EventDataReportPage.tsx @@ -0,0 +1,6 @@ +'use client'; +import EventDataReport from './EventDataReport'; + +export default function EventDataReportPage() { + return ; +} diff --git a/src/app/(main)/reports/event-data/EventDataTable.tsx b/src/app/(main)/reports/event-data/EventDataTable.tsx index cf593759..e9a2b876 100644 --- a/src/app/(main)/reports/event-data/EventDataTable.tsx +++ b/src/app/(main)/reports/event-data/EventDataTable.tsx @@ -1,8 +1,7 @@ -'use client'; import { useContext } from 'react'; import { GridTable, GridColumn } from 'react-basics'; import { useMessages } from 'components/hooks'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; export function EventDataTable() { const { report } = useContext(ReportContext); diff --git a/src/app/(main)/reports/event-data/page.tsx b/src/app/(main)/reports/event-data/page.tsx index fe0fdb55..b8a11749 100644 --- a/src/app/(main)/reports/event-data/page.tsx +++ b/src/app/(main)/reports/event-data/page.tsx @@ -1,7 +1,7 @@ import { Metadata } from 'next'; import EventDataReport from './EventDataReport'; -export default function EventDataReportPage() { +export default function () { return ; } diff --git a/src/app/(main)/reports/funnel/FunnelChart.tsx b/src/app/(main)/reports/funnel/FunnelChart.tsx index e643967f..e7ec7b59 100644 --- a/src/app/(main)/reports/funnel/FunnelChart.tsx +++ b/src/app/(main)/reports/funnel/FunnelChart.tsx @@ -1,10 +1,9 @@ -'use client'; import { JSX, useCallback, useContext, useMemo } from 'react'; import { Loading, StatusLight } from 'react-basics'; import { useMessages, useTheme } from 'components/hooks'; import BarChart from 'components/metrics/BarChart'; import { formatLongNumber } from 'lib/format'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import styles from './FunnelChart.module.css'; export interface FunnelChartProps { diff --git a/src/app/(main)/reports/funnel/FunnelParameters.tsx b/src/app/(main)/reports/funnel/FunnelParameters.tsx index 5a3bdada..676c18d4 100644 --- a/src/app/(main)/reports/funnel/FunnelParameters.tsx +++ b/src/app/(main)/reports/funnel/FunnelParameters.tsx @@ -1,4 +1,3 @@ -'use client'; import { useContext } from 'react'; import { useMessages } from 'components/hooks'; import { @@ -14,7 +13,7 @@ import { } from 'react-basics'; import Icons from 'components/icons'; import UrlAddForm from './UrlAddForm'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import BaseParameters from '../[reportId]/BaseParameters'; import ParameterList from '../[reportId]/ParameterList'; import PopupForm from '../[reportId]/PopupForm'; diff --git a/src/app/(main)/reports/funnel/FunnelReport.tsx b/src/app/(main)/reports/funnel/FunnelReport.tsx index 4013f073..47987348 100644 --- a/src/app/(main)/reports/funnel/FunnelReport.tsx +++ b/src/app/(main)/reports/funnel/FunnelReport.tsx @@ -1,8 +1,7 @@ -'use client'; import FunnelChart from './FunnelChart'; import FunnelTable from './FunnelTable'; import FunnelParameters from './FunnelParameters'; -import Report from '../[reportId]/Report'; +import ReportPage from '../[reportId]/ReportPage'; import ReportHeader from '../[reportId]/ReportHeader'; import ReportMenu from '../[reportId]/ReportMenu'; import ReportBody from '../[reportId]/ReportBody'; @@ -16,7 +15,7 @@ const defaultParameters = { export default function FunnelReport({ reportId }: { reportId?: string }) { return ( - + } /> @@ -25,6 +24,6 @@ export default function FunnelReport({ reportId }: { reportId?: string }) { - + ); } diff --git a/src/app/(main)/reports/funnel/FunnelReportPage.tsx b/src/app/(main)/reports/funnel/FunnelReportPage.tsx new file mode 100644 index 00000000..a114a8cc --- /dev/null +++ b/src/app/(main)/reports/funnel/FunnelReportPage.tsx @@ -0,0 +1,6 @@ +'use client'; +import FunnelReport from './FunnelReport'; + +export default function FunnelReportPage() { + return ; +} diff --git a/src/app/(main)/reports/funnel/FunnelTable.tsx b/src/app/(main)/reports/funnel/FunnelTable.tsx index d74bdeb4..67a2444a 100644 --- a/src/app/(main)/reports/funnel/FunnelTable.tsx +++ b/src/app/(main)/reports/funnel/FunnelTable.tsx @@ -1,8 +1,7 @@ -'use client'; import { useContext } from 'react'; import ListTable from 'components/metrics/ListTable'; import { useMessages } from 'components/hooks'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; export function FunnelTable() { const { report } = useContext(ReportContext); diff --git a/src/app/(main)/reports/funnel/UrlAddForm.tsx b/src/app/(main)/reports/funnel/UrlAddForm.tsx index 9aa342f7..88c27ae9 100644 --- a/src/app/(main)/reports/funnel/UrlAddForm.tsx +++ b/src/app/(main)/reports/funnel/UrlAddForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useState } from 'react'; import { useMessages } from 'components/hooks'; import { Button, Form, FormRow, TextField, Flexbox } from 'react-basics'; diff --git a/src/app/(main)/reports/funnel/page.tsx b/src/app/(main)/reports/funnel/page.tsx index 7a2f2a5a..e00cfd51 100644 --- a/src/app/(main)/reports/funnel/page.tsx +++ b/src/app/(main)/reports/funnel/page.tsx @@ -1,8 +1,8 @@ -import FunnelReport from './FunnelReport'; +import FunnelReportPage from './FunnelReportPage'; import { Metadata } from 'next'; -export default function FunnelReportPage() { - return ; +export default function () { + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/reports/insights/InsightsParameters.tsx b/src/app/(main)/reports/insights/InsightsParameters.tsx index 5adfc58e..3799ec8c 100644 --- a/src/app/(main)/reports/insights/InsightsParameters.tsx +++ b/src/app/(main)/reports/insights/InsightsParameters.tsx @@ -1,4 +1,3 @@ -'use client'; import { useContext } from 'react'; import { useFormat, useMessages, useFilters } from 'components/hooks'; import { @@ -13,7 +12,7 @@ import { } from 'react-basics'; import Icons from 'components/icons'; import BaseParameters from '../[reportId]/BaseParameters'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import ParameterList from '../[reportId]/ParameterList'; import FilterSelectForm from '../[reportId]/FilterSelectForm'; import FieldSelectForm from '../[reportId]/FieldSelectForm'; diff --git a/src/app/(main)/reports/insights/InsightsReport.tsx b/src/app/(main)/reports/insights/InsightsReport.tsx index 3c199003..306b3e76 100644 --- a/src/app/(main)/reports/insights/InsightsReport.tsx +++ b/src/app/(main)/reports/insights/InsightsReport.tsx @@ -1,5 +1,4 @@ -'use client'; -import Report from '../[reportId]/Report'; +import ReportPage from '../[reportId]/ReportPage'; import ReportHeader from '../[reportId]/ReportHeader'; import ReportMenu from '../[reportId]/ReportMenu'; import ReportBody from '../[reportId]/ReportBody'; @@ -15,7 +14,7 @@ const defaultParameters = { export default function InsightsReport({ reportId }: { reportId?: string }) { return ( - + } /> @@ -23,6 +22,6 @@ export default function InsightsReport({ reportId }: { reportId?: string }) { - + ); } diff --git a/src/app/(main)/reports/insights/InsightsReportPage.tsx b/src/app/(main)/reports/insights/InsightsReportPage.tsx new file mode 100644 index 00000000..7525b767 --- /dev/null +++ b/src/app/(main)/reports/insights/InsightsReportPage.tsx @@ -0,0 +1,6 @@ +'use client'; +import InsightsReport from './InsightsReport'; + +export default function InsightsReportPage() { + return ; +} diff --git a/src/app/(main)/reports/insights/InsightsTable.tsx b/src/app/(main)/reports/insights/InsightsTable.tsx index f69d8ccc..f19aaa14 100644 --- a/src/app/(main)/reports/insights/InsightsTable.tsx +++ b/src/app/(main)/reports/insights/InsightsTable.tsx @@ -1,8 +1,7 @@ -'use client'; import { useContext, useEffect, useState } from 'react'; import { GridTable, GridColumn } from 'react-basics'; import { useFormat, useMessages } from 'components/hooks'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; export function InsightsTable() { diff --git a/src/app/(main)/reports/insights/page.tsx b/src/app/(main)/reports/insights/page.tsx index e09565c0..cb3b9016 100644 --- a/src/app/(main)/reports/insights/page.tsx +++ b/src/app/(main)/reports/insights/page.tsx @@ -1,8 +1,8 @@ -import InsightsReport from './InsightsReport'; +import InsightsReportPage from './InsightsReportPage'; import { Metadata } from 'next'; -export default function InsightsReportPage() { - return ; +export default function () { + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/reports/page.tsx b/src/app/(main)/reports/page.tsx index 0dc380a9..44a034a0 100644 --- a/src/app/(main)/reports/page.tsx +++ b/src/app/(main)/reports/page.tsx @@ -1,14 +1,10 @@ -import ReportsHeader from './ReportsHeader'; -import ReportsDataTable from './ReportsDataTable'; +import ReportsPage from './ReportsPage'; +import { Metadata } from 'next'; export default function ({ params: { teamId } }: { params: { teamId: string } }) { - return ( - <> - - - - ); + return ; } -export const metadata = { + +export const metadata: Metadata = { title: 'Reports | Umami', }; diff --git a/src/app/(main)/reports/retention/RetentionParameters.tsx b/src/app/(main)/reports/retention/RetentionParameters.tsx index 16955338..461dd90b 100644 --- a/src/app/(main)/reports/retention/RetentionParameters.tsx +++ b/src/app/(main)/reports/retention/RetentionParameters.tsx @@ -1,8 +1,7 @@ -'use client'; import { useContext } from 'react'; import { useMessages } from 'components/hooks'; import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import { MonthSelect } from 'components/input/MonthSelect'; import BaseParameters from '../[reportId]/BaseParameters'; import { parseDateRange } from 'lib/date'; diff --git a/src/app/(main)/reports/retention/RetentionReport.tsx b/src/app/(main)/reports/retention/RetentionReport.tsx index f02e5bb1..37fc5820 100644 --- a/src/app/(main)/reports/retention/RetentionReport.tsx +++ b/src/app/(main)/reports/retention/RetentionReport.tsx @@ -1,7 +1,6 @@ -'use client'; import RetentionTable from './RetentionTable'; import RetentionParameters from './RetentionParameters'; -import Report from '../[reportId]/Report'; +import ReportPage from '../[reportId]/ReportPage'; import ReportHeader from '../[reportId]/ReportHeader'; import ReportMenu from '../[reportId]/ReportMenu'; import ReportBody from '../[reportId]/ReportBody'; @@ -21,7 +20,7 @@ const defaultParameters = { export default function RetentionReport({ reportId }: { reportId?: string }) { return ( - + } /> @@ -29,6 +28,6 @@ export default function RetentionReport({ reportId }: { reportId?: string }) { - + ); } diff --git a/src/app/(main)/reports/retention/RetentionReportPage.tsx b/src/app/(main)/reports/retention/RetentionReportPage.tsx new file mode 100644 index 00000000..f2500fb2 --- /dev/null +++ b/src/app/(main)/reports/retention/RetentionReportPage.tsx @@ -0,0 +1,6 @@ +'use client'; +import RetentionReport from './RetentionReport'; + +export default function RetentionReportPage() { + return ; +} diff --git a/src/app/(main)/reports/retention/RetentionTable.tsx b/src/app/(main)/reports/retention/RetentionTable.tsx index b4384893..2ad36177 100644 --- a/src/app/(main)/reports/retention/RetentionTable.tsx +++ b/src/app/(main)/reports/retention/RetentionTable.tsx @@ -1,7 +1,6 @@ -'use client'; import { useContext } from 'react'; import classNames from 'classnames'; -import { ReportContext } from '../[reportId]/Report'; +import { ReportContext } from '../[reportId]/ReportPage'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import { useMessages, useLocale } from 'components/hooks'; import { formatDate } from 'lib/date'; diff --git a/src/app/(main)/reports/retention/page.tsx b/src/app/(main)/reports/retention/page.tsx index 41784372..81071403 100644 --- a/src/app/(main)/reports/retention/page.tsx +++ b/src/app/(main)/reports/retention/page.tsx @@ -1,8 +1,8 @@ import { Metadata } from 'next'; -import RetentionReport from './RetentionReport'; +import RetentionReportPage from './RetentionReportPage'; -export default function RetentionReportPage() { - return ; +export default function () { + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/settings/Settings.tsx b/src/app/(main)/settings/SettingsLayout.tsx similarity index 72% rename from src/app/(main)/settings/Settings.tsx rename to src/app/(main)/settings/SettingsLayout.tsx index 85e9caee..28e9a074 100644 --- a/src/app/(main)/settings/Settings.tsx +++ b/src/app/(main)/settings/SettingsLayout.tsx @@ -1,9 +1,9 @@ 'use client'; import { ReactNode } from 'react'; import { useLogin, useMessages } from 'components/hooks'; -import SettingsLayout from 'components/layout/SettingsLayout'; +import MenuLayout from 'components/layout/MenuLayout'; -export default function Settings({ children }: { children: ReactNode }) { +export default function SettingsLayout({ children }: { children: ReactNode }) { const { user } = useLogin(); const { formatMessage, labels } = useMessages(); @@ -21,5 +21,5 @@ export default function Settings({ children }: { children: ReactNode }) { }, ].filter(n => n); - return {children}; + return {children}; } diff --git a/src/app/(main)/settings/layout.tsx b/src/app/(main)/settings/layout.tsx index 6829e966..eb382e3b 100644 --- a/src/app/(main)/settings/layout.tsx +++ b/src/app/(main)/settings/layout.tsx @@ -1,5 +1,5 @@ -import Settings from './Settings'; +import SettingsLayout from './SettingsLayout'; export default function ({ children }) { - return {children}; + return {children}; } diff --git a/src/app/(main)/settings/teams/TeamAddForm.tsx b/src/app/(main)/settings/teams/TeamAddForm.tsx index a3caf25f..9bcf7840 100644 --- a/src/app/(main)/settings/teams/TeamAddForm.tsx +++ b/src/app/(main)/settings/teams/TeamAddForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { Form, FormRow, diff --git a/src/app/(main)/settings/teams/TeamJoinForm.tsx b/src/app/(main)/settings/teams/TeamJoinForm.tsx index b448a368..385ff1df 100644 --- a/src/app/(main)/settings/teams/TeamJoinForm.tsx +++ b/src/app/(main)/settings/teams/TeamJoinForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useRef } from 'react'; import { Form, diff --git a/src/app/(main)/settings/teams/TeamLeaveButton.tsx b/src/app/(main)/settings/teams/TeamLeaveButton.tsx index db9dc050..8b246a3b 100644 --- a/src/app/(main)/settings/teams/TeamLeaveButton.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { useMessages, useLocale, useLogin } from 'components/hooks'; import TeamDeleteForm from './TeamLeaveForm'; diff --git a/src/app/(main)/settings/teams/TeamLeaveForm.tsx b/src/app/(main)/settings/teams/TeamLeaveForm.tsx index eba448f1..466fbab3 100644 --- a/src/app/(main)/settings/teams/TeamLeaveForm.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import { touch } from 'store/modified'; import ConfirmationForm from 'components/common/ConfirmationForm'; diff --git a/src/app/(main)/settings/teams/TeamsAddButton.tsx b/src/app/(main)/settings/teams/TeamsAddButton.tsx index 94519358..871cdb76 100644 --- a/src/app/(main)/settings/teams/TeamsAddButton.tsx +++ b/src/app/(main)/settings/teams/TeamsAddButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Modal, ModalTrigger, Text } from 'react-basics'; import Icons from 'components/icons'; import { useMessages } from 'components/hooks'; diff --git a/src/app/(main)/settings/teams/TeamsDataTable.tsx b/src/app/(main)/settings/teams/TeamsDataTable.tsx index c48617f2..1890af8a 100644 --- a/src/app/(main)/settings/teams/TeamsDataTable.tsx +++ b/src/app/(main)/settings/teams/TeamsDataTable.tsx @@ -1,4 +1,3 @@ -'use client'; import DataTable from 'components/common/DataTable'; import TeamsTable from 'app/(main)/settings/teams/TeamsTable'; import { useTeams } from 'components/hooks'; diff --git a/src/app/(main)/settings/teams/TeamsHeader.tsx b/src/app/(main)/settings/teams/TeamsHeader.tsx index 0148d97b..4c040691 100644 --- a/src/app/(main)/settings/teams/TeamsHeader.tsx +++ b/src/app/(main)/settings/teams/TeamsHeader.tsx @@ -1,4 +1,3 @@ -'use client'; import { Flexbox } from 'react-basics'; import PageHeader from 'components/layout/PageHeader'; import { ROLES } from 'lib/constants'; diff --git a/src/app/(main)/settings/teams/TeamsJoinButton.tsx b/src/app/(main)/settings/teams/TeamsJoinButton.tsx index 04bb9824..45a2142e 100644 --- a/src/app/(main)/settings/teams/TeamsJoinButton.tsx +++ b/src/app/(main)/settings/teams/TeamsJoinButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import Icons from 'components/icons'; import { useMessages } from 'components/hooks'; diff --git a/src/app/(main)/settings/teams/TeamsPage.tsx b/src/app/(main)/settings/teams/TeamsPage.tsx new file mode 100644 index 00000000..33ddda3d --- /dev/null +++ b/src/app/(main)/settings/teams/TeamsPage.tsx @@ -0,0 +1,12 @@ +'use client'; +import TeamsDataTable from './TeamsDataTable'; +import TeamsHeader from './TeamsHeader'; + +export default function TeamsPage() { + return ( + <> + + + + ); +} diff --git a/src/app/(main)/settings/teams/TeamsTable.tsx b/src/app/(main)/settings/teams/TeamsTable.tsx index 65d79e51..787d51c7 100644 --- a/src/app/(main)/settings/teams/TeamsTable.tsx +++ b/src/app/(main)/settings/teams/TeamsTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { GridColumn, GridTable, Icon, Text, useBreakpoint } from 'react-basics'; import { useMessages } from 'components/hooks'; import Icons from 'components/icons'; diff --git a/src/app/(main)/settings/teams/WebsiteTags.tsx b/src/app/(main)/settings/teams/WebsiteTags.tsx index 9e71e3d6..4a0f109d 100644 --- a/src/app/(main)/settings/teams/WebsiteTags.tsx +++ b/src/app/(main)/settings/teams/WebsiteTags.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Icons, Text } from 'react-basics'; import styles from './WebsiteTags.module.css'; diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx index bae0e723..0b4ca500 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; import { touch } from 'store/modified'; diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersDataTable.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersDataTable.tsx index ff95e522..996283a7 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersDataTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersDataTable.tsx @@ -1,4 +1,3 @@ -'use client'; import DataTable from 'components/common/DataTable'; import TeamMembersTable from './TeamMembersTable'; import { useTeamMembers } from 'components/hooks'; diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMembers.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx similarity index 62% rename from src/app/(main)/settings/teams/[teamId]/members/TeamMembers.tsx rename to src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx index 34cb248c..ef0e12d1 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMembers.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx @@ -1,17 +1,18 @@ 'use client'; +import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; import TeamMembersDataTable from './TeamMembersDataTable'; import PageHeader from 'components/layout/PageHeader'; import { useMessages } from 'components/hooks'; -export function TeamMembers({ teamId }: { teamId: string }) { +export function TeamMembersPage({ teamId }: { teamId: string }) { const { formatMessage, labels } = useMessages(); return ( - <> + - + ); } -export default TeamMembers; +export default TeamMembersPage; diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx index aceb5894..d993bbc0 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { GridColumn, GridTable, useBreakpoint } from 'react-basics'; import { useMessages, useLogin } from 'components/hooks'; import { ROLES } from 'lib/constants'; diff --git a/src/app/(main)/settings/teams/[teamId]/members/page.tsx b/src/app/(main)/settings/teams/[teamId]/members/page.tsx index 295b3f15..e36e9214 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/page.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/page.tsx @@ -1,13 +1,8 @@ -import TeamMembers from './TeamMembers'; -import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; +import TeamMembersPage from './TeamMembersPage'; import { Metadata } from 'next'; export default function ({ params: { teamId } }) { - return ( - - - - ); + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx index ff20989a..582012d4 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx @@ -1,4 +1,3 @@ -'use client'; import { ActionForm, Button, Modal, ModalTrigger } from 'react-basics'; import { useMessages } from 'components/hooks'; import TeamDeleteForm from './TeamDeleteForm'; diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx index aa2b1d3f..33694495 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import { touch } from 'store/modified'; import TypeConfirmationForm from 'components/common/TypeConfirmationForm'; diff --git a/src/app/(main)/settings/teams/[teamId]/team/Team.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx similarity index 94% rename from src/app/(main)/settings/teams/[teamId]/team/Team.tsx rename to src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx index 18e0c014..4162e83f 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/Team.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx @@ -1,4 +1,3 @@ -'use client'; import { useContext, useState } from 'react'; import { Item, Tabs, Flexbox, Text, Icon } from 'react-basics'; import PageHeader from 'components/layout/PageHeader'; @@ -10,7 +9,7 @@ import TeamAdmin from './TeamAdmin'; import LinkButton from 'components/common/LinkButton'; import { TeamContext } from 'app/(main)/teams/[teamId]/TeamProvider'; -export function Team({ teamId }: { teamId: string }) { +export function TeamDetails({ teamId }: { teamId: string }) { const team = useContext(TeamContext); const { formatMessage, labels } = useMessages(); const { user } = useLogin(); @@ -42,4 +41,4 @@ export function Team({ teamId }: { teamId: string }) { ); } -export default Team; +export default TeamDetails; diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx index 7e158191..cee3c3f1 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { SubmitButton, Form, diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamPage.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamPage.tsx new file mode 100644 index 00000000..82abcf8d --- /dev/null +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamPage.tsx @@ -0,0 +1,13 @@ +'use client'; +import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; +import TeamDetails from './TeamDetails'; + +export function TeamMembersPage({ teamId }: { teamId: string }) { + return ( + + + + ); +} + +export default TeamMembersPage; diff --git a/src/app/(main)/settings/teams/[teamId]/team/page.tsx b/src/app/(main)/settings/teams/[teamId]/team/page.tsx index e23b670e..de2c9657 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/page.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/page.tsx @@ -1,13 +1,8 @@ -import Team from './Team'; -import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; import { Metadata } from 'next'; +import TeamPage from './TeamPage'; export default function ({ params: { teamId } }) { - return ( - - - - ); + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsiteRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsiteRemoveButton.tsx index 843b76d3..336e151a 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsiteRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsiteRemoveButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesDataTable.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesDataTable.tsx index 794ce948..9e2985d4 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesDataTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesDataTable.tsx @@ -1,4 +1,3 @@ -'use client'; import DataTable from 'components/common/DataTable'; import { useTeamWebsites } from 'components/hooks'; import TeamWebsitesTable from './TeamWebsitesTable'; diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsites.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx similarity index 62% rename from src/app/(main)/settings/teams/[teamId]/websites/TeamWebsites.tsx rename to src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx index 36f8d39b..56582c04 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsites.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx @@ -1,17 +1,18 @@ 'use client'; +import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; import TeamWebsitesDataTable from './TeamWebsitesDataTable'; import PageHeader from 'components/layout/PageHeader'; import { useMessages } from 'components/hooks'; -export function TeamWebsites({ teamId }: { teamId: string }) { +export function TeamWebsitesPage({ teamId }: { teamId: string }) { const { formatMessage, labels } = useMessages(); return ( - <> + - + ); } -export default TeamWebsites; +export default TeamWebsitesPage; diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx index 0d54763e..b07f3dbf 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { GridColumn, GridTable, Icon, Text } from 'react-basics'; import { useLogin, useMessages } from 'components/hooks'; import Icons from 'components/icons'; diff --git a/src/app/(main)/settings/teams/[teamId]/websites/page.tsx b/src/app/(main)/settings/teams/[teamId]/websites/page.tsx index 31b02065..ac4eb94f 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/page.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/page.tsx @@ -1,15 +1,10 @@ -import TeamWebsites from './TeamWebsites'; -import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; +import TeamWebsitesPage from './TeamWebsitesPage'; import { Metadata } from 'next'; export default function ({ params: { teamId } }) { - return ( - - - - ); + return ; } export const metadata: Metadata = { - title: 'Teams websites - Umami', + title: 'Teams Websites - Umami', }; diff --git a/src/app/(main)/settings/teams/page.tsx b/src/app/(main)/settings/teams/page.tsx index 98ce95fb..e45d6f2d 100644 --- a/src/app/(main)/settings/teams/page.tsx +++ b/src/app/(main)/settings/teams/page.tsx @@ -1,14 +1,8 @@ import { Metadata } from 'next'; -import TeamsDataTable from './TeamsDataTable'; -import TeamsHeader from './TeamsHeader'; +import TeamsPage from './TeamsPage'; export default function () { - return ( - <> - - - - ); + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/settings/users/UserAddButton.tsx b/src/app/(main)/settings/users/UserAddButton.tsx index 57f2ebc5..5746ff2a 100644 --- a/src/app/(main)/settings/users/UserAddButton.tsx +++ b/src/app/(main)/settings/users/UserAddButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Text, Modal, Icons, ModalTrigger, useToasts } from 'react-basics'; import UserAddForm from './UserAddForm'; import { useMessages } from 'components/hooks'; diff --git a/src/app/(main)/settings/users/UserAddForm.tsx b/src/app/(main)/settings/users/UserAddForm.tsx index 0632165c..7ea72007 100644 --- a/src/app/(main)/settings/users/UserAddForm.tsx +++ b/src/app/(main)/settings/users/UserAddForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { Dropdown, Item, diff --git a/src/app/(main)/settings/users/UserDeleteButton.tsx b/src/app/(main)/settings/users/UserDeleteButton.tsx index cdfde6ae..9f1f8459 100644 --- a/src/app/(main)/settings/users/UserDeleteButton.tsx +++ b/src/app/(main)/settings/users/UserDeleteButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { useMessages, useLogin } from 'components/hooks'; import UserDeleteForm from './UserDeleteForm'; diff --git a/src/app/(main)/settings/users/UserDeleteForm.tsx b/src/app/(main)/settings/users/UserDeleteForm.tsx index 0cce8d6d..97caf644 100644 --- a/src/app/(main)/settings/users/UserDeleteForm.tsx +++ b/src/app/(main)/settings/users/UserDeleteForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import ConfirmationForm from 'components/common/ConfirmationForm'; import { touch } from 'store/modified'; diff --git a/src/app/(main)/settings/users/UserEditForm.tsx b/src/app/(main)/settings/users/UserEditForm.tsx index 53384285..12c5afbc 100644 --- a/src/app/(main)/settings/users/UserEditForm.tsx +++ b/src/app/(main)/settings/users/UserEditForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { Dropdown, Item, diff --git a/src/app/(main)/settings/users/UsersDataTable.tsx b/src/app/(main)/settings/users/UsersDataTable.tsx index a8e46cda..cfff4e71 100644 --- a/src/app/(main)/settings/users/UsersDataTable.tsx +++ b/src/app/(main)/settings/users/UsersDataTable.tsx @@ -1,4 +1,3 @@ -'use client'; import DataTable from 'components/common/DataTable'; import { useUsers } from 'components/hooks'; import UsersTable from './UsersTable'; diff --git a/src/app/(main)/settings/users/UsersHeader.tsx b/src/app/(main)/settings/users/UsersHeader.tsx index 20c5f898..6f4387c7 100644 --- a/src/app/(main)/settings/users/UsersHeader.tsx +++ b/src/app/(main)/settings/users/UsersHeader.tsx @@ -1,4 +1,3 @@ -'use client'; import PageHeader from 'components/layout/PageHeader'; import { useMessages } from 'components/hooks'; import UserAddButton from './UserAddButton'; diff --git a/src/app/(main)/settings/users/UsersPage.tsx b/src/app/(main)/settings/users/UsersPage.tsx new file mode 100644 index 00000000..348c5a33 --- /dev/null +++ b/src/app/(main)/settings/users/UsersPage.tsx @@ -0,0 +1,12 @@ +'use client'; +import UsersDataTable from './UsersDataTable'; +import UsersHeader from './UsersHeader'; + +export default function UsersPage() { + return ( + <> + + + + ); +} diff --git a/src/app/(main)/settings/users/UsersTable.tsx b/src/app/(main)/settings/users/UsersTable.tsx index 523bd01c..88effa54 100644 --- a/src/app/(main)/settings/users/UsersTable.tsx +++ b/src/app/(main)/settings/users/UsersTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; import { formatDistance } from 'date-fns'; import { ROLES } from 'lib/constants'; diff --git a/src/app/(main)/settings/users/[userId]/UserPage.tsx b/src/app/(main)/settings/users/[userId]/UserPage.tsx new file mode 100644 index 00000000..285433eb --- /dev/null +++ b/src/app/(main)/settings/users/[userId]/UserPage.tsx @@ -0,0 +1,6 @@ +'use client'; +import UserSettings from './UserSettings'; + +export default function ({ userId }: { userId: string }) { + return ; +} diff --git a/src/app/(main)/settings/users/[userId]/UserSettings.tsx b/src/app/(main)/settings/users/[userId]/UserSettings.tsx index eda38089..50a36487 100644 --- a/src/app/(main)/settings/users/[userId]/UserSettings.tsx +++ b/src/app/(main)/settings/users/[userId]/UserSettings.tsx @@ -1,4 +1,3 @@ -'use client'; import { Key, useState } from 'react'; import { Item, Loading, Tabs } from 'react-basics'; import Icons from 'components/icons'; diff --git a/src/app/(main)/settings/users/[userId]/UserWebsites.tsx b/src/app/(main)/settings/users/[userId]/UserWebsites.tsx index 429195cd..bfc6f74b 100644 --- a/src/app/(main)/settings/users/[userId]/UserWebsites.tsx +++ b/src/app/(main)/settings/users/[userId]/UserWebsites.tsx @@ -1,4 +1,3 @@ -'use client'; import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable'; import DataTable from 'components/common/DataTable'; import { useWebsites } from 'components/hooks'; diff --git a/src/app/(main)/settings/users/[userId]/page.tsx b/src/app/(main)/settings/users/[userId]/page.tsx index 2e2e4137..414ad483 100644 --- a/src/app/(main)/settings/users/[userId]/page.tsx +++ b/src/app/(main)/settings/users/[userId]/page.tsx @@ -1,5 +1,10 @@ -import UserSettings from './UserSettings'; +import UserPage from './UserPage'; +import { Metadata } from 'next'; export default function ({ params: { userId } }) { - return ; + return ; } + +export const metadata: Metadata = { + title: 'User Settings - Umami', +}; diff --git a/src/app/(main)/settings/users/page.tsx b/src/app/(main)/settings/users/page.tsx index 0be95a0d..fa63cf18 100644 --- a/src/app/(main)/settings/users/page.tsx +++ b/src/app/(main)/settings/users/page.tsx @@ -1,14 +1,8 @@ import { Metadata } from 'next'; -import UsersDataTable from './UsersDataTable'; -import UsersHeader from './UsersHeader'; +import UsersPage from './UsersPage'; export default function () { - return ( - <> - - - - ); + return ; } export const metadata: Metadata = { title: 'Users | Umami', diff --git a/src/app/(main)/settings/websites/WebsiteAddButton.tsx b/src/app/(main)/settings/websites/WebsiteAddButton.tsx index 90fc15b1..35e9bbc3 100644 --- a/src/app/(main)/settings/websites/WebsiteAddButton.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import WebsiteAddForm from './WebsiteAddForm'; import { useMessages } from 'components/hooks'; diff --git a/src/app/(main)/settings/websites/WebsiteAddForm.tsx b/src/app/(main)/settings/websites/WebsiteAddForm.tsx index 55054cd4..88cbb4ff 100644 --- a/src/app/(main)/settings/websites/WebsiteAddForm.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { Form, FormRow, diff --git a/src/app/(main)/settings/websites/WebsitesDataTable.tsx b/src/app/(main)/settings/websites/WebsitesDataTable.tsx index 18502244..a9d99f9a 100644 --- a/src/app/(main)/settings/websites/WebsitesDataTable.tsx +++ b/src/app/(main)/settings/websites/WebsitesDataTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { ReactNode } from 'react'; import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable'; import DataTable from 'components/common/DataTable'; diff --git a/src/app/(main)/settings/websites/WebsitesHeader.tsx b/src/app/(main)/settings/websites/WebsitesHeader.tsx index 3ffc1a95..e0d3860a 100644 --- a/src/app/(main)/settings/websites/WebsitesHeader.tsx +++ b/src/app/(main)/settings/websites/WebsitesHeader.tsx @@ -1,4 +1,3 @@ -'use client'; import { useMessages } from 'components/hooks'; import PageHeader from 'components/layout/PageHeader'; import WebsiteAddButton from './WebsiteAddButton'; diff --git a/src/app/(main)/settings/websites/Websites.tsx b/src/app/(main)/settings/websites/WebsitesPage.tsx similarity index 70% rename from src/app/(main)/settings/websites/Websites.tsx rename to src/app/(main)/settings/websites/WebsitesPage.tsx index ffa197ad..4de8f105 100644 --- a/src/app/(main)/settings/websites/Websites.tsx +++ b/src/app/(main)/settings/websites/WebsitesPage.tsx @@ -3,12 +3,12 @@ import { useLogin } from 'components/hooks'; import WebsitesDataTable from './WebsitesDataTable'; import WebsitesHeader from './WebsitesHeader'; -export default function Websites({ teamId }: { teamId: string }) { +export default function WebsitesPage({ teamId }: { teamId: string }) { const { user } = useLogin(); return ( <> - + ); diff --git a/src/app/(main)/settings/websites/WebsitesTable.tsx b/src/app/(main)/settings/websites/WebsitesTable.tsx index 1f1353c0..cbd5e3a7 100644 --- a/src/app/(main)/settings/websites/WebsitesTable.tsx +++ b/src/app/(main)/settings/websites/WebsitesTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { ReactNode } from 'react'; import { Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; import { useMessages, useTeamUrl } from 'components/hooks'; diff --git a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx index 13c07dd1..6fb543d0 100644 --- a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx @@ -1,4 +1,3 @@ -'use client'; import { Form, FormRow, diff --git a/src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx b/src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx index 0995c8ca..66222349 100644 --- a/src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/TrackingCode.tsx @@ -1,4 +1,3 @@ -'use client'; import { TextArea } from 'react-basics'; import { useMessages, useConfig } from 'components/hooks'; diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx index d22c0608..4dd5fde4 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Modal, ModalTrigger, ActionForm, useToasts } from 'react-basics'; import { useRouter } from 'next/navigation'; import { useMessages } from 'components/hooks'; diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx index be703d91..19755205 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import TypeConfirmationForm from 'components/common/TypeConfirmationForm'; diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx index cd4fb5d7..53f27b26 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useContext, useRef } from 'react'; import { SubmitButton, diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsitePage.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsitePage.tsx new file mode 100644 index 00000000..752fd33c --- /dev/null +++ b/src/app/(main)/settings/websites/[websiteId]/WebsitePage.tsx @@ -0,0 +1,11 @@ +'use client'; +import WebsiteProvider from 'app/(main)/websites/[websiteId]/WebsiteProvider'; +import WebsiteSettings from './WebsiteSettings'; + +export default function WebsitePage({ websiteId }: { websiteId: string }) { + return ( + + + + ); +} diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteResetForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteResetForm.tsx index f96a705c..c43f3efb 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteResetForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteResetForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { useApi, useMessages } from 'components/hooks'; import TypeConfirmationForm from 'components/common/TypeConfirmationForm'; diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx index fcb6316b..24bf3d02 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx @@ -1,4 +1,3 @@ -'use client'; import { useState, Key, useContext } from 'react'; import { Item, Tabs, Button, Text, Icon } from 'react-basics'; import Link from 'next/link'; diff --git a/src/app/(main)/settings/websites/[websiteId]/page.tsx b/src/app/(main)/settings/websites/[websiteId]/page.tsx index fe6fc69d..b8eb8530 100644 --- a/src/app/(main)/settings/websites/[websiteId]/page.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/page.tsx @@ -1,10 +1,10 @@ -import WebsiteProvider from 'app/(main)/websites/[websiteId]/WebsiteProvider'; -import WebsiteSettings from './WebsiteSettings'; +import WebsitePage from './WebsitePage'; +import { Metadata } from 'next'; -export default async function WebsiteSettingsPage({ params: { websiteId } }) { - return ( - - - - ); +export default async function ({ params: { websiteId } }) { + return ; } + +export const metadata: Metadata = { + title: 'Website settings - Umami', +}; diff --git a/src/app/(main)/settings/websites/page.tsx b/src/app/(main)/settings/websites/page.tsx index 70c64dd3..50a2df87 100644 --- a/src/app/(main)/settings/websites/page.tsx +++ b/src/app/(main)/settings/websites/page.tsx @@ -1,8 +1,8 @@ import { Metadata } from 'next'; -import Websites from './Websites'; +import WebsitesPage from './WebsitesPage'; export default function ({ params: { teamId } }: { params: { teamId: string } }) { - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/teams/[teamId]/TeamProvider.tsx b/src/app/(main)/teams/[teamId]/TeamProvider.tsx index a456f987..6f0e391b 100644 --- a/src/app/(main)/teams/[teamId]/TeamProvider.tsx +++ b/src/app/(main)/teams/[teamId]/TeamProvider.tsx @@ -1,4 +1,3 @@ -'use client'; import { createContext, ReactNode, useEffect } from 'react'; import { useTeam } from 'components/hooks'; import { Loading } from 'react-basics'; diff --git a/src/app/(main)/teams/[teamId]/layout.tsx b/src/app/(main)/teams/[teamId]/layout.tsx deleted file mode 100644 index f18d802a..00000000 --- a/src/app/(main)/teams/[teamId]/layout.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import TeamProvider from './TeamProvider'; - -export default function ({ children, params: { teamId } }) { - return {children}; -} diff --git a/src/app/(main)/teams/[teamId]/settings/TeamSettings.tsx b/src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx similarity index 83% rename from src/app/(main)/teams/[teamId]/settings/TeamSettings.tsx rename to src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx index 4be58432..5c2f2502 100644 --- a/src/app/(main)/teams/[teamId]/settings/TeamSettings.tsx +++ b/src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx @@ -1,6 +1,6 @@ 'use client'; import { ReactNode } from 'react'; -import SettingsLayout from 'components/layout/SettingsLayout'; +import MenuLayout from 'components/layout/MenuLayout'; import { useMessages } from 'components/hooks'; export default function ({ children, teamId }: { children: ReactNode; teamId: string }) { @@ -24,5 +24,5 @@ export default function ({ children, teamId }: { children: ReactNode; teamId: st }, ].filter(n => n); - return {children}; + return {children}; } diff --git a/src/app/(main)/teams/[teamId]/settings/layout.tsx b/src/app/(main)/teams/[teamId]/settings/layout.tsx index a72ce3b7..c86d0196 100644 --- a/src/app/(main)/teams/[teamId]/settings/layout.tsx +++ b/src/app/(main)/teams/[teamId]/settings/layout.tsx @@ -1,5 +1,5 @@ -import TeamSettings from './TeamSettings'; +import TeamSettingsLayout from './TeamSettingsLayout'; export default function ({ children, params: { teamId } }) { - return {children}; + return {children}; } diff --git a/src/app/(main)/websites/Websites.tsx b/src/app/(main)/websites/Websites.tsx deleted file mode 100644 index 8769d6ad..00000000 --- a/src/app/(main)/websites/Websites.tsx +++ /dev/null @@ -1,8 +0,0 @@ -'use client'; -import WebsitesDataTable from '../settings/websites/WebsitesDataTable'; - -export function Websites({ teamId, userId }: { teamId: string; userId: string }) { - return ; -} - -export default Websites; diff --git a/src/app/(main)/websites/WebsitesPage.tsx b/src/app/(main)/websites/WebsitesPage.tsx new file mode 100644 index 00000000..fa2e9f71 --- /dev/null +++ b/src/app/(main)/websites/WebsitesPage.tsx @@ -0,0 +1,12 @@ +'use client'; +import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader'; +import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable'; + +export default function WebsitesPage({ teamId, userId }: { teamId: string; userId: string }) { + return ( + <> + + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index fb04a6ad..c4df6e71 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -1,4 +1,3 @@ -'use client'; import { useMemo } from 'react'; import PageviewsChart from 'components/metrics/PageviewsChart'; import { useApi, useDateRange, useTimezone, useNavigation } from 'components/hooks'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx index 6d069088..b35b6f1f 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Text, Icon, Icons } from 'react-basics'; import { useMemo } from 'react'; import { firstBy } from 'thenby'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteDetails.tsx b/src/app/(main)/websites/[websiteId]/WebsiteDetails.tsx index 0a18c03f..e4203177 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteDetails.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteDetails.tsx @@ -1,10 +1,8 @@ -'use client'; import { Loading } from 'react-basics'; import { usePathname } from 'next/navigation'; import Page from 'components/layout/Page'; import FilterTags from 'components/metrics/FilterTags'; -import { useNavigation } from 'components/hooks'; -import { useWebsite } from 'components/hooks'; +import { useNavigation, useWebsite } from 'components/hooks'; import WebsiteChart from './WebsiteChart'; import WebsiteExpandedView from './WebsiteExpandedView'; import WebsiteHeader from './WebsiteHeader'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx index b47d435b..fcded254 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx @@ -1,4 +1,3 @@ -'use client'; import { Icons, Icon, Text, Dropdown, Item } from 'react-basics'; import BrowsersTable from 'components/metrics/BrowsersTable'; import CountriesTable from 'components/metrics/CountriesTable'; @@ -13,8 +12,7 @@ import ReferrersTable from 'components/metrics/ReferrersTable'; import ScreenTable from 'components/metrics/ScreenTable'; import EventsTable from 'components/metrics/EventsTable'; import SideNav from 'components/layout/SideNav'; -import { useNavigation } from 'components/hooks'; -import { useMessages } from 'components/hooks'; +import { useNavigation, useMessages } from 'components/hooks'; import LinkButton from 'components/common/LinkButton'; import styles from './WebsiteExpandedView.module.css'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx index 25174a53..998c73c4 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx @@ -1,4 +1,3 @@ -'use client'; import { Button, Icon, Icons, Popup, PopupTrigger, Text } from 'react-basics'; import PopupForm from 'app/(main)/reports/[reportId]/PopupForm'; import FilterSelectForm from 'app/(main)/reports/[reportId]/FilterSelectForm'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx index 0af9e596..58ec225a 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx @@ -1,4 +1,3 @@ -'use client'; import { ReactNode } from 'react'; import classNames from 'classnames'; import { Text, Button, Icon } from 'react-basics'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index e4011ea2..3c5c4e9a 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -1,4 +1,3 @@ -'use client'; import classNames from 'classnames'; import { useApi, useDateRange, useMessages, useNavigation, useSticky } from 'components/hooks'; import WebsiteDateFilter from 'components/input/WebsiteDateFilter'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx b/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx index 4ea5a032..e1d3da26 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx @@ -1,4 +1,3 @@ -'use client'; import { createContext, ReactNode, useEffect } from 'react'; import { useWebsite } from 'components/hooks'; import { Loading } from 'react-basics'; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteTableView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteTableView.tsx index 65b432cb..7cc415e5 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteTableView.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteTableView.tsx @@ -1,4 +1,3 @@ -'use client'; import { useState } from 'react'; import { Grid, GridRow } from 'components/layout/Grid'; import PagesTable from 'components/metrics/PagesTable'; diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx index e4903a78..fceb86aa 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx @@ -1,7 +1,5 @@ -'use client'; -import { useApi, useDateRange } from 'components/hooks'; +import { useApi, useDateRange, useMessages } from 'components/hooks'; import MetricCard from 'components/metrics/MetricCard'; -import { useMessages } from 'components/hooks'; import WebsiteDateFilter from 'components/input/WebsiteDateFilter'; import MetricsBar from 'components/metrics/MetricsBar'; import styles from './EventDataMetricsBar.module.css'; diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx index 94b9934e..71c36992 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataTable.tsx @@ -1,4 +1,3 @@ -'use client'; import Link from 'next/link'; import { GridTable, GridColumn } from 'react-basics'; import { useMessages, useNavigation } from 'components/hooks'; diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx index 8b7c8070..edf1fa15 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataValueTable.tsx @@ -1,4 +1,3 @@ -'use client'; import { GridTable, GridColumn, Icon, Text } from 'react-basics'; import { useMessages, useNavigation } from 'components/hooks'; import Icons from 'components/icons'; diff --git a/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx b/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx index 61a4dc62..27ccd96c 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx @@ -1,4 +1,3 @@ -'use client'; import { Flexbox, Loading } from 'react-basics'; import EventDataTable from './EventDataTable'; import EventDataValueTable from './EventDataValueTable'; diff --git a/src/app/(main)/websites/[websiteId]/realtime/Realtime.tsx b/src/app/(main)/websites/[websiteId]/realtime/Realtime.tsx index 3990b820..6314fbb8 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/Realtime.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/Realtime.tsx @@ -1,4 +1,3 @@ -'use client'; import { useMemo, useState, useEffect } from 'react'; import { subMinutes, startOfMinute } from 'date-fns'; import thenby from 'thenby'; @@ -6,8 +5,7 @@ import { Grid, GridRow } from 'components/layout/Grid'; import Page from 'components/layout/Page'; import RealtimeChart from 'components/metrics/RealtimeChart'; import WorldMap from 'components/metrics/WorldMap'; -import { useApi } from 'components/hooks'; -import { useWebsite } from 'components/hooks'; +import { useApi, useWebsite } from 'components/hooks'; import { percentFilter } from 'lib/filters'; import { REALTIME_RANGE, REALTIME_INTERVAL } from 'lib/constants'; import { RealtimeData } from 'lib/types'; diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx index 47417e0d..506d5733 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx @@ -1,9 +1,6 @@ -'use client'; import { useCallback } from 'react'; import ListTable from 'components/metrics/ListTable'; -import { useLocale } from 'components/hooks'; -import { useCountryNames } from 'components/hooks'; -import { useMessages } from 'components/hooks'; +import { useLocale, useCountryNames, useMessages } from 'components/hooks'; import classNames from 'classnames'; import styles from './RealtimeCountries.module.css'; diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx index 228dbc00..80d3d8c6 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx @@ -1,4 +1,3 @@ -'use client'; import MetricCard from 'components/metrics/MetricCard'; import { useMessages } from 'components/hooks'; import { RealtimeData } from 'lib/types'; diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx index ee170c54..0ed5fbde 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx @@ -1,11 +1,9 @@ -'use client'; import { useEffect } from 'react'; import { useRouter } from 'next/navigation'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; -import { useApi } from 'components/hooks'; +import { useApi, useMessages } from 'components/hooks'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; -import { useMessages } from 'components/hooks'; export function RealtimeHome() { const { formatMessage, labels, messages } = useMessages(); diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx index 1380207d..d9aad35b 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx @@ -1,4 +1,3 @@ -'use client'; import { useMemo, useState } from 'react'; import { StatusLight, Icon, Text, SearchField } from 'react-basics'; import { FixedSizeList } from 'react-window'; @@ -7,10 +6,8 @@ import thenby from 'thenby'; import { safeDecodeURI } from 'next-basics'; import FilterButtons from 'components/common/FilterButtons'; import Empty from 'components/common/Empty'; -import { useLocale } from 'components/hooks'; -import { useCountryNames } from 'components/hooks'; +import { useLocale, useCountryNames, useMessages } from 'components/hooks'; import Icons from 'components/icons'; -import { useMessages } from 'components/hooks'; import useFormat from 'components//hooks/useFormat'; import { BROWSERS } from 'lib/constants'; import { stringToColor } from 'lib/format'; diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx index cdd810f7..b3726d6d 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx @@ -1,4 +1,3 @@ -'use client'; import { Key, useMemo, useState } from 'react'; import { ButtonGroup, Button, Flexbox } from 'react-basics'; import thenby from 'thenby'; diff --git a/src/app/(main)/websites/[websiteId]/reports/WebsiteReports.tsx b/src/app/(main)/websites/[websiteId]/reports/WebsiteReports.tsx index 5ea6f614..60c36cc6 100644 --- a/src/app/(main)/websites/[websiteId]/reports/WebsiteReports.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/WebsiteReports.tsx @@ -1,4 +1,3 @@ -'use client'; import Link from 'next/link'; import { Button, Flexbox, Icon, Icons, Text } from 'react-basics'; import { useMessages } from 'components/hooks'; diff --git a/src/app/(main)/websites/page.tsx b/src/app/(main)/websites/page.tsx index 4f4d5e24..ee6e4336 100644 --- a/src/app/(main)/websites/page.tsx +++ b/src/app/(main)/websites/page.tsx @@ -1,14 +1,8 @@ -import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader'; -import Websites from './Websites'; +import WebsitesPage from './WebsitesPage'; import { Metadata } from 'next'; -export default function WebsitesPage({ params: { teamId, userId } }) { - return ( - <> - - - - ); +export default function ({ params: { teamId, userId } }) { + return ; } export const metadata: Metadata = { diff --git a/src/app/login/LoginForm.tsx b/src/app/login/LoginForm.tsx index de92373c..28d79458 100644 --- a/src/app/login/LoginForm.tsx +++ b/src/app/login/LoginForm.tsx @@ -1,4 +1,3 @@ -'use client'; import { Form, FormRow, diff --git a/src/app/login/page.module.css b/src/app/login/LoginPage.module.css similarity index 100% rename from src/app/login/page.module.css rename to src/app/login/LoginPage.module.css diff --git a/src/app/login/LoginPage.tsx b/src/app/login/LoginPage.tsx new file mode 100644 index 00000000..28a3c024 --- /dev/null +++ b/src/app/login/LoginPage.tsx @@ -0,0 +1,17 @@ +'use client'; +import LoginForm from './LoginForm'; +import styles from './LoginPage.module.css'; + +export function LoginPage() { + if (process.env.loginDisabled) { + return null; + } + + return ( +
+ +
+ ); +} + +export default LoginPage; diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index aa2765c9..80543ef6 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,23 +1,7 @@ -import LoginForm from './LoginForm'; import { Metadata } from 'next'; -import styles from './page.module.css'; - -async function getDisabled() { - return !!process.env.LOGIN_DISABLED; -} export default async function LoginPage() { - const disabled = await getDisabled(); - - if (disabled) { - return null; - } - - return ( -
- -
- ); + return ; } export const metadata: Metadata = { diff --git a/src/app/logout/Logout.tsx b/src/app/logout/LogoutPage.tsx similarity index 91% rename from src/app/logout/Logout.tsx rename to src/app/logout/LogoutPage.tsx index a6f43f92..11d96329 100644 --- a/src/app/logout/Logout.tsx +++ b/src/app/logout/LogoutPage.tsx @@ -5,7 +5,7 @@ import { useApi } from 'components/hooks'; import { setUser } from 'store/app'; import { removeClientAuthToken } from 'lib/client'; -export function Logout() { +export function LogoutPage() { const disabled = !!(process.env.disableLogin || process.env.cloudMode); const router = useRouter(); const { post } = useApi(); @@ -29,4 +29,4 @@ export function Logout() { return null; } -export default Logout; +export default LogoutPage; diff --git a/src/app/logout/page.tsx b/src/app/logout/page.tsx index 11ee9b67..b74f6584 100644 --- a/src/app/logout/page.tsx +++ b/src/app/logout/page.tsx @@ -1,8 +1,8 @@ -import Logout from './Logout'; +import LogoutPage from './LogoutPage'; import { Metadata } from 'next'; export default function () { - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/page.tsx b/src/app/page.tsx index 6a146801..4977c99b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,4 +1,3 @@ -'use client'; import { redirect } from 'next/navigation'; export default function RootPage() { diff --git a/src/app/share/[...shareId]/Footer.tsx b/src/app/share/[...shareId]/Footer.tsx index 84d4162f..3a07c12a 100644 --- a/src/app/share/[...shareId]/Footer.tsx +++ b/src/app/share/[...shareId]/Footer.tsx @@ -1,4 +1,3 @@ -'use client'; import { CURRENT_VERSION, HOMEPAGE_URL } from 'lib/constants'; import styles from './Footer.module.css'; diff --git a/src/app/share/[...shareId]/Header.tsx b/src/app/share/[...shareId]/Header.tsx index 2b82908d..ddfb52a5 100644 --- a/src/app/share/[...shareId]/Header.tsx +++ b/src/app/share/[...shareId]/Header.tsx @@ -1,4 +1,3 @@ -'use client'; import { Icon, Text } from 'react-basics'; import Link from 'next/link'; import LanguageButton from 'components/input/LanguageButton'; diff --git a/src/app/share/[...shareId]/Share.module.css b/src/app/share/[...shareId]/SharePage.module.css similarity index 100% rename from src/app/share/[...shareId]/Share.module.css rename to src/app/share/[...shareId]/SharePage.module.css diff --git a/src/app/share/[...shareId]/Share.tsx b/src/app/share/[...shareId]/SharePage.tsx similarity index 73% rename from src/app/share/[...shareId]/Share.tsx rename to src/app/share/[...shareId]/SharePage.tsx index d8b83fe7..b49d36ec 100644 --- a/src/app/share/[...shareId]/Share.tsx +++ b/src/app/share/[...shareId]/SharePage.tsx @@ -1,12 +1,12 @@ 'use client'; -import WebsiteDetails from '../../(main)/websites/[websiteId]/WebsiteDetails'; +import WebsiteDetails from 'app/(main)/websites/[websiteId]/WebsiteDetails'; import { useShareToken } from 'components/hooks'; -import styles from './Share.module.css'; import Page from 'components/layout/Page'; import Header from './Header'; import Footer from './Footer'; +import styles from './SharePage.module.css'; -export default function Share({ shareId }) { +export default function SharePage({ shareId }) { const { shareToken, isLoading } = useShareToken(shareId); if (isLoading || !shareToken) { diff --git a/src/app/share/[...shareId]/page.tsx b/src/app/share/[...shareId]/page.tsx index 5a0b2822..02d244e9 100644 --- a/src/app/share/[...shareId]/page.tsx +++ b/src/app/share/[...shareId]/page.tsx @@ -1,8 +1,8 @@ -import Share from './Share'; +import SharePage from './SharePage'; import { Metadata } from 'next'; export default function ({ params: { shareId } }) { - return ; + return ; } export const metadata: Metadata = { diff --git a/src/components/common/ErrorBoundary.tsx b/src/components/common/ErrorBoundary.tsx index 6bb1f4ed..9669580f 100644 --- a/src/components/common/ErrorBoundary.tsx +++ b/src/components/common/ErrorBoundary.tsx @@ -1,4 +1,3 @@ -'use client'; import { ErrorInfo, ReactNode } from 'react'; import { ErrorBoundary as Boundary } from 'react-error-boundary'; import { Button } from 'react-basics'; diff --git a/src/components/hooks/queries/useApi.ts b/src/components/hooks/queries/useApi.ts index 88427bc7..e806d37e 100644 --- a/src/components/hooks/queries/useApi.ts +++ b/src/components/hooks/queries/useApi.ts @@ -1,4 +1,3 @@ -'use client'; import * as reactQuery from '@tanstack/react-query'; import { useApi as nextUseApi } from 'next-basics'; import { getClientAuthToken } from 'lib/client'; diff --git a/src/components/hooks/queries/useConfig.ts b/src/components/hooks/queries/useConfig.ts index 505a93f3..72fe095d 100644 --- a/src/components/hooks/queries/useConfig.ts +++ b/src/components/hooks/queries/useConfig.ts @@ -1,4 +1,3 @@ -'use client'; import { useEffect } from 'react'; import useStore, { setConfig } from 'store/app'; import { useApi } from './useApi'; diff --git a/src/components/hooks/queries/useFilterQuery.ts b/src/components/hooks/queries/useFilterQuery.ts index 5d86c724..7e4c9a86 100644 --- a/src/components/hooks/queries/useFilterQuery.ts +++ b/src/components/hooks/queries/useFilterQuery.ts @@ -1,4 +1,3 @@ -'use client'; import { UseQueryOptions } from '@tanstack/react-query'; import { useState, Dispatch, SetStateAction } from 'react'; import { useApi } from './useApi'; diff --git a/src/components/hooks/queries/useLogin.ts b/src/components/hooks/queries/useLogin.ts index 2f777a77..c17687b0 100644 --- a/src/components/hooks/queries/useLogin.ts +++ b/src/components/hooks/queries/useLogin.ts @@ -1,4 +1,3 @@ -'use client'; import useStore, { setUser } from 'store/app'; import useApi from './useApi'; import { UseQueryResult } from '@tanstack/react-query'; diff --git a/src/components/hooks/queries/useReport.ts b/src/components/hooks/queries/useReport.ts index 332ba755..38061761 100644 --- a/src/components/hooks/queries/useReport.ts +++ b/src/components/hooks/queries/useReport.ts @@ -1,4 +1,3 @@ -'use client'; import { produce } from 'immer'; import { useCallback, useEffect, useState } from 'react'; import { useApi } from './useApi'; diff --git a/src/components/hooks/queries/useReports.ts b/src/components/hooks/queries/useReports.ts index 77ebdbe9..0e0f260b 100644 --- a/src/components/hooks/queries/useReports.ts +++ b/src/components/hooks/queries/useReports.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import useModified from 'store/modified'; diff --git a/src/components/hooks/queries/useShareToken.ts b/src/components/hooks/queries/useShareToken.ts index 8197fe66..189657be 100644 --- a/src/components/hooks/queries/useShareToken.ts +++ b/src/components/hooks/queries/useShareToken.ts @@ -1,4 +1,3 @@ -'use client'; import useStore, { setShareToken } from 'store/app'; import useApi from './useApi'; diff --git a/src/components/hooks/queries/useTeam.ts b/src/components/hooks/queries/useTeam.ts index 1a8ccc54..e348531c 100644 --- a/src/components/hooks/queries/useTeam.ts +++ b/src/components/hooks/queries/useTeam.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; export function useTeam(teamId: string) { diff --git a/src/components/hooks/queries/useTeamMembers.ts b/src/components/hooks/queries/useTeamMembers.ts index ccfd6c9b..064231d1 100644 --- a/src/components/hooks/queries/useTeamMembers.ts +++ b/src/components/hooks/queries/useTeamMembers.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; diff --git a/src/components/hooks/queries/useTeamWebsites.ts b/src/components/hooks/queries/useTeamWebsites.ts index 036d715b..19bcdf76 100644 --- a/src/components/hooks/queries/useTeamWebsites.ts +++ b/src/components/hooks/queries/useTeamWebsites.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; diff --git a/src/components/hooks/queries/useTeams.ts b/src/components/hooks/queries/useTeams.ts index 7628887f..020c9915 100644 --- a/src/components/hooks/queries/useTeams.ts +++ b/src/components/hooks/queries/useTeams.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import { useLogin } from 'components/hooks'; diff --git a/src/components/hooks/queries/useUser.ts b/src/components/hooks/queries/useUser.ts index 7ff73dac..61c22ecd 100644 --- a/src/components/hooks/queries/useUser.ts +++ b/src/components/hooks/queries/useUser.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; export function useUser(userId: string, options?: { [key: string]: any }) { diff --git a/src/components/hooks/queries/useUsers.ts b/src/components/hooks/queries/useUsers.ts index 05f273d8..ab897c17 100644 --- a/src/components/hooks/queries/useUsers.ts +++ b/src/components/hooks/queries/useUsers.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import useModified from 'store/modified'; diff --git a/src/components/hooks/queries/useWebsite.ts b/src/components/hooks/queries/useWebsite.ts index 6aec87e8..4121f97b 100644 --- a/src/components/hooks/queries/useWebsite.ts +++ b/src/components/hooks/queries/useWebsite.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; export function useWebsite(websiteId: string, options?: { [key: string]: any }) { diff --git a/src/components/hooks/queries/useWebsiteEvents.ts b/src/components/hooks/queries/useWebsiteEvents.ts index 613788e2..de18a1f9 100644 --- a/src/components/hooks/queries/useWebsiteEvents.ts +++ b/src/components/hooks/queries/useWebsiteEvents.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import { UseQueryOptions } from '@tanstack/react-query'; diff --git a/src/components/hooks/queries/useWebsiteMetrics.ts b/src/components/hooks/queries/useWebsiteMetrics.ts index 300e526d..8e7d00db 100644 --- a/src/components/hooks/queries/useWebsiteMetrics.ts +++ b/src/components/hooks/queries/useWebsiteMetrics.ts @@ -1,4 +1,3 @@ -'use client'; import useApi from './useApi'; import { UseQueryOptions } from '@tanstack/react-query'; diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index 9449acc7..bb3e9a2d 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -1,4 +1,3 @@ -'use client'; import { useApi } from './useApi'; import { useFilterQuery } from './useFilterQuery'; import { useLogin } from './useLogin'; diff --git a/src/components/hooks/useCountryNames.ts b/src/components/hooks/useCountryNames.ts index 47716449..acfada44 100644 --- a/src/components/hooks/useCountryNames.ts +++ b/src/components/hooks/useCountryNames.ts @@ -1,4 +1,3 @@ -'use client'; import { useState, useEffect } from 'react'; import { httpGet } from 'next-basics'; import enUS from '../../../public/intl/country/en-US.json'; diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts index 8d7cf57c..e022d960 100644 --- a/src/components/hooks/useDateRange.ts +++ b/src/components/hooks/useDateRange.ts @@ -1,4 +1,3 @@ -'use client'; import { getMinimumUnit, parseDateRange } from 'lib/date'; import { setItem } from 'next-basics'; import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE } from 'lib/constants'; diff --git a/src/components/hooks/useDocumentClick.ts b/src/components/hooks/useDocumentClick.ts index dce9e106..eefd9366 100644 --- a/src/components/hooks/useDocumentClick.ts +++ b/src/components/hooks/useDocumentClick.ts @@ -1,4 +1,3 @@ -'use client'; import { useEffect } from 'react'; export function useDocumentClick(handler: (event: MouseEvent) => any) { diff --git a/src/components/hooks/useEscapeKey.ts b/src/components/hooks/useEscapeKey.ts index 567878b0..5c3350e7 100644 --- a/src/components/hooks/useEscapeKey.ts +++ b/src/components/hooks/useEscapeKey.ts @@ -1,4 +1,3 @@ -'use client'; import { useEffect, useCallback, KeyboardEvent } from 'react'; export function useEscapeKey(handler: (event: KeyboardEvent) => void) { diff --git a/src/components/hooks/useFilters.ts b/src/components/hooks/useFilters.ts index 51a5d972..e1a9a885 100644 --- a/src/components/hooks/useFilters.ts +++ b/src/components/hooks/useFilters.ts @@ -1,4 +1,3 @@ -'use client'; import { useMessages } from './useMessages'; import { OPERATORS } from 'lib/constants'; diff --git a/src/components/hooks/useForceUpdate.ts b/src/components/hooks/useForceUpdate.ts index 1798cdd8..35f7fe16 100644 --- a/src/components/hooks/useForceUpdate.ts +++ b/src/components/hooks/useForceUpdate.ts @@ -1,4 +1,3 @@ -'use client'; import { useCallback, useState } from 'react'; export function useForceUpdate() { diff --git a/src/components/hooks/useFormat.ts b/src/components/hooks/useFormat.ts index 4d8994fc..3057e9d8 100644 --- a/src/components/hooks/useFormat.ts +++ b/src/components/hooks/useFormat.ts @@ -1,4 +1,3 @@ -'use client'; import useMessages from './useMessages'; import { BROWSERS } from 'lib/constants'; import useLocale from './useLocale'; diff --git a/src/components/hooks/useLanguageNames.ts b/src/components/hooks/useLanguageNames.ts index 95b1a97f..d4bfbf2f 100644 --- a/src/components/hooks/useLanguageNames.ts +++ b/src/components/hooks/useLanguageNames.ts @@ -1,4 +1,3 @@ -'use client'; import { useState, useEffect } from 'react'; import { httpGet } from 'next-basics'; import enUS from '../../../public/intl/language/en-US.json'; diff --git a/src/components/hooks/useLocale.ts b/src/components/hooks/useLocale.ts index 00998ba4..5e4e1ce8 100644 --- a/src/components/hooks/useLocale.ts +++ b/src/components/hooks/useLocale.ts @@ -1,4 +1,3 @@ -'use client'; import { useEffect } from 'react'; import { httpGet, setItem } from 'next-basics'; import { LOCALE_CONFIG } from 'lib/constants'; diff --git a/src/components/hooks/useMessages.ts b/src/components/hooks/useMessages.ts index 8b82dd57..ab37cc19 100644 --- a/src/components/hooks/useMessages.ts +++ b/src/components/hooks/useMessages.ts @@ -1,4 +1,3 @@ -'use client'; import { useIntl, FormattedMessage } from 'react-intl'; import { messages, labels } from 'components/messages'; diff --git a/src/components/hooks/useNavigation.ts b/src/components/hooks/useNavigation.ts index 59731c3e..0ff7155a 100644 --- a/src/components/hooks/useNavigation.ts +++ b/src/components/hooks/useNavigation.ts @@ -1,4 +1,3 @@ -'use client'; import { useMemo } from 'react'; import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { buildUrl } from 'next-basics'; diff --git a/src/components/hooks/useSticky.ts b/src/components/hooks/useSticky.ts index 39c57f6e..459c489a 100644 --- a/src/components/hooks/useSticky.ts +++ b/src/components/hooks/useSticky.ts @@ -1,4 +1,3 @@ -'use client'; import { useState, useEffect, useRef } from 'react'; export function useSticky({ enabled = true, threshold = 1 }) { diff --git a/src/components/hooks/useTeamUrl.ts b/src/components/hooks/useTeamUrl.ts index 3e1c3972..b2aa8ea7 100644 --- a/src/components/hooks/useTeamUrl.ts +++ b/src/components/hooks/useTeamUrl.ts @@ -1,4 +1,3 @@ -'use client'; import { usePathname } from 'next/navigation'; export function useTeamUrl(): { diff --git a/src/components/hooks/useTheme.ts b/src/components/hooks/useTheme.ts index cd19f702..099bf962 100644 --- a/src/components/hooks/useTheme.ts +++ b/src/components/hooks/useTheme.ts @@ -1,4 +1,3 @@ -'use client'; import { useEffect } from 'react'; import useStore, { setTheme } from 'store/app'; import { getItem, setItem } from 'next-basics'; diff --git a/src/components/hooks/useTimezone.ts b/src/components/hooks/useTimezone.ts index 0f5f8dbc..3dbb52b3 100644 --- a/src/components/hooks/useTimezone.ts +++ b/src/components/hooks/useTimezone.ts @@ -1,4 +1,3 @@ -'use client'; import { useState, useCallback } from 'react'; import { getTimezone } from 'lib/date'; import { getItem, setItem } from 'next-basics'; diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx index 34c80b5b..0c29afa6 100644 --- a/src/components/input/DateFilter.tsx +++ b/src/components/input/DateFilter.tsx @@ -1,4 +1,3 @@ -'use client'; import { useState } from 'react'; import { Icon, Modal, Dropdown, Item, Text, Flexbox } from 'react-basics'; import { endOfYear, isSameDay } from 'date-fns'; diff --git a/src/components/input/LogoutButton.tsx b/src/components/input/LogoutButton.tsx index f3129207..ddc71142 100644 --- a/src/components/input/LogoutButton.tsx +++ b/src/components/input/LogoutButton.tsx @@ -9,7 +9,7 @@ export function LogoutButton({ }) { const { formatMessage, labels } = useMessages(); return ( - + - {(close: () => void) => } + {(close: () => void) => } ); diff --git a/src/components/hooks/queries/useTeams.ts b/src/components/hooks/queries/useTeams.ts index 020c9915..3360a6c4 100644 --- a/src/components/hooks/queries/useTeams.ts +++ b/src/components/hooks/queries/useTeams.ts @@ -1,13 +1,15 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; import { useLogin } from 'components/hooks'; +import useModified from 'store/modified'; export function useTeams(userId?: string) { const { get } = useApi(); const { user } = useLogin(); + const modified = useModified((state: any) => state?.teams); return useFilterQuery({ - queryKey: ['teams', { userId: userId || user?.id }], + queryKey: ['teams', { userId: userId || user?.id, modified }], queryFn: (params: any) => { return get(`/teams`, params); }, diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index bb3e9a2d..4f16e4d8 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -3,15 +3,13 @@ import { useFilterQuery } from './useFilterQuery'; import { useLogin } from './useLogin'; import useModified from 'store/modified'; -const selector = (state: any) => state?.websites; - export function useWebsites( { userId, teamId }: { userId?: string; teamId?: string }, params?: { [key: string]: string | number }, ) { const { get } = useApi(); const { user } = useLogin(); - const modified = useModified(selector); + const modified = useModified((state: any) => state?.websites); return useFilterQuery({ queryKey: ['websites', { userId, teamId, modified, ...params }], From f9f67264a54ca8483a3b4bf0347705ef5cd7dc45 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 6 Feb 2024 21:50:48 -0800 Subject: [PATCH 095/142] Fix type errors in admin queries --- src/queries/admin/report.ts | 3 +-- src/queries/admin/team.ts | 4 ++-- src/queries/admin/teamUser.ts | 25 ++++++++++++++----------- src/queries/admin/user.ts | 2 +- src/queries/admin/website.ts | 4 ++-- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/queries/admin/report.ts b/src/queries/admin/report.ts index fee0b442..d6b28cc4 100644 --- a/src/queries/admin/report.ts +++ b/src/queries/admin/report.ts @@ -1,10 +1,9 @@ import { Prisma, Report } from '@prisma/client'; import prisma from 'lib/prisma'; import { FilterResult, ReportSearchFilter } from 'lib/types'; -import ReportFindUniqueArgs = Prisma.ReportFindUniqueArgs; import ReportFindManyArgs = Prisma.ReportFindManyArgs; -async function findReport(criteria: ReportFindUniqueArgs) { +async function findReport(criteria: Prisma.ReportFindUniqueArgs): Promise { return prisma.client.report.findUnique(criteria); } diff --git a/src/queries/admin/team.ts b/src/queries/admin/team.ts index e381d5ce..225d57c4 100644 --- a/src/queries/admin/team.ts +++ b/src/queries/admin/team.ts @@ -5,8 +5,8 @@ import prisma from 'lib/prisma'; import { FilterResult, TeamSearchFilter } from 'lib/types'; import TeamFindManyArgs = Prisma.TeamFindManyArgs; -export async function findTeam(criteria: Prisma.TeamFindFirstArgs): Promise { - return prisma.client.team.findFirst(criteria); +export async function findTeam(criteria: Prisma.TeamFindUniqueArgs): Promise { + return prisma.client.team.findUnique(criteria); } export async function getTeam(teamId: string, options: { includeMembers?: boolean } = {}) { diff --git a/src/queries/admin/teamUser.ts b/src/queries/admin/teamUser.ts index 83f788de..43785b78 100644 --- a/src/queries/admin/teamUser.ts +++ b/src/queries/admin/teamUser.ts @@ -4,6 +4,10 @@ import prisma from 'lib/prisma'; import { FilterResult, TeamUserSearchFilter } from 'lib/types'; import TeamUserFindManyArgs = Prisma.TeamUserFindManyArgs; +export async function findTeamUser(criteria: Prisma.TeamUserFindUniqueArgs): Promise { + return prisma.client.teamUser.findUnique(criteria); +} + export async function getTeamUser(teamId: string, userId: string): Promise { return prisma.client.teamUser.findFirst({ where: { @@ -49,21 +53,20 @@ export async function createTeamUser( }); } -export async function updateTeamUser(teamUserId: string, data: any): Promise { - return prisma.client.teamUser.update( - { - where: { - id: teamUserId, - }, +export async function updateTeamUser( + teamUserId: string, + data: Prisma.TeamUserUpdateInput, +): Promise { + return prisma.client.teamUser.update({ + where: { + id: teamUserId, }, data, - ); + }); } -export async function deleteTeamUser(teamId: string, userId: string): Promise { - const { client } = prisma; - - return client.teamUser.deleteMany({ +export async function deleteTeamUser(teamId: string, userId: string): Promise { + return prisma.client.teamUser.deleteMany({ where: { teamId, userId, diff --git a/src/queries/admin/user.ts b/src/queries/admin/user.ts index 0b5fe349..274bb43d 100644 --- a/src/queries/admin/user.ts +++ b/src/queries/admin/user.ts @@ -221,7 +221,7 @@ export async function deleteUser( id: userId, }, }), - ]).then(async (data: any) => { + ]).then(async data => { if (cache.enabled) { const ids = websites.map(a => a.id); diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 53627f22..01d52019 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -4,7 +4,7 @@ import prisma from 'lib/prisma'; import { FilterResult, WebsiteSearchFilter } from 'lib/types'; import WebsiteFindManyArgs = Prisma.WebsiteFindManyArgs; -async function findWebsite(criteria: Prisma.WebsiteFindManyArgs): Promise { +async function findWebsite(criteria: Prisma.WebsiteFindUniqueArgs): Promise { return prisma.client.website.findUnique(criteria); } @@ -106,7 +106,7 @@ export async function createWebsite( .create({ data, }) - .then(async (data: { id: any }) => { + .then(async data => { if (cache.enabled) { await cache.storeWebsite(data); } From 87a18dc5708ec5c4e0496427f21fd0568e35151e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 6 Feb 2024 23:04:22 -0800 Subject: [PATCH 096/142] add modified to useTeamMembers, fix website delete --- src/app/(main)/reports/ReportDeleteButton.tsx | 1 + .../settings/websites/[websiteId]/WebsiteDeleteForm.tsx | 2 +- src/components/hooks/queries/useTeamMembers.ts | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/reports/ReportDeleteButton.tsx b/src/app/(main)/reports/ReportDeleteButton.tsx index 99e39d71..affd81fd 100644 --- a/src/app/(main)/reports/ReportDeleteButton.tsx +++ b/src/app/(main)/reports/ReportDeleteButton.tsx @@ -49,6 +49,7 @@ export function ReportDeleteButton({ error={error} onConfirm={handleConfirm.bind(null, close)} onClose={close} + buttonLabel={formatMessage(labels.delete)} /> )} diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx index 19755205..077a8f4a 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteDeleteForm.tsx @@ -15,7 +15,7 @@ export function WebsiteDeleteForm({ const { formatMessage, labels } = useMessages(); const { del, useMutation } = useApi(); const { mutate, isPending, error } = useMutation({ - mutationFn: (data: any) => del(`/websites/${websiteId}`, data), + mutationFn: () => del(`/websites/${websiteId}`), }); const handleConfirm = async () => { diff --git a/src/components/hooks/queries/useTeamMembers.ts b/src/components/hooks/queries/useTeamMembers.ts index 064231d1..a6011cb8 100644 --- a/src/components/hooks/queries/useTeamMembers.ts +++ b/src/components/hooks/queries/useTeamMembers.ts @@ -1,11 +1,13 @@ +import useModified from 'store/modified'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; export function useTeamMembers(teamId: string) { const { get } = useApi(); + const modified = useModified((state: any) => state?.['team:users']); return useFilterQuery({ - queryKey: ['teams:users', { teamId }], + queryKey: ['teams:users', { teamId, modified }], queryFn: (params: any) => { return get(`/teams/${teamId}/users`, params); }, From ba081565fc20414fa8533012542d770e5ed1184b Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 6 Feb 2024 23:42:37 -0800 Subject: [PATCH 097/142] make zustand teams:members consistent, fix team delete --- src/app/(main)/settings/teams/TeamLeaveForm.tsx | 2 +- .../teams/[teamId]/members/TeamMemberRemoveButton.tsx | 2 +- .../(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx | 2 +- src/components/hooks/queries/useTeamMembers.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/(main)/settings/teams/TeamLeaveForm.tsx b/src/app/(main)/settings/teams/TeamLeaveForm.tsx index 466fbab3..a22a9060 100644 --- a/src/app/(main)/settings/teams/TeamLeaveForm.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveForm.tsx @@ -24,7 +24,7 @@ export function TeamLeaveForm({ const handleConfirm = async () => { mutate(null, { onSuccess: async () => { - touch('team:members'); + touch('teams:members'); onSave(); onClose(); }, diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx index 0b4ca500..fc51a818 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx @@ -22,7 +22,7 @@ export function TeamMemberRemoveButton({ const handleRemoveTeamMember = () => { mutate(null, { onSuccess: () => { - touch('team:members'); + touch('teams:members'); onSave?.(); }, }); diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx index 33694495..2200cc1e 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx @@ -16,7 +16,7 @@ export function TeamDeleteForm({ const { labels, formatMessage } = useMessages(); const { del, useMutation } = useApi(); const { mutate, error, isPending } = useMutation({ - mutationFn: (data: any) => del(`/teams/${teamId}`, data), + mutationFn: () => del(`/teams/${teamId}`), }); const handleConfirm = async () => { diff --git a/src/components/hooks/queries/useTeamMembers.ts b/src/components/hooks/queries/useTeamMembers.ts index a6011cb8..d18ada3f 100644 --- a/src/components/hooks/queries/useTeamMembers.ts +++ b/src/components/hooks/queries/useTeamMembers.ts @@ -4,10 +4,10 @@ import useFilterQuery from './useFilterQuery'; export function useTeamMembers(teamId: string) { const { get } = useApi(); - const modified = useModified((state: any) => state?.['team:users']); + const modified = useModified((state: any) => state?.['teams:members']); return useFilterQuery({ - queryKey: ['teams:users', { teamId, modified }], + queryKey: ['teams:members', { teamId, modified }], queryFn: (params: any) => { return get(`/teams/${teamId}/users`, params); }, From 46a57183a18c0261147575534d7b9be33bc2f967 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Feb 2024 10:26:36 -0800 Subject: [PATCH 098/142] Fixed team users validation. --- src/pages/api/me/teams.ts | 3 ++- src/pages/api/users/[userId]/teams.ts | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pages/api/me/teams.ts b/src/pages/api/me/teams.ts index d068e0d3..1f6de446 100644 --- a/src/pages/api/me/teams.ts +++ b/src/pages/api/me/teams.ts @@ -1,4 +1,4 @@ -import { useCors, useValidate } from 'lib/middleware'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { pageInfo } from 'lib/schema'; import { NextApiResponse } from 'next'; @@ -14,6 +14,7 @@ const schema = { export default async (req: NextApiRequestQueryBody, res: NextApiResponse) => { await useCors(req, res); + await useAuth(req, res); await useValidate(schema, req, res); if (req.method === 'GET') { diff --git a/src/pages/api/users/[userId]/teams.ts b/src/pages/api/users/[userId]/teams.ts index ac6b98ea..0a75ff98 100644 --- a/src/pages/api/users/[userId]/teams.ts +++ b/src/pages/api/users/[userId]/teams.ts @@ -7,7 +7,7 @@ import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getUserTeams } from 'queries'; export interface UserTeamsRequestQuery extends SearchFilter { - id: string; + userId: string; } export interface UserTeamsRequestBody { @@ -18,13 +18,13 @@ export interface UserTeamsRequestBody { const schema = { GET: yup.object().shape({ - id: yup.string().uuid().required(), + userId: yup.string().uuid().required(), ...pageInfo, }), }; export default async ( - req: NextApiRequestQueryBody, + req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useCors(req, res); @@ -41,7 +41,7 @@ export default async ( const { page, query, pageSize } = req.query; - const teams = await getUserTeams(userId, { + const teams = await getUserTeams(userId as string, { query, page, pageSize, From 91e679643fb1cd8ea3f68c1d74f9837c55f2c8bf Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Feb 2024 10:27:23 -0800 Subject: [PATCH 099/142] Fixed TeamsProvider not working. --- src/app/(main)/teams/[teamId]/TeamProvider.tsx | 1 + src/app/(main)/{settings => }/teams/[teamId]/layout.tsx | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/app/(main)/{settings => }/teams/[teamId]/layout.tsx (61%) diff --git a/src/app/(main)/teams/[teamId]/TeamProvider.tsx b/src/app/(main)/teams/[teamId]/TeamProvider.tsx index 1ccdfd64..02a7e1b8 100644 --- a/src/app/(main)/teams/[teamId]/TeamProvider.tsx +++ b/src/app/(main)/teams/[teamId]/TeamProvider.tsx @@ -1,3 +1,4 @@ +'use client'; import { createContext, ReactNode, useEffect } from 'react'; import { useTeam } from 'components/hooks'; import { Loading } from 'react-basics'; diff --git a/src/app/(main)/settings/teams/[teamId]/layout.tsx b/src/app/(main)/teams/[teamId]/layout.tsx similarity index 61% rename from src/app/(main)/settings/teams/[teamId]/layout.tsx rename to src/app/(main)/teams/[teamId]/layout.tsx index dfe95bd3..f18d802a 100644 --- a/src/app/(main)/settings/teams/[teamId]/layout.tsx +++ b/src/app/(main)/teams/[teamId]/layout.tsx @@ -1,5 +1,4 @@ -'use client'; -import TeamProvider from 'app/(main)/teams/[teamId]/TeamProvider'; +import TeamProvider from './TeamProvider'; export default function ({ children, params: { teamId } }) { return {children}; From 0016a9f4e18d0011656f2e849d82db8ba7389604 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Feb 2024 11:33:35 -0800 Subject: [PATCH 100/142] Add functionality to leave team --- .../(main)/settings/teams/TeamLeaveButton.tsx | 24 +++++++++---------- .../(main)/settings/teams/TeamLeaveForm.tsx | 2 +- .../(main)/settings/teams/TeamsJoinButton.tsx | 2 ++ .../teams/[teamId]/team/TeamDetails.tsx | 23 +++++++----------- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/app/(main)/settings/teams/TeamLeaveButton.tsx b/src/app/(main)/settings/teams/TeamLeaveButton.tsx index 8b246a3b..308f8fb9 100644 --- a/src/app/(main)/settings/teams/TeamLeaveButton.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveButton.tsx @@ -1,23 +1,23 @@ +import { useLocale, useLogin, useMessages } from 'components/hooks'; +import { useRouter } from 'next/navigation'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; -import { useMessages, useLocale, useLogin } from 'components/hooks'; +import { touch } from 'store/modified'; import TeamDeleteForm from './TeamLeaveForm'; -export function TeamLeaveButton({ - teamId, - teamName, - onLeave, -}: { - teamId: string; - teamName: string; - onLeave?: () => void; -}) { +export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName: string }) { const { formatMessage, labels } = useMessages(); + const router = useRouter(); const { dir } = useLocale(); const { user } = useLogin(); + const handleLeave = async () => { + touch('teams'); + router.push('/settings/teams'); + }; + return ( - - {(close: () => void) => } + {(close: () => void) => ( + + )} diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx index 2200cc1e..3cbdf550 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamDeleteForm.tsx @@ -1,6 +1,5 @@ -import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/modified'; import TypeConfirmationForm from 'components/common/TypeConfirmationForm'; +import { useApi, useMessages } from 'components/hooks'; const CONFIRM_VALUE = 'DELETE'; @@ -22,7 +21,6 @@ export function TeamDeleteForm({ const handleConfirm = async () => { mutate(null, { onSuccess: async () => { - touch('teams'); onSave?.(); onClose?.(); }, From a47f94c577002dd7ac57afd63bc45e9c976038ba Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Feb 2024 11:58:58 -0800 Subject: [PATCH 102/142] Allow only team owner to remove other members --- .../teams/[teamId]/members/TeamMembersPage.tsx | 13 +++++++++++-- .../teams/[teamId]/members/TeamMembersTable.tsx | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx index 2ba4d177..a8159891 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersPage.tsx @@ -1,15 +1,24 @@ 'use client'; +import { TeamContext } from 'app/(main)/teams/[teamId]/TeamProvider'; import TeamMembersDataTable from './TeamMembersDataTable'; import PageHeader from 'components/layout/PageHeader'; -import { useMessages } from 'components/hooks'; +import { useLogin, useMessages } from 'components/hooks'; +import { ROLES } from 'lib/constants'; +import { useContext } from 'react'; export function TeamMembersPage({ teamId }: { teamId: string }) { + const team = useContext(TeamContext); + const { user } = useLogin(); const { formatMessage, labels } = useMessages(); + const canEdit = team?.teamUser?.find( + ({ userId, role }) => role === ROLES.teamOwner && userId === user.id, + ); + return ( <> - + ); } diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx index d993bbc0..0b60293a 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx @@ -6,7 +6,7 @@ import TeamMemberRemoveButton from './TeamMemberRemoveButton'; export function TeamMembersTable({ data = [], teamId, - allowEdit, + allowEdit = false, }: { data: any[]; teamId: string; From c302939043373f26583f9b6f6e8b4d73b34bf4c5 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Feb 2024 13:45:06 -0800 Subject: [PATCH 103/142] Remove admin panel if not team-owner --- src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx index e5af54c6..4fd97b60 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx @@ -26,10 +26,10 @@ export function TeamDetails({ teamId }: { teamId: string }) { setTab(value)} style={{ marginBottom: 30 }}> {formatMessage(labels.details)} - {formatMessage(labels.admin)} + {canEdit && {formatMessage(labels.admin)}} {tab === 'details' && } - {canEdit && tab === 'admin' && } + {tab === 'admin' && } ); } From bc73410dba10e50433e67aaef924beccb39aa20b Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Feb 2024 14:01:25 -0800 Subject: [PATCH 104/142] remove default deleted_at --- db/postgresql/migrations/04_team_redesign/migration.sql | 6 ++---- db/postgresql/schema.prisma | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/db/postgresql/migrations/04_team_redesign/migration.sql b/db/postgresql/migrations/04_team_redesign/migration.sql index 68b96ab0..91726316 100644 --- a/db/postgresql/migrations/04_team_redesign/migration.sql +++ b/db/postgresql/migrations/04_team_redesign/migration.sql @@ -5,7 +5,7 @@ */ -- AlterTable -ALTER TABLE "team" ADD COLUMN "deleted_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, +ALTER TABLE "team" ADD COLUMN "deleted_at" TIMESTAMPTZ(6), ADD COLUMN "logo_url" VARCHAR(2183); -- AlterTable @@ -26,6 +26,4 @@ DROP TABLE "team_website"; CREATE INDEX "website_team_id_idx" ON "website"("team_id"); -- CreateIndex -CREATE INDEX "website_created_by_idx" ON "website"("created_by"); - - +CREATE INDEX "website_created_by_idx" ON "website"("created_by"); \ No newline at end of file diff --git a/db/postgresql/schema.prisma b/db/postgresql/schema.prisma index 3f1838be..31cc7616 100644 --- a/db/postgresql/schema.prisma +++ b/db/postgresql/schema.prisma @@ -168,7 +168,7 @@ model Team { logoUrl String? @map("logo_url") @db.VarChar(2183) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) - deletedAt DateTime? @default(now()) @map("deleted_at") @db.Timestamptz(6) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) website Website[] teamUser TeamUser[] From b885f57f40db2ee998e3d293fb5ef2ce177ba1f3 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Feb 2024 14:22:38 -0800 Subject: [PATCH 105/142] only get non-deleted teams --- src/queries/admin/team.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/queries/admin/team.ts b/src/queries/admin/team.ts index 225d57c4..74b877de 100644 --- a/src/queries/admin/team.ts +++ b/src/queries/admin/team.ts @@ -46,6 +46,7 @@ export async function getUserTeams(userId: string, filters: TeamSearchFilter = { return getTeams( { where: { + deletedAt: null, teamUser: { some: { userId }, }, From 8da3811c730ffa49468504031ba6af1bbf87ad5b Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Feb 2024 16:37:48 -0800 Subject: [PATCH 106/142] add website in team context, permissions, display non-deleted users --- src/app/(main)/dashboard/DashboardPage.tsx | 2 +- .../[teamId]/websites/TeamWebsitesPage.tsx | 20 +++++++++++++++---- .../[teamId]/websites/TeamWebsitesTable.tsx | 4 ++-- .../settings/websites/WebsiteAddButton.tsx | 7 ++++--- .../hooks/queries/useTeamMembers.ts | 2 +- .../hooks/queries/useTeamWebsites.ts | 4 +++- src/pages/api/teams/[teamId]/users/index.ts | 7 ++++++- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/app/(main)/dashboard/DashboardPage.tsx b/src/app/(main)/dashboard/DashboardPage.tsx index 0b8a7d90..60bf1799 100644 --- a/src/app/(main)/dashboard/DashboardPage.tsx +++ b/src/app/(main)/dashboard/DashboardPage.tsx @@ -36,7 +36,7 @@ export function DashboardPage() { {!hasData && ( - + diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx index d600c9cd..ade43014 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage.tsx @@ -1,15 +1,27 @@ 'use client'; -import TeamWebsitesDataTable from './TeamWebsitesDataTable'; +import { TeamContext } from 'app/(main)/teams/[teamId]/TeamProvider'; +import WebsiteAddButton from 'app/(main)/settings/websites/WebsiteAddButton'; +import { useLogin, useMessages } from 'components/hooks'; import PageHeader from 'components/layout/PageHeader'; -import { useMessages } from 'components/hooks'; +import TeamWebsitesDataTable from './TeamWebsitesDataTable'; +import { ROLES } from 'lib/constants'; +import { useContext } from 'react'; export function TeamWebsitesPage({ teamId }: { teamId: string }) { + const team = useContext(TeamContext); const { formatMessage, labels } = useMessages(); + const { user } = useLogin(); + + const canEdit = team?.teamUser?.find( + ({ userId, role }) => role !== ROLES.viewOnly && userId === user.id, + ); return ( <> - - + + {canEdit && } + + ); } diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx index b07f3dbf..99a5d7fe 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx @@ -6,7 +6,7 @@ import LinkButton from 'components/common/LinkButton'; export function TeamWebsitesTable({ teamId, data = [], - allowEdit, + allowEdit = false, }: { teamId: string; data: any[]; @@ -21,7 +21,7 @@ export function TeamWebsitesTable({ {row => { - const { websiteId } = row; + const { id: websiteId } = row; return ( <> {allowEdit && (teamId || user?.isAdmin) && ( diff --git a/src/app/(main)/settings/websites/WebsiteAddButton.tsx b/src/app/(main)/settings/websites/WebsiteAddButton.tsx index 35e9bbc3..58b3001c 100644 --- a/src/app/(main)/settings/websites/WebsiteAddButton.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddButton.tsx @@ -1,7 +1,7 @@ -import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; -import WebsiteAddForm from './WebsiteAddForm'; import { useMessages } from 'components/hooks'; +import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import { touch } from 'store/modified'; +import WebsiteAddForm from './WebsiteAddForm'; export function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); @@ -9,7 +9,8 @@ export function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?: const handleSave = async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); - touch('websites'); + teamId ? touch('teams:websites') : touch('websites'); + onSave?.(); }; diff --git a/src/components/hooks/queries/useTeamMembers.ts b/src/components/hooks/queries/useTeamMembers.ts index d18ada3f..866e28e7 100644 --- a/src/components/hooks/queries/useTeamMembers.ts +++ b/src/components/hooks/queries/useTeamMembers.ts @@ -1,6 +1,6 @@ -import useModified from 'store/modified'; import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; +import useModified from 'store/modified'; export function useTeamMembers(teamId: string) { const { get } = useApi(); diff --git a/src/components/hooks/queries/useTeamWebsites.ts b/src/components/hooks/queries/useTeamWebsites.ts index 19bcdf76..5259f9d3 100644 --- a/src/components/hooks/queries/useTeamWebsites.ts +++ b/src/components/hooks/queries/useTeamWebsites.ts @@ -1,11 +1,13 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; +import useModified from 'store/modified'; export function useTeamWebsites(teamId: string) { const { get } = useApi(); + const modified = useModified((state: any) => state?.['teams:websites']); return useFilterQuery({ - queryKey: ['teams:websites', { teamId }], + queryKey: ['teams:websites', { teamId, modified }], queryFn: (params: any) => { return get(`/teams/${teamId}/websites`, params); }, diff --git a/src/pages/api/teams/[teamId]/users/index.ts b/src/pages/api/teams/[teamId]/users/index.ts index 53f0dd0a..47394eef 100644 --- a/src/pages/api/teams/[teamId]/users/index.ts +++ b/src/pages/api/teams/[teamId]/users/index.ts @@ -48,7 +48,12 @@ export default async ( const users = await getTeamUsers( { - where: { teamId }, + where: { + teamId, + user: { + deletedAt: null, + }, + }, include: { user: { select: { From 264c6954e98cb1ae9af98679f8796c05cd6888ac Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Feb 2024 22:53:36 -0800 Subject: [PATCH 107/142] Updated menu style. --- src/components/layout/SideNav.module.css | 2 ++ src/tracker/index.d.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/layout/SideNav.module.css b/src/components/layout/SideNav.module.css index 5dbe4105..be80506a 100644 --- a/src/components/layout/SideNav.module.css +++ b/src/components/layout/SideNav.module.css @@ -1,6 +1,7 @@ .menu { display: flex; flex-direction: column; + gap: 2px; } .item a { @@ -16,4 +17,5 @@ .selected { font-weight: 700; + background: var(--base75); } diff --git a/src/tracker/index.d.ts b/src/tracker/index.d.ts index f9bd4b24..05497da2 100644 --- a/src/tracker/index.d.ts +++ b/src/tracker/index.d.ts @@ -138,7 +138,7 @@ export type UmamiTracker = { /** * Tracks an event with fully customizable dynamic data - * Ilf you don't specify any `name` and/or `data`, it will be treated as a page view + * If you don't specify any `name` and/or `data`, it will be treated as a page view * * @example ``` * umami.track((props) => ({ ...props, url: path })); From 32a97e68ecd948e13a667fef08d7548b0e12bd7f Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Feb 2024 22:55:09 -0800 Subject: [PATCH 108/142] Do not export page components. --- src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 8653cd4f..948923af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,6 @@ export * from 'components/hooks'; export * from 'app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton'; -export * from 'app/(main)/settings/teams/[teamId]/members/TeamMembersPage'; export * from 'app/(main)/settings/teams/[teamId]/members/TeamMembersDataTable'; export * from 'app/(main)/settings/teams/[teamId]/members/TeamMembersTable'; @@ -9,10 +8,8 @@ export * from 'app/(main)/settings/teams/[teamId]/team/TeamAdmin'; export * from 'app/(main)/settings/teams/[teamId]/team/TeamDeleteForm'; export * from 'app/(main)/settings/teams/[teamId]/team/TeamDetails'; export * from 'app/(main)/settings/teams/[teamId]/team/TeamEditForm'; -export * from 'app/(main)/settings/teams/[teamId]/team/TeamPage'; export * from 'app/(main)/settings/teams/[teamId]/websites/TeamWebsiteRemoveButton'; -export * from './app/(main)/settings/teams/[teamId]/websites/TeamWebsitesPage'; export * from 'app/(main)/settings/teams/[teamId]/websites/TeamWebsitesDataTable'; export * from 'app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable'; From a426c242cb6dba41b5b85d8b67debd31e9834ff3 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Feb 2024 23:20:41 -0800 Subject: [PATCH 109/142] Fixed website edit for teams. --- .../settings/teams/[teamId]/websites/TeamWebsitesTable.tsx | 2 +- .../teams/[teamId]/settings/websites/[websiteId]/page.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx index 99a5d7fe..086cc03a 100644 --- a/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/websites/TeamWebsitesTable.tsx @@ -25,7 +25,7 @@ export function TeamWebsitesTable({ return ( <> {allowEdit && (teamId || user?.isAdmin) && ( - + diff --git a/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx b/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx index 224ff4d5..ad1a97dd 100644 --- a/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx +++ b/src/app/(main)/teams/[teamId]/settings/websites/[websiteId]/page.tsx @@ -1,3 +1,3 @@ -import Page from 'app/(main)/websites/[websiteId]/page'; +import Page from 'app/(main)/settings/websites/[websiteId]/page'; export default Page; From 91e3dff7f5f6f9f41424d60db633ce7d68c8d495 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Feb 2024 23:48:51 -0800 Subject: [PATCH 110/142] Convert useModified into a real hook. --- src/app/(main)/reports/ReportDeleteButton.tsx | 4 ++-- src/app/(main)/settings/teams/TeamJoinForm.tsx | 4 ++-- src/app/(main)/settings/teams/TeamLeaveButton.tsx | 4 ++-- src/app/(main)/settings/teams/TeamLeaveForm.tsx | 4 ++-- src/app/(main)/settings/teams/TeamsAddButton.tsx | 4 ++-- src/app/(main)/settings/teams/TeamsJoinButton.tsx | 4 ++-- .../[teamId]/members/TeamMemberRemoveButton.tsx | 4 ++-- .../settings/teams/[teamId]/team/TeamAdmin.tsx | 4 ++-- src/app/(main)/settings/users/UserAddButton.tsx | 4 ++-- src/app/(main)/settings/users/UserDeleteForm.tsx | 4 ++-- .../(main)/settings/websites/WebsiteAddButton.tsx | 4 ++-- .../settings/websites/[websiteId]/ShareUrl.tsx | 4 ++-- .../settings/websites/[websiteId]/WebsiteData.tsx | 4 ++-- .../websites/[websiteId]/WebsiteEditForm.tsx | 4 ++-- src/app/(main)/teams/[teamId]/TeamProvider.tsx | 5 ++--- .../websites/[websiteId]/WebsiteProvider.tsx | 5 ++--- src/components/hooks/index.ts | 1 + src/components/hooks/queries/useReports.ts | 4 ++-- src/components/hooks/queries/useTeamMembers.ts | 4 ++-- src/components/hooks/queries/useTeamWebsites.ts | 4 ++-- src/components/hooks/queries/useTeams.ts | 9 +++++---- src/components/hooks/queries/useUsers.ts | 4 ++-- src/components/hooks/queries/useWebsites.ts | 4 ++-- src/components/hooks/useModified.ts | 15 +++++++++++++++ 24 files changed, 63 insertions(+), 48 deletions(-) create mode 100644 src/components/hooks/useModified.ts diff --git a/src/app/(main)/reports/ReportDeleteButton.tsx b/src/app/(main)/reports/ReportDeleteButton.tsx index affd81fd..7ad9c465 100644 --- a/src/app/(main)/reports/ReportDeleteButton.tsx +++ b/src/app/(main)/reports/ReportDeleteButton.tsx @@ -1,6 +1,5 @@ import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; -import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/modified'; +import { useApi, useMessages, useModified } from 'components/hooks'; import ConfirmationForm from 'components/common/ConfirmationForm'; export function ReportDeleteButton({ @@ -17,6 +16,7 @@ export function ReportDeleteButton({ const { mutate, isPending, error } = useMutation({ mutationFn: reportId => del(`/reports/${reportId}`), }); + const { touch } = useModified(); const handleConfirm = (close: () => void) => { mutate(reportId as any, { diff --git a/src/app/(main)/settings/teams/TeamJoinForm.tsx b/src/app/(main)/settings/teams/TeamJoinForm.tsx index 385ff1df..939b5d4b 100644 --- a/src/app/(main)/settings/teams/TeamJoinForm.tsx +++ b/src/app/(main)/settings/teams/TeamJoinForm.tsx @@ -8,14 +8,14 @@ import { Button, SubmitButton, } from 'react-basics'; -import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/modified'; +import { useApi, useMessages, useModified } from 'components/hooks'; export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) { const { formatMessage, labels, getMessage } = useMessages(); const { post, useMutation } = useApi(); const { mutate, error } = useMutation({ mutationFn: (data: any) => post('/teams/join', data) }); const ref = useRef(null); + const { touch } = useModified(); const handleSubmit = async (data: any) => { mutate(data, { diff --git a/src/app/(main)/settings/teams/TeamLeaveButton.tsx b/src/app/(main)/settings/teams/TeamLeaveButton.tsx index 308f8fb9..b8a24c7e 100644 --- a/src/app/(main)/settings/teams/TeamLeaveButton.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveButton.tsx @@ -1,7 +1,6 @@ -import { useLocale, useLogin, useMessages } from 'components/hooks'; +import { useLocale, useLogin, useMessages, useModified } from 'components/hooks'; import { useRouter } from 'next/navigation'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; -import { touch } from 'store/modified'; import TeamDeleteForm from './TeamLeaveForm'; export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName: string }) { @@ -9,6 +8,7 @@ export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName const router = useRouter(); const { dir } = useLocale(); const { user } = useLogin(); + const { touch } = useModified(); const handleLeave = async () => { touch('teams'); diff --git a/src/app/(main)/settings/teams/TeamLeaveForm.tsx b/src/app/(main)/settings/teams/TeamLeaveForm.tsx index 980a8cb7..8c9726be 100644 --- a/src/app/(main)/settings/teams/TeamLeaveForm.tsx +++ b/src/app/(main)/settings/teams/TeamLeaveForm.tsx @@ -1,5 +1,4 @@ -import { useApi, useMessages } from 'components/hooks'; -import { touch } from 'store/modified'; +import { useApi, useMessages, useModified } from 'components/hooks'; import ConfirmationForm from 'components/common/ConfirmationForm'; export function TeamLeaveForm({ @@ -20,6 +19,7 @@ export function TeamLeaveForm({ const { mutate, error, isPending } = useMutation({ mutationFn: () => del(`/teams/${teamId}/users/${userId}`), }); + const { touch } = useModified(); const handleConfirm = async () => { mutate(null, { diff --git a/src/app/(main)/settings/teams/TeamsAddButton.tsx b/src/app/(main)/settings/teams/TeamsAddButton.tsx index 15f541ea..6ec4cf39 100644 --- a/src/app/(main)/settings/teams/TeamsAddButton.tsx +++ b/src/app/(main)/settings/teams/TeamsAddButton.tsx @@ -1,13 +1,13 @@ import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import Icons from 'components/icons'; -import { useMessages } from 'components/hooks'; +import { useMessages, useModified } from 'components/hooks'; import TeamAddForm from './TeamAddForm'; import { messages } from 'components/messages'; -import { touch } from 'store/modified'; export function TeamsAddButton({ onSave }: { onSave?: () => void }) { const { formatMessage, labels } = useMessages(); const { showToast } = useToasts(); + const { touch } = useModified(); const handleSave = async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); diff --git a/src/app/(main)/settings/teams/TeamsJoinButton.tsx b/src/app/(main)/settings/teams/TeamsJoinButton.tsx index 21f821c9..24925bb6 100644 --- a/src/app/(main)/settings/teams/TeamsJoinButton.tsx +++ b/src/app/(main)/settings/teams/TeamsJoinButton.tsx @@ -1,12 +1,12 @@ import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import Icons from 'components/icons'; -import { useMessages } from 'components/hooks'; +import { useMessages, useModified } from 'components/hooks'; import TeamJoinForm from './TeamJoinForm'; -import { touch } from 'store/modified'; export function TeamsJoinButton() { const { formatMessage, labels, messages } = useMessages(); const { showToast } = useToasts(); + const { touch } = useModified(); const handleJoin = () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx index fc51a818..bb944061 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx @@ -1,6 +1,5 @@ -import { useApi, useMessages } from 'components/hooks'; +import { useApi, useMessages, useModified } from 'components/hooks'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; -import { touch } from 'store/modified'; export function TeamMemberRemoveButton({ teamId, @@ -18,6 +17,7 @@ export function TeamMemberRemoveButton({ const { mutate, isPending } = useMutation({ mutationFn: () => del(`/teams/${teamId}/users/${userId}`), }); + const { touch } = useModified(); const handleRemoveTeamMember = () => { mutate(null, { diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx index b52b661e..2c0a20d2 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx @@ -1,12 +1,12 @@ -import { useMessages } from 'components/hooks'; +import { useMessages, useModified } from 'components/hooks'; import { useRouter } from 'next/navigation'; import { ActionForm, Button, Modal, ModalTrigger } from 'react-basics'; import TeamDeleteForm from './TeamDeleteForm'; -import { touch } from 'store/modified'; export function TeamAdmin({ teamId }: { teamId: string }) { const { formatMessage, labels, messages } = useMessages(); const router = useRouter(); + const { touch } = useModified(); const handleLeave = async () => { touch('teams'); diff --git a/src/app/(main)/settings/users/UserAddButton.tsx b/src/app/(main)/settings/users/UserAddButton.tsx index 5746ff2a..832cf75b 100644 --- a/src/app/(main)/settings/users/UserAddButton.tsx +++ b/src/app/(main)/settings/users/UserAddButton.tsx @@ -1,11 +1,11 @@ import { Button, Icon, Text, Modal, Icons, ModalTrigger, useToasts } from 'react-basics'; import UserAddForm from './UserAddForm'; -import { useMessages } from 'components/hooks'; -import { touch } from 'store/modified'; +import { useMessages, useModified } from 'components/hooks'; export function UserAddButton({ onSave }: { onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); const { showToast } = useToasts(); + const { touch } = useModified(); const handleSave = () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); diff --git a/src/app/(main)/settings/users/UserDeleteForm.tsx b/src/app/(main)/settings/users/UserDeleteForm.tsx index 97caf644..9b49647f 100644 --- a/src/app/(main)/settings/users/UserDeleteForm.tsx +++ b/src/app/(main)/settings/users/UserDeleteForm.tsx @@ -1,11 +1,11 @@ -import { useApi, useMessages } from 'components/hooks'; +import { useApi, useMessages, useModified } from 'components/hooks'; import ConfirmationForm from 'components/common/ConfirmationForm'; -import { touch } from 'store/modified'; export function UserDeleteForm({ userId, username, onSave, onClose }) { const { FormattedMessage, messages, labels, formatMessage } = useMessages(); const { del, useMutation } = useApi(); const { mutate, error, isPending } = useMutation({ mutationFn: () => del(`/users/${userId}`) }); + const { touch } = useModified(); const handleConfirm = async () => { mutate(null, { diff --git a/src/app/(main)/settings/websites/WebsiteAddButton.tsx b/src/app/(main)/settings/websites/WebsiteAddButton.tsx index 58b3001c..8f0b2091 100644 --- a/src/app/(main)/settings/websites/WebsiteAddButton.tsx +++ b/src/app/(main)/settings/websites/WebsiteAddButton.tsx @@ -1,11 +1,11 @@ -import { useMessages } from 'components/hooks'; +import { useMessages, useModified } from 'components/hooks'; import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; -import { touch } from 'store/modified'; import WebsiteAddForm from './WebsiteAddForm'; export function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); const { showToast } = useToasts(); + const { touch } = useModified(); const handleSave = async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); diff --git a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx index 6fb543d0..e06657d4 100644 --- a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx @@ -11,9 +11,8 @@ import { } from 'react-basics'; import { useContext, useState } from 'react'; import { getRandomChars } from 'next-basics'; -import { useApi, useMessages } from 'components/hooks'; +import { useApi, useMessages, useModified } from 'components/hooks'; import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; -import { touch } from 'store/modified'; const generateId = () => getRandomChars(16); @@ -33,6 +32,7 @@ export function ShareUrl({ const { mutate, error, isPending } = useMutation({ mutationFn: (data: any) => post(`/websites/${website.id}`, data), }); + const { touch } = useModified(); const url = `${hostUrl || process.env.hostUrl || window?.location.origin}${ process.env.basePath diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx index 4dd5fde4..c75ef74b 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx @@ -1,14 +1,14 @@ import { Button, Modal, ModalTrigger, ActionForm, useToasts } from 'react-basics'; import { useRouter } from 'next/navigation'; -import { useMessages } from 'components/hooks'; +import { useMessages, useModified } from 'components/hooks'; import WebsiteDeleteForm from './WebsiteDeleteForm'; import WebsiteResetForm from './WebsiteResetForm'; -import { touch } from 'store/modified'; export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); const router = useRouter(); const { showToast } = useToasts(); + const { touch } = useModified(); const handleReset = async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx index 543261dd..d7d9cef4 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx @@ -8,9 +8,8 @@ import { TextField, useToasts, } from 'react-basics'; -import { useApi, useMessages } from 'components/hooks'; +import { useApi, useMessages, useModified } from 'components/hooks'; import { DOMAIN_REGEX } from 'lib/constants'; -import { touch } from 'store/modified'; import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; export function WebsiteEditForm({ websiteId }: { websiteId: string }) { @@ -22,6 +21,7 @@ export function WebsiteEditForm({ websiteId }: { websiteId: string }) { }); const ref = useRef(null); const { showToast } = useToasts(); + const { touch } = useModified(); const handleSubmit = async (data: any) => { mutate(data, { diff --git a/src/app/(main)/teams/[teamId]/TeamProvider.tsx b/src/app/(main)/teams/[teamId]/TeamProvider.tsx index 02a7e1b8..a9c57cec 100644 --- a/src/app/(main)/teams/[teamId]/TeamProvider.tsx +++ b/src/app/(main)/teams/[teamId]/TeamProvider.tsx @@ -1,13 +1,12 @@ 'use client'; import { createContext, ReactNode, useEffect } from 'react'; -import { useTeam } from 'components/hooks'; +import { useTeam, useModified } from 'components/hooks'; import { Loading } from 'react-basics'; -import useModified from 'store/modified'; export const TeamContext = createContext(null); export function TeamProvider({ teamId, children }: { teamId?: string; children: ReactNode }) { - const modified = useModified(state => state?.[`team:${teamId}`]); + const { modified } = useModified(`teams`); const { data: team, isLoading, isFetching, refetch } = useTeam(teamId); useEffect(() => { diff --git a/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx b/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx index e1d3da26..76d40b70 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteProvider.tsx @@ -1,7 +1,6 @@ import { createContext, ReactNode, useEffect } from 'react'; -import { useWebsite } from 'components/hooks'; +import { useModified, useWebsite } from 'components/hooks'; import { Loading } from 'react-basics'; -import useModified from 'store/modified'; export const WebsiteContext = createContext(null); @@ -12,7 +11,7 @@ export function WebsiteProvider({ websiteId: string; children: ReactNode; }) { - const modified = useModified(state => state?.[`website:${websiteId}`]); + const { modified } = useModified(`website:${websiteId}`); const { data: website, isFetching, isLoading, refetch } = useWebsite(websiteId); useEffect(() => { diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index 79cefcfd..560d48a0 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -25,6 +25,7 @@ export * from './useFormat'; export * from './useLanguageNames'; export * from './useLocale'; export * from './useMessages'; +export * from './useModified'; export * from './useNavigation'; export * from './useSticky'; export * from './useTeamUrl'; diff --git a/src/components/hooks/queries/useReports.ts b/src/components/hooks/queries/useReports.ts index 0e0f260b..314880f8 100644 --- a/src/components/hooks/queries/useReports.ts +++ b/src/components/hooks/queries/useReports.ts @@ -1,9 +1,9 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import useModified from 'store/modified'; +import useModified from '../useModified'; export function useReports({ websiteId, teamId }: { websiteId?: string; teamId?: string }) { - const modified = useModified((state: any) => state?.reports); + const { modified } = useModified(`reports`); const { get, del, useMutation } = useApi(); const queryResult = useFilterQuery({ queryKey: ['reports', { websiteId, teamId, modified }], diff --git a/src/components/hooks/queries/useTeamMembers.ts b/src/components/hooks/queries/useTeamMembers.ts index 866e28e7..85860870 100644 --- a/src/components/hooks/queries/useTeamMembers.ts +++ b/src/components/hooks/queries/useTeamMembers.ts @@ -1,10 +1,10 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import useModified from 'store/modified'; +import useModified from '../useModified'; export function useTeamMembers(teamId: string) { const { get } = useApi(); - const modified = useModified((state: any) => state?.['teams:members']); + const { modified } = useModified(`teams:members`); return useFilterQuery({ queryKey: ['teams:members', { teamId, modified }], diff --git a/src/components/hooks/queries/useTeamWebsites.ts b/src/components/hooks/queries/useTeamWebsites.ts index 5259f9d3..06e12a82 100644 --- a/src/components/hooks/queries/useTeamWebsites.ts +++ b/src/components/hooks/queries/useTeamWebsites.ts @@ -1,10 +1,10 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import useModified from 'store/modified'; +import useModified from '../useModified'; export function useTeamWebsites(teamId: string) { const { get } = useApi(); - const modified = useModified((state: any) => state?.['teams:websites']); + const { modified } = useModified(`teams:websites`); return useFilterQuery({ queryKey: ['teams:websites', { teamId, modified }], diff --git a/src/components/hooks/queries/useTeams.ts b/src/components/hooks/queries/useTeams.ts index 3360a6c4..f8084025 100644 --- a/src/components/hooks/queries/useTeams.ts +++ b/src/components/hooks/queries/useTeams.ts @@ -1,15 +1,16 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import { useLogin } from 'components/hooks'; -import useModified from 'store/modified'; +import useLogin from './useLogin'; +import useModified from '../useModified'; export function useTeams(userId?: string) { const { get } = useApi(); const { user } = useLogin(); - const modified = useModified((state: any) => state?.teams); + const id = userId || user?.id; + const { modified } = useModified(`teams`); return useFilterQuery({ - queryKey: ['teams', { userId: userId || user?.id, modified }], + queryKey: ['teams', { userId: id, modified }], queryFn: (params: any) => { return get(`/teams`, params); }, diff --git a/src/components/hooks/queries/useUsers.ts b/src/components/hooks/queries/useUsers.ts index ab897c17..169cf424 100644 --- a/src/components/hooks/queries/useUsers.ts +++ b/src/components/hooks/queries/useUsers.ts @@ -1,10 +1,10 @@ import useApi from './useApi'; import useFilterQuery from './useFilterQuery'; -import useModified from 'store/modified'; +import useModified from '../useModified'; export function useUsers() { const { get } = useApi(); - const modified = useModified((state: any) => state?.users); + const { modified } = useModified(`users`); return useFilterQuery({ queryKey: ['users', { modified }], diff --git a/src/components/hooks/queries/useWebsites.ts b/src/components/hooks/queries/useWebsites.ts index 4f16e4d8..94198975 100644 --- a/src/components/hooks/queries/useWebsites.ts +++ b/src/components/hooks/queries/useWebsites.ts @@ -1,7 +1,7 @@ import { useApi } from './useApi'; import { useFilterQuery } from './useFilterQuery'; import { useLogin } from './useLogin'; -import useModified from 'store/modified'; +import useModified from '../useModified'; export function useWebsites( { userId, teamId }: { userId?: string; teamId?: string }, @@ -9,7 +9,7 @@ export function useWebsites( ) { const { get } = useApi(); const { user } = useLogin(); - const modified = useModified((state: any) => state?.websites); + const { modified } = useModified(`websites`); return useFilterQuery({ queryKey: ['websites', { userId, teamId, modified, ...params }], diff --git a/src/components/hooks/useModified.ts b/src/components/hooks/useModified.ts new file mode 100644 index 00000000..858be87e --- /dev/null +++ b/src/components/hooks/useModified.ts @@ -0,0 +1,15 @@ +import useStore from 'store/modified'; + +export function useModified(key?: string) { + const modified = useStore(state => state?.[key]); + + const touch = (id?: string) => { + if (id || key) { + useStore.setState({ [id || key]: Date.now() }); + } + }; + + return { modified, touch }; +} + +export default useModified; From 5ae04291afd60420dfc4bcfc45657f6e0c8f8fd7 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 8 Feb 2024 10:30:14 -0800 Subject: [PATCH 111/142] Disable website select for saved report. Fix delete website routing --- .../reports/[reportId]/BaseParameters.tsx | 9 ++++++--- .../event-data/EventDataParameters.tsx | 4 ++-- .../reports/funnel/FunnelParameters.tsx | 4 ++-- .../reports/insights/InsightsParameters.tsx | 20 +++++++++---------- .../reports/retention/RetentionParameters.tsx | 4 ++-- .../websites/[websiteId]/WebsiteData.tsx | 12 ++++++++--- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/app/(main)/reports/[reportId]/BaseParameters.tsx b/src/app/(main)/reports/[reportId]/BaseParameters.tsx index 1da70d2b..49c3347e 100644 --- a/src/app/(main)/reports/[reportId]/BaseParameters.tsx +++ b/src/app/(main)/reports/[reportId]/BaseParameters.tsx @@ -3,7 +3,7 @@ import { FormRow } from 'react-basics'; import { parseDateRange } from 'lib/date'; import DateFilter from 'components/input/DateFilter'; import WebsiteSelect from 'components/input/WebsiteSelect'; -import { useMessages, useTeamUrl } from 'components/hooks'; +import { useMessages, useTeamUrl, useWebsite } from 'components/hooks'; import { ReportContext } from './Report'; export interface BaseParametersProps { @@ -22,10 +22,11 @@ export function BaseParameters({ const { report, updateReport } = useContext(ReportContext); const { formatMessage, labels } = useMessages(); const { teamId } = useTeamUrl(); - const { parameters } = report || {}; const { websiteId, dateRange } = parameters || {}; const { value, startDate, endDate } = dateRange || {}; + const { data: website } = useWebsite(websiteId); + const { name } = website || {}; const handleWebsiteSelect = (websiteId: string) => { updateReport({ websiteId, parameters: { websiteId } }); @@ -39,8 +40,10 @@ export function BaseParameters({ <> {showWebsiteSelect && ( - {allowWebsiteSelect && ( + {allowWebsiteSelect ? ( + ) : ( + name )} )} diff --git a/src/app/(main)/reports/event-data/EventDataParameters.tsx b/src/app/(main)/reports/event-data/EventDataParameters.tsx index 2ee77a43..efa9fb67 100644 --- a/src/app/(main)/reports/event-data/EventDataParameters.tsx +++ b/src/app/(main)/reports/event-data/EventDataParameters.tsx @@ -29,7 +29,7 @@ function useFields(websiteId, startDate, endDate) { export function EventDataParameters() { const { report, runReport, updateReport, isRunning } = useContext(ReportContext); const { formatMessage, labels, messages } = useMessages(); - const { parameters } = report || {}; + const { id, parameters } = report || {}; const { websiteId, dateRange, fields, filters, groups } = parameters || {}; const { startDate, endDate } = dateRange || {}; const queryEnabled = websiteId && dateRange && fields?.length; @@ -93,7 +93,7 @@ export function EventDataParameters() { return ( - + {!hasData && } {parametersSelected && hasData && diff --git a/src/app/(main)/reports/funnel/FunnelParameters.tsx b/src/app/(main)/reports/funnel/FunnelParameters.tsx index c4f8f384..6eefbaae 100644 --- a/src/app/(main)/reports/funnel/FunnelParameters.tsx +++ b/src/app/(main)/reports/funnel/FunnelParameters.tsx @@ -22,7 +22,7 @@ export function FunnelParameters() { const { report, runReport, updateReport, isRunning } = useContext(ReportContext); const { formatMessage, labels } = useMessages(); - const { parameters } = report || {}; + const { id, parameters } = report || {}; const { websiteId, dateRange, urls } = parameters || {}; const queryDisabled = !websiteId || !dateRange || urls?.length < 2; @@ -62,7 +62,7 @@ export function FunnelParameters() { return ( - + - + {parametersSelected && parameterGroups.map(({ id, label }) => { return ( diff --git a/src/app/(main)/reports/retention/RetentionParameters.tsx b/src/app/(main)/reports/retention/RetentionParameters.tsx index 9bc1c548..f441177c 100644 --- a/src/app/(main)/reports/retention/RetentionParameters.tsx +++ b/src/app/(main)/reports/retention/RetentionParameters.tsx @@ -10,7 +10,7 @@ export function RetentionParameters() { const { report, runReport, isRunning, updateReport } = useContext(ReportContext); const { formatMessage, labels } = useMessages(); - const { parameters } = report || {}; + const { id, parameters } = report || {}; const { websiteId, dateRange } = parameters || {}; const { startDate } = dateRange || {}; const queryDisabled = !websiteId || !dateRange; @@ -30,7 +30,7 @@ export function RetentionParameters() { return ( - + diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx index c75ef74b..44872f88 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx @@ -1,6 +1,6 @@ import { Button, Modal, ModalTrigger, ActionForm, useToasts } from 'react-basics'; import { useRouter } from 'next/navigation'; -import { useMessages, useModified } from 'components/hooks'; +import { useMessages, useModified, useTeamUrl } from 'components/hooks'; import WebsiteDeleteForm from './WebsiteDeleteForm'; import WebsiteResetForm from './WebsiteResetForm'; @@ -9,6 +9,7 @@ export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: const router = useRouter(); const { showToast } = useToasts(); const { touch } = useModified(); + const { teamId, renderTeamUrl } = useTeamUrl(); const handleReset = async () => { showToast({ message: formatMessage(messages.saved), variant: 'success' }); @@ -16,8 +17,13 @@ export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: }; const handleDelete = async () => { - touch('websites'); - router.push('/settings/websites'); + if (teamId) { + touch('teams:websites'); + router.push(renderTeamUrl('/settings/websites')); + } else { + touch('websites'); + router.push('/settings/websites'); + } }; return ( From 642aba83e5355dc96f18dfdc507aaa5e212a8bbc Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 8 Feb 2024 11:47:32 -0800 Subject: [PATCH 112/142] Changed Admin tab to Manage. --- .../(main)/settings/teams/[teamId]/team/TeamDetails.tsx | 8 ++++---- .../teams/[teamId]/team/{TeamAdmin.tsx => TeamManage.tsx} | 4 ++-- src/components/layout/SideNav.module.css | 2 +- src/components/messages.ts | 2 +- src/index.ts | 2 +- src/lang/am-ET.json | 2 +- src/lang/ar-SA.json | 2 +- src/lang/be-BY.json | 2 +- src/lang/bn-BD.json | 2 +- src/lang/ca-ES.json | 2 +- src/lang/cs-CZ.json | 2 +- src/lang/da-DK.json | 2 +- src/lang/de-CH.json | 2 +- src/lang/de-DE.json | 2 +- src/lang/el-GR.json | 2 +- src/lang/en-GB.json | 2 +- src/lang/en-US.json | 2 +- src/lang/es-ES.json | 2 +- src/lang/fa-IR.json | 2 +- src/lang/fi-FI.json | 2 +- src/lang/fo-FO.json | 2 +- src/lang/fr-FR.json | 2 +- src/lang/ga-ES.json | 2 +- src/lang/he-IL.json | 2 +- src/lang/hi-IN.json | 2 +- src/lang/hr-HR.json | 2 +- src/lang/hu-HU.json | 2 +- src/lang/id-ID.json | 2 +- src/lang/it-IT.json | 2 +- src/lang/ja-JP.json | 2 +- src/lang/km-KH.json | 2 +- src/lang/ko-KR.json | 2 +- src/lang/lt-LT.json | 2 +- src/lang/mn-MN.json | 2 +- src/lang/ms-MY.json | 2 +- src/lang/my-MM.json | 2 +- src/lang/nb-NO.json | 2 +- src/lang/nl-NL.json | 2 +- src/lang/pl-PL.json | 2 +- src/lang/pt-BR.json | 2 +- src/lang/pt-PT.json | 2 +- src/lang/ro-RO.json | 2 +- src/lang/ru-RU.json | 2 +- src/lang/si-LK.json | 2 +- src/lang/sk-SK.json | 2 +- src/lang/sl-SI.json | 2 +- src/lang/sv-SE.json | 2 +- src/lang/ta-IN.json | 2 +- src/lang/th-TH.json | 2 +- src/lang/tr-TR.json | 2 +- src/lang/uk-UA.json | 2 +- src/lang/ur-PK.json | 2 +- src/lang/vi-VN.json | 2 +- src/lang/zh-CN.json | 2 +- src/lang/zh-TW.json | 2 +- 55 files changed, 59 insertions(+), 59 deletions(-) rename src/app/(main)/settings/teams/[teamId]/team/{TeamAdmin.tsx => TeamManage.tsx} (91%) diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx index 4fd97b60..0ce43fec 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamDetails.tsx @@ -6,7 +6,7 @@ import { ROLES } from 'lib/constants'; import { useContext, useState } from 'react'; import { Flexbox, Item, Tabs } from 'react-basics'; import TeamLeaveButton from '../../TeamLeaveButton'; -import TeamAdmin from './TeamAdmin'; +import TeamManage from './TeamManage'; import TeamEditForm from './TeamEditForm'; export function TeamDetails({ teamId }: { teamId: string }) { @@ -15,7 +15,7 @@ export function TeamDetails({ teamId }: { teamId: string }) { const { user } = useLogin(); const [tab, setTab] = useState('details'); - const canEdit = team?.teamUser?.find( + const canEdit = !!team?.teamUser?.find( ({ userId, role }) => role === ROLES.teamOwner && userId === user.id, ); @@ -26,10 +26,10 @@ export function TeamDetails({ teamId }: { teamId: string }) { setTab(value)} style={{ marginBottom: 30 }}> {formatMessage(labels.details)} - {canEdit && {formatMessage(labels.admin)}} + {canEdit && {formatMessage(labels.manage)}} {tab === 'details' && } - {tab === 'admin' && } + {tab === 'manage' && } ); } diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamManage.tsx similarity index 91% rename from src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx rename to src/app/(main)/settings/teams/[teamId]/team/TeamManage.tsx index 2c0a20d2..40cbee04 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamAdmin.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamManage.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/navigation'; import { ActionForm, Button, Modal, ModalTrigger } from 'react-basics'; import TeamDeleteForm from './TeamDeleteForm'; -export function TeamAdmin({ teamId }: { teamId: string }) { +export function TeamManage({ teamId }: { teamId: string }) { const { formatMessage, labels, messages } = useMessages(); const router = useRouter(); const { touch } = useModified(); @@ -30,4 +30,4 @@ export function TeamAdmin({ teamId }: { teamId: string }) { ); } -export default TeamAdmin; +export default TeamManage; diff --git a/src/components/layout/SideNav.module.css b/src/components/layout/SideNav.module.css index be80506a..ba347916 100644 --- a/src/components/layout/SideNav.module.css +++ b/src/components/layout/SideNav.module.css @@ -1,7 +1,7 @@ .menu { display: flex; flex-direction: column; - gap: 2px; + gap: 4px; } .item a { diff --git a/src/components/messages.ts b/src/components/messages.ts index 19f60b46..42a32cf5 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -17,7 +17,7 @@ export const labels = defineMessages({ role: { id: 'label.role', defaultMessage: 'Role' }, user: { id: 'label.user', defaultMessage: 'User' }, viewOnly: { id: 'label.view-only', defaultMessage: 'View only' }, - admin: { id: 'label.admin', defaultMessage: 'Admin' }, + manage: { id: 'label.manage', defaultMessage: 'Manage' }, administrator: { id: 'label.administrator', defaultMessage: 'Administrator' }, confirm: { id: 'label.confirm', defaultMessage: 'Confirm' }, details: { id: 'label.details', defaultMessage: 'Details' }, diff --git a/src/index.ts b/src/index.ts index 948923af..58b8ab6c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ export * from 'app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton export * from 'app/(main)/settings/teams/[teamId]/members/TeamMembersDataTable'; export * from 'app/(main)/settings/teams/[teamId]/members/TeamMembersTable'; -export * from 'app/(main)/settings/teams/[teamId]/team/TeamAdmin'; +export * from './app/(main)/settings/teams/[teamId]/team/TeamManage'; export * from 'app/(main)/settings/teams/[teamId]/team/TeamDeleteForm'; export * from 'app/(main)/settings/teams/[teamId]/team/TeamDetails'; export * from 'app/(main)/settings/teams/[teamId]/team/TeamEditForm'; diff --git a/src/lang/am-ET.json b/src/lang/am-ET.json index e79afb48..859a2ce2 100644 --- a/src/lang/am-ET.json +++ b/src/lang/am-ET.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Add website", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "All", "label.all-time": "All time", diff --git a/src/lang/ar-SA.json b/src/lang/ar-SA.json index 311e5430..427cb339 100644 --- a/src/lang/ar-SA.json +++ b/src/lang/ar-SA.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "إضافة موقع", - "label.admin": "مدير", + "label.administrator": "مدير", "label.after": "After", "label.all": "الكل", "label.all-time": "كل الوقت", diff --git a/src/lang/be-BY.json b/src/lang/be-BY.json index dc0be21d..dd56ab6c 100644 --- a/src/lang/be-BY.json +++ b/src/lang/be-BY.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Дадаць сайт", - "label.admin": "Адміністратар", + "label.administrator": "Адміністратар", "label.after": "After", "label.all": "Усё", "label.all-time": "Увесь час", diff --git a/src/lang/bn-BD.json b/src/lang/bn-BD.json index 201157ac..98cd96ac 100644 --- a/src/lang/bn-BD.json +++ b/src/lang/bn-BD.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "ওয়েবসাইট যুক্ত করুন", - "label.admin": "অ্যাডমিন", + "label.administrator": "অ্যাডমিন", "label.after": "After", "label.all": "সবগুলো", "label.all-time": "সব সময়", diff --git a/src/lang/ca-ES.json b/src/lang/ca-ES.json index e55d90da..806d2169 100644 --- a/src/lang/ca-ES.json +++ b/src/lang/ca-ES.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Afegeix lloc web", - "label.admin": "Administrador", + "label.administrator": "Administrador", "label.after": "After", "label.all": "Tots", "label.all-time": "Sempre", diff --git a/src/lang/cs-CZ.json b/src/lang/cs-CZ.json index 86f2043a..9cedf933 100644 --- a/src/lang/cs-CZ.json +++ b/src/lang/cs-CZ.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Přidat web", - "label.admin": "Administrátor", + "label.administrator": "Administrátor", "label.after": "After", "label.all": "Vše", "label.all-time": "All time", diff --git a/src/lang/da-DK.json b/src/lang/da-DK.json index 8df7dd6b..961011e2 100644 --- a/src/lang/da-DK.json +++ b/src/lang/da-DK.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Tilføj hjemmeside", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "Alle", "label.all-time": "Altid", diff --git a/src/lang/de-CH.json b/src/lang/de-CH.json index 95ba3b6a..c79c1d22 100644 --- a/src/lang/de-CH.json +++ b/src/lang/de-CH.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Websiite hinzuefüege", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "Alli", "label.all-time": "Gesamte Zitruum", diff --git a/src/lang/de-DE.json b/src/lang/de-DE.json index 1e98b14c..c469a3a4 100644 --- a/src/lang/de-DE.json +++ b/src/lang/de-DE.json @@ -5,7 +5,7 @@ "label.add": "Hinzufügen", "label.add-description": "Beschreibung hinzufügen", "label.add-website": "Website hinzufügen", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "Nach", "label.all": "Alle", "label.all-time": "Gesamter Zeitraum", diff --git a/src/lang/el-GR.json b/src/lang/el-GR.json index f93742fd..d5c06738 100644 --- a/src/lang/el-GR.json +++ b/src/lang/el-GR.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Προσθήκη ιστότοπου", - "label.admin": "Διαχειριστής", + "label.administrator": "Διαχειριστής", "label.after": "After", "label.all": "All", "label.all-time": "All time", diff --git a/src/lang/en-GB.json b/src/lang/en-GB.json index b6cb2c9a..71197e53 100644 --- a/src/lang/en-GB.json +++ b/src/lang/en-GB.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Add website", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "All", "label.all-time": "All time", diff --git a/src/lang/en-US.json b/src/lang/en-US.json index 2f957a45..aa7ddb90 100644 --- a/src/lang/en-US.json +++ b/src/lang/en-US.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Add website", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "All", "label.all-time": "All time", diff --git a/src/lang/es-ES.json b/src/lang/es-ES.json index e2827bec..0db1ebb5 100644 --- a/src/lang/es-ES.json +++ b/src/lang/es-ES.json @@ -5,7 +5,7 @@ "label.add": "Añadir", "label.add-description": "Añadir descripción", "label.add-website": "Nuevo sitio web", - "label.admin": "Administrador", + "label.administrator": "Administrador", "label.after": "Después", "label.all": "Todos", "label.all-time": "Todos los tiempos", diff --git a/src/lang/fa-IR.json b/src/lang/fa-IR.json index 0458e3c6..02700f1b 100644 --- a/src/lang/fa-IR.json +++ b/src/lang/fa-IR.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "افزودن وب‌سایت", - "label.admin": "مدیر", + "label.administrator": "مدیر", "label.after": "After", "label.all": "همه", "label.all-time": "همه زمان", diff --git a/src/lang/fi-FI.json b/src/lang/fi-FI.json index 52d88238..f8b09f45 100644 --- a/src/lang/fi-FI.json +++ b/src/lang/fi-FI.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Lisää verkkosivu", - "label.admin": "Järjestelmänvalvoja", + "label.administrator": "Järjestelmänvalvoja", "label.after": "After", "label.all": "Kaikki", "label.all-time": "Alusta lähtien", diff --git a/src/lang/fo-FO.json b/src/lang/fo-FO.json index ef5b0bc1..0d67276e 100644 --- a/src/lang/fo-FO.json +++ b/src/lang/fo-FO.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Legg heimasíðu afturat", - "label.admin": "Fyrisitari", + "label.administrator": "Fyrisitari", "label.after": "After", "label.all": "Alt", "label.all-time": "All time", diff --git a/src/lang/fr-FR.json b/src/lang/fr-FR.json index bb4a56a5..e2eef653 100644 --- a/src/lang/fr-FR.json +++ b/src/lang/fr-FR.json @@ -5,7 +5,7 @@ "label.add": "Ajouter", "label.add-description": "Ajouter une description", "label.add-website": "Ajouter un site", - "label.admin": "Administrateur", + "label.administrator": "Administrateur", "label.after": "Après", "label.all": "Tout", "label.all-time": "Toutes les données", diff --git a/src/lang/ga-ES.json b/src/lang/ga-ES.json index 2a2d16c9..3b33c2b5 100644 --- a/src/lang/ga-ES.json +++ b/src/lang/ga-ES.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Engadir sitio web", - "label.admin": "Administradora", + "label.administrator": "Administradora", "label.after": "After", "label.all": "Todo", "label.all-time": "Sempre", diff --git a/src/lang/he-IL.json b/src/lang/he-IL.json index 04912335..03956457 100644 --- a/src/lang/he-IL.json +++ b/src/lang/he-IL.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "הוספת אתר", - "label.admin": "מנהל", + "label.administrator": "מנהל", "label.after": "After", "label.all": "הכל", "label.all-time": "All time", diff --git a/src/lang/hi-IN.json b/src/lang/hi-IN.json index c872fd1a..c28d9166 100644 --- a/src/lang/hi-IN.json +++ b/src/lang/hi-IN.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "वेबसाइट", - "label.admin": "प्रशासक", + "label.administrator": "प्रशासक", "label.after": "After", "label.all": "सब", "label.all-time": "All time", diff --git a/src/lang/hr-HR.json b/src/lang/hr-HR.json index 55feb48b..836e6ba7 100644 --- a/src/lang/hr-HR.json +++ b/src/lang/hr-HR.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Dodaj web stranicu", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "Sve", "label.all-time": "Svo vrijeme", diff --git a/src/lang/hu-HU.json b/src/lang/hu-HU.json index 407687f2..3cf72159 100644 --- a/src/lang/hu-HU.json +++ b/src/lang/hu-HU.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Weboldal hozzáadása", - "label.admin": "Adminisztrátor", + "label.administrator": "Adminisztrátor", "label.after": "After", "label.all": "Összes", "label.all-time": "All time", diff --git a/src/lang/id-ID.json b/src/lang/id-ID.json index 64fed9e1..5a82edd5 100644 --- a/src/lang/id-ID.json +++ b/src/lang/id-ID.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Tambah situs web", - "label.admin": "Pengelola", + "label.administrator": "Pengelola", "label.after": "After", "label.all": "Semua", "label.all-time": "Semua waktu", diff --git a/src/lang/it-IT.json b/src/lang/it-IT.json index 29c664b5..f94486f8 100644 --- a/src/lang/it-IT.json +++ b/src/lang/it-IT.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Aggiungi sito", - "label.admin": "Amministratore", + "label.administrator": "Amministratore", "label.after": "After", "label.all": "Tutto", "label.all-time": "Sempre", diff --git a/src/lang/ja-JP.json b/src/lang/ja-JP.json index 8e26205e..9cd9d884 100644 --- a/src/lang/ja-JP.json +++ b/src/lang/ja-JP.json @@ -5,7 +5,7 @@ "label.add": "追加", "label.add-description": "説明を追加", "label.add-website": "Webサイトの追加", - "label.admin": "管理者", + "label.administrator": "管理者", "label.after": "直後", "label.all": "すべて", "label.all-time": "すべての時間帯", diff --git a/src/lang/km-KH.json b/src/lang/km-KH.json index 2333fe6b..6a163074 100644 --- a/src/lang/km-KH.json +++ b/src/lang/km-KH.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "បន្ថែមគេហទំព័រ", - "label.admin": "អ្នកគ្រប់គ្រង", + "label.administrator": "អ្នកគ្រប់គ្រង", "label.after": "After", "label.all": "ទាំងអស់", "label.all-time": "គ្រប់ពេល", diff --git a/src/lang/ko-KR.json b/src/lang/ko-KR.json index b4b7d566..d211a823 100644 --- a/src/lang/ko-KR.json +++ b/src/lang/ko-KR.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "웹사이트 추가", - "label.admin": "관리자", + "label.administrator": "관리자", "label.after": "After", "label.all": "전체", "label.all-time": "All time", diff --git a/src/lang/lt-LT.json b/src/lang/lt-LT.json index 13f2b06b..1c91916c 100644 --- a/src/lang/lt-LT.json +++ b/src/lang/lt-LT.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Pridėti svetainę", - "label.admin": "Administratorius", + "label.administrator": "Administratorius", "label.after": "After", "label.all": "Visi", "label.all-time": "Visas laikotarpis", diff --git a/src/lang/mn-MN.json b/src/lang/mn-MN.json index 100d43d8..5b2cf6b8 100644 --- a/src/lang/mn-MN.json +++ b/src/lang/mn-MN.json @@ -5,7 +5,7 @@ "label.add": "Нэмэх", "label.add-description": "Тайлбар нэмэх", "label.add-website": "Веб нэмэх", - "label.admin": "Админ", + "label.administrator": "Админ", "label.after": "Хойно", "label.all": "Бүх", "label.all-time": "Бүх цаг үеийн", diff --git a/src/lang/ms-MY.json b/src/lang/ms-MY.json index 256a4d0b..6b29c1e6 100644 --- a/src/lang/ms-MY.json +++ b/src/lang/ms-MY.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Tambah laman web", - "label.admin": "Pentadbir", + "label.administrator": "Pentadbir", "label.after": "After", "label.all": "Semua", "label.all-time": "All time", diff --git a/src/lang/my-MM.json b/src/lang/my-MM.json index 704e2949..72f6b128 100644 --- a/src/lang/my-MM.json +++ b/src/lang/my-MM.json @@ -5,7 +5,7 @@ "label.add": "ထပ်ထည့်မည်", "label.add-description": "အကြောင်းအရာဖော်ပြချက် ထည့်မည်", "label.add-website": "ဝက်ဘ်ဆိုဒ်ထည့်မည်", - "label.admin": "အက်ဒမင်", + "label.administrator": "အက်ဒမင်", "label.after": "ပြီးနောက်", "label.all": "အားလုံး", "label.all-time": "အချိန်အစမှအခုထိ", diff --git a/src/lang/nb-NO.json b/src/lang/nb-NO.json index 5744d211..df292936 100644 --- a/src/lang/nb-NO.json +++ b/src/lang/nb-NO.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Legg til nettsted", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "Alle", "label.all-time": "Noensinne", diff --git a/src/lang/nl-NL.json b/src/lang/nl-NL.json index 9dfcbb92..bdd0347a 100644 --- a/src/lang/nl-NL.json +++ b/src/lang/nl-NL.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Website koppelen", - "label.admin": "Beheerder", + "label.administrator": "Beheerder", "label.after": "After", "label.all": "Alles", "label.all-time": "Onbeperkt", diff --git a/src/lang/pl-PL.json b/src/lang/pl-PL.json index 37a77b2e..f8956087 100644 --- a/src/lang/pl-PL.json +++ b/src/lang/pl-PL.json @@ -5,7 +5,7 @@ "label.add": "Dodaj", "label.add-description": "Dodaj opis", "label.add-website": "Dodaj witrynę", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "Po", "label.all": "Wszystkie", "label.all-time": "Cały czas", diff --git a/src/lang/pt-BR.json b/src/lang/pt-BR.json index ae345986..63cc4f02 100644 --- a/src/lang/pt-BR.json +++ b/src/lang/pt-BR.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Adicionar site", - "label.admin": "Administrador", + "label.administrator": "Administrador", "label.after": "Depois", "label.all": "Todos", "label.all-time": "Todo o período", diff --git a/src/lang/pt-PT.json b/src/lang/pt-PT.json index 3e1df4de..71a306eb 100644 --- a/src/lang/pt-PT.json +++ b/src/lang/pt-PT.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Adicionar website", - "label.admin": "Administrador", + "label.administrator": "Administrador", "label.after": "After", "label.all": "Todos", "label.all-time": "Todo o tempo", diff --git a/src/lang/ro-RO.json b/src/lang/ro-RO.json index d3b9d3db..17f5da15 100644 --- a/src/lang/ro-RO.json +++ b/src/lang/ro-RO.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Adăugare site web", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "Toate", "label.all-time": "All time", diff --git a/src/lang/ru-RU.json b/src/lang/ru-RU.json index 3063cbfa..a2c3e27d 100644 --- a/src/lang/ru-RU.json +++ b/src/lang/ru-RU.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Добавить сайт", - "label.admin": "Администратор", + "label.administrator": "Администратор", "label.after": "After", "label.all": "Все", "label.all-time": "Все время", diff --git a/src/lang/si-LK.json b/src/lang/si-LK.json index d9a61eb0..fd21488a 100644 --- a/src/lang/si-LK.json +++ b/src/lang/si-LK.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "වෙබ් අඩවිය එක් කරන්න", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "After", "label.all": "සියල්ල", "label.all-time": "හැම වෙලාවෙම", diff --git a/src/lang/sk-SK.json b/src/lang/sk-SK.json index 7d9073dd..1ca9c173 100644 --- a/src/lang/sk-SK.json +++ b/src/lang/sk-SK.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Pridať web", - "label.admin": "Administrátor", + "label.administrator": "Administrátor", "label.after": "After", "label.all": "Všetko", "label.all-time": "All time", diff --git a/src/lang/sl-SI.json b/src/lang/sl-SI.json index 66ce08e0..dbe18272 100644 --- a/src/lang/sl-SI.json +++ b/src/lang/sl-SI.json @@ -5,7 +5,7 @@ "label.add": "Dodaj", "label.add-description": "Dodaj opis", "label.add-website": "Dodaj spletno mesto", - "label.admin": "Administrator", + "label.administrator": "Administrator", "label.after": "Po", "label.all": "Vsi", "label.all-time": "Ves čas", diff --git a/src/lang/sv-SE.json b/src/lang/sv-SE.json index 1696bbf0..c44824ae 100644 --- a/src/lang/sv-SE.json +++ b/src/lang/sv-SE.json @@ -5,7 +5,7 @@ "label.add": "Lägg till", "label.add-description": "Lägg till beskrivning", "label.add-website": "Lägg till webbplats", - "label.admin": "Administratör", + "label.administrator": "Administratör", "label.after": "Efter", "label.all": "Alla", "label.all-time": "Sedan början", diff --git a/src/lang/ta-IN.json b/src/lang/ta-IN.json index 53b7659e..9a9f3cbf 100644 --- a/src/lang/ta-IN.json +++ b/src/lang/ta-IN.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "வலைத்தளத்தைச் சேர்க்க", - "label.admin": "நிர்வாகியைச் சேர்க்க", + "label.administrator": "நிர்வாகியைச் சேர்க்க", "label.after": "After", "label.all": "எல்லாம்", "label.all-time": "All time", diff --git a/src/lang/th-TH.json b/src/lang/th-TH.json index ee2fc19c..4281b103 100644 --- a/src/lang/th-TH.json +++ b/src/lang/th-TH.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "เพิ่มเว็บไซต์", - "label.admin": "ผู้ดูแลระบบ", + "label.administrator": "ผู้ดูแลระบบ", "label.after": "After", "label.all": "ทั้งหมด", "label.all-time": "ทุกช่วงเวลา", diff --git a/src/lang/tr-TR.json b/src/lang/tr-TR.json index 6eac527b..98373891 100644 --- a/src/lang/tr-TR.json +++ b/src/lang/tr-TR.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Web sitesi ekle", - "label.admin": "Yönetici", + "label.administrator": "Yönetici", "label.after": "After", "label.all": "Tümü", "label.all-time": "All time", diff --git a/src/lang/uk-UA.json b/src/lang/uk-UA.json index 95995648..31f67053 100644 --- a/src/lang/uk-UA.json +++ b/src/lang/uk-UA.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Додати сайт", - "label.admin": "Адміністратор", + "label.administrator": "Адміністратор", "label.after": "After", "label.all": "Всі", "label.all-time": "Весь час", diff --git a/src/lang/ur-PK.json b/src/lang/ur-PK.json index 5edaddd8..723b72a3 100644 --- a/src/lang/ur-PK.json +++ b/src/lang/ur-PK.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "ویب سائٹ کا اضافہ کریں", - "label.admin": "منتظم", + "label.administrator": "منتظم", "label.after": "After", "label.all": "تمام", "label.all-time": "تمام وقت", diff --git a/src/lang/vi-VN.json b/src/lang/vi-VN.json index 9c629100..5eca11ae 100644 --- a/src/lang/vi-VN.json +++ b/src/lang/vi-VN.json @@ -5,7 +5,7 @@ "label.add": "Add", "label.add-description": "Add description", "label.add-website": "Thêm website", - "label.admin": "Quản trị", + "label.administrator": "Quản trị", "label.after": "After", "label.all": "Tất cả", "label.all-time": "Toàn thời gian", diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index 5eda0949..d34a7fec 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -5,7 +5,7 @@ "label.add": "添加", "label.add-description": "添加描述", "label.add-website": "添加网站", - "label.admin": "管理员", + "label.administrator": "管理员", "label.after": "之后", "label.all": "所有", "label.all-time": "所有时间段", diff --git a/src/lang/zh-TW.json b/src/lang/zh-TW.json index aed04d0c..b2920f23 100644 --- a/src/lang/zh-TW.json +++ b/src/lang/zh-TW.json @@ -5,7 +5,7 @@ "label.add": "新增", "label.add-description": "新增描述", "label.add-website": "新增網站", - "label.admin": "管理員", + "label.administrator": "管理員", "label.after": "之後", "label.all": "全部", "label.all-time": "所有時間", From c7e9190c9587295627c38c35be8f049cb98a3985 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 8 Feb 2024 13:01:39 -0800 Subject: [PATCH 113/142] add team member edit and remove confirmation --- .../[teamId]/members/TeamMemberEditButton.tsx | 49 ++++++++++++ .../[teamId]/members/TeamMemberEditForm.tsx | 78 +++++++++++++++++++ .../members/TeamMemberRemoveButton.tsx | 48 ++++++++---- .../[teamId]/members/TeamMembersTable.tsx | 11 ++- src/components/messages.ts | 9 ++- src/lib/constants.ts | 4 +- .../api/teams/[teamId]/users/[userId].ts | 2 +- 7 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditButton.tsx create mode 100644 src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditForm.tsx diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditButton.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditButton.tsx new file mode 100644 index 00000000..31186055 --- /dev/null +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditButton.tsx @@ -0,0 +1,49 @@ +import { useMessages, useModified } from 'components/hooks'; +import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; +import TeamMemberEditForm from './TeamMemberEditForm'; + +export function TeamMemberEditButton({ + teamId, + userId, + role, + onSave, +}: { + teamId: string; + userId: string; + role: string; + onSave?: () => void; +}) { + const { formatMessage, labels, messages } = useMessages(); + const { showToast } = useToasts(); + const { touch } = useModified(); + + const handleSave = () => { + showToast({ message: formatMessage(messages.saved), variant: 'success' }); + touch('teams:members'); + onSave?.(); + }; + + return ( + + + + {(close: () => void) => ( + + )} + + + ); +} + +export default TeamMemberEditButton; diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditForm.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditForm.tsx new file mode 100644 index 00000000..b54757e7 --- /dev/null +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberEditForm.tsx @@ -0,0 +1,78 @@ +import { useApi, useMessages } from 'components/hooks'; +import { ROLES } from 'lib/constants'; +import { + Button, + Dropdown, + Form, + FormButtons, + FormInput, + FormRow, + Item, + SubmitButton, +} from 'react-basics'; + +export function UserAddForm({ + teamId, + userId, + role, + onSave, + onClose, +}: { + teamId: string; + userId: string; + role: string; + onSave?: () => void; + onClose?: () => void; +}) { + const { post, useMutation } = useApi(); + const { mutate, error, isPending } = useMutation({ + mutationFn: (data: any) => post(`/teams/${teamId}/users/${userId}`, data), + }); + const { formatMessage, labels } = useMessages(); + + const handleSubmit = async (data: any) => { + mutate(data, { + onSuccess: async () => { + onSave(); + onClose(); + }, + }); + }; + + const renderValue = (value: string) => { + if (value === ROLES.teamMember) { + return formatMessage(labels.teamMember); + } + if (value === ROLES.teamViewOnly) { + return formatMessage(labels.viewOnly); + } + }; + + return ( + + + + + {formatMessage(labels.teamMember)} + {formatMessage(labels.viewOnly)} + + + + + + {formatMessage(labels.save)} + + + + + ); +} + +export default UserAddForm; diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx index bb944061..f19d857b 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMemberRemoveButton.tsx @@ -1,44 +1,64 @@ +import ConfirmationForm from 'components/common/ConfirmationForm'; import { useApi, useMessages, useModified } from 'components/hooks'; -import { Icon, Icons, LoadingButton, Text } from 'react-basics'; +import { messages } from 'components/messages'; +import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; +import { FormattedMessage } from 'react-intl'; export function TeamMemberRemoveButton({ teamId, userId, - disabled, + userName, onSave, }: { teamId: string; userId: string; + userName: string; disabled?: boolean; onSave?: () => void; }) { const { formatMessage, labels } = useMessages(); const { del, useMutation } = useApi(); - const { mutate, isPending } = useMutation({ + const { mutate, isPending, error } = useMutation({ mutationFn: () => del(`/teams/${teamId}/users/${userId}`), }); const { touch } = useModified(); - const handleRemoveTeamMember = () => { + const handleConfirm = (close: () => void) => { mutate(null, { onSuccess: () => { touch('teams:members'); onSave?.(); + close(); }, }); }; return ( - handleRemoveTeamMember()} - disabled={disabled} - isLoading={isPending} - > - - - - {formatMessage(labels.remove)} - + + + + {(close: () => void) => ( + {userName} }} + /> + } + isLoading={isPending} + error={error} + onConfirm={handleConfirm.bind(null, close)} + onClose={close} + buttonLabel={formatMessage(labels.remove)} + /> + )} + + ); } diff --git a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx index 0b60293a..2f3f75c2 100644 --- a/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx +++ b/src/app/(main)/settings/teams/[teamId]/members/TeamMembersTable.tsx @@ -2,6 +2,7 @@ import { GridColumn, GridTable, useBreakpoint } from 'react-basics'; import { useMessages, useLogin } from 'components/hooks'; import { ROLES } from 'lib/constants'; import TeamMemberRemoveButton from './TeamMemberRemoveButton'; +import TeamMemberEditButton from './TeamMemberEditButton'; export function TeamMembersTable({ data = [], @@ -19,6 +20,7 @@ export function TeamMembersTable({ const roles = { [ROLES.teamOwner]: formatMessage(labels.teamOwner), [ROLES.teamMember]: formatMessage(labels.teamMember), + [ROLES.teamViewOnly]: formatMessage(labels.viewOnly), }; return ( @@ -35,7 +37,14 @@ export function TeamMembersTable({ allowEdit && row?.role !== ROLES.teamOwner && user?.id !== row?.id && ( - + <> + + + ) ); }} diff --git a/src/components/messages.ts b/src/components/messages.ts index 19f60b46..0577f8c6 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -42,7 +42,7 @@ export const labels = defineMessages({ owner: { id: 'label.owner', defaultMessage: 'Owner' }, teamOwner: { id: 'label.team-owner', defaultMessage: 'Team owner' }, teamMember: { id: 'label.team-member', defaultMessage: 'Team member' }, - teamGuest: { id: 'label.team-guest', defaultMessage: 'Team guest' }, + teamViewOnly: { id: 'label.team-view-only', defaultMessage: 'Team view only' }, enableShareUrl: { id: 'label.enable-share-url', defaultMessage: 'Enable share URL' }, data: { id: 'label.data', defaultMessage: 'Data' }, trackingCode: { id: 'label.tracking-code', defaultMessage: 'Tracking code' }, @@ -56,6 +56,8 @@ export const labels = defineMessages({ reset: { id: 'label.reset', defaultMessage: 'Reset' }, addWebsite: { id: 'label.add-website', defaultMessage: 'Add website' }, addMember: { id: 'label.add-member', defaultMessage: 'Add member' }, + editMember: { id: 'label.edit-member', defaultMessage: 'Edit member' }, + removeMember: { id: 'label.remove-member', defaultMessage: 'Remove member' }, addDescription: { id: 'label.add-description', defaultMessage: 'Add description' }, changePassword: { id: 'label.change-password', defaultMessage: 'Change password' }, currentPassword: { id: 'label.current-password', defaultMessage: 'Current password' }, @@ -109,6 +111,7 @@ export const labels = defineMessages({ allTime: { id: 'label.all-time', defaultMessage: 'All time' }, customRange: { id: 'label.custom-range', defaultMessage: 'Custom range' }, selectWebsite: { id: 'label.select-website', defaultMessage: 'Select website' }, + selectRole: { id: 'label.select-role', defaultMessage: 'Select role' }, selectDate: { id: 'label.select-date', defaultMessage: 'Select date' }, all: { id: 'label.all', defaultMessage: 'All' }, sessions: { id: 'label.sessions', defaultMessage: 'Sessions' }, @@ -220,6 +223,10 @@ export const messages = defineMessages({ id: 'message.confirm-delete', defaultMessage: 'Are you sure you want to delete {target}?', }, + confirmRemove: { + id: 'message.confirm-remove', + defaultMessage: 'Are you sure you want to remove {target}?', + }, confirmLeave: { id: 'message.confirm-leave', defaultMessage: 'Are you sure you want to leave {target}?', diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 1dc1c0d5..97535899 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -125,7 +125,7 @@ export const ROLES = { viewOnly: 'view-only', teamOwner: 'team-owner', teamMember: 'team-member', - teamGuest: 'team-guest', + teamViewOnly: 'team-view-only', } as const; export const PERMISSIONS = { @@ -159,7 +159,7 @@ export const ROLE_PERMISSIONS = { PERMISSIONS.websiteUpdate, PERMISSIONS.websiteDelete, ], - [ROLES.teamGuest]: [], + [ROLES.teamViewOnly]: [], } as const; export const THEME_COLORS = { diff --git a/src/pages/api/teams/[teamId]/users/[userId].ts b/src/pages/api/teams/[teamId]/users/[userId].ts index 02e5eecd..4b52fe3e 100644 --- a/src/pages/api/teams/[teamId]/users/[userId].ts +++ b/src/pages/api/teams/[teamId]/users/[userId].ts @@ -23,7 +23,7 @@ const schema = { POST: yup.object().shape({ role: yup .string() - .matches(/team-member|team-guest/i) + .matches(/team-member|team-view-only/i) .required(), }), }; From 56441a4157ddb3a8c96ae87072a7e15cfd286494 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 8 Feb 2024 13:40:44 -0800 Subject: [PATCH 114/142] Moved menu items to match cloud. --- .../teams/[teamId]/settings/TeamSettingsLayout.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx b/src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx index 5c2f2502..5f894228 100644 --- a/src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx +++ b/src/app/(main)/teams/[teamId]/settings/TeamSettingsLayout.tsx @@ -12,16 +12,16 @@ export default function ({ children, teamId }: { children: ReactNode; teamId: st label: formatMessage(labels.team), url: `/teams/${teamId}/settings/team`, }, - { - key: 'members', - label: formatMessage(labels.members), - url: `/teams/${teamId}/settings/members`, - }, { key: 'websites', label: formatMessage(labels.websites), url: `/teams/${teamId}/settings/websites`, }, + { + key: 'members', + label: formatMessage(labels.members), + url: `/teams/${teamId}/settings/members`, + }, ].filter(n => n); return {children}; From 6b381e71579e7cc39897593dcbcfb6e7c09435a0 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 8 Feb 2024 13:44:51 -0800 Subject: [PATCH 115/142] Remove team access code functionality from cloud mode --- src/app/(main)/settings/teams/TeamsHeader.tsx | 3 ++- src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/settings/teams/TeamsHeader.tsx b/src/app/(main)/settings/teams/TeamsHeader.tsx index 4c040691..a656e500 100644 --- a/src/app/(main)/settings/teams/TeamsHeader.tsx +++ b/src/app/(main)/settings/teams/TeamsHeader.tsx @@ -8,11 +8,12 @@ import TeamsAddButton from './TeamsAddButton'; export function TeamsHeader({ allowCreate = true }: { allowCreate?: boolean }) { const { formatMessage, labels } = useMessages(); const { user } = useLogin(); + const cloudMode = process.env.CLOUD_MODE; return ( - + {!cloudMode && } {allowCreate && user.role !== ROLES.viewOnly && } diff --git a/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx b/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx index cee3c3f1..d81bd01e 100644 --- a/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx +++ b/src/app/(main)/settings/teams/[teamId]/team/TeamEditForm.tsx @@ -26,6 +26,7 @@ export function TeamEditForm({ teamId, allowEdit }: { teamId: string; allowEdit? const ref = useRef(null); const [accessCode, setAccessCode] = useState(team.accessCode); const { showToast } = useToasts(); + const cloudMode = process.env.CLOUD_MODE; const handleSubmit = async (data: any) => { mutate(data, { @@ -58,7 +59,7 @@ export function TeamEditForm({ teamId, allowEdit }: { teamId: string; allowEdit? )} {!allowEdit && team.name} - {allowEdit && ( + {!cloudMode && allowEdit && ( From e8d8a8a84a0b84518be8ca495d0a997ee1a2a77f Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 8 Feb 2024 14:05:35 -0800 Subject: [PATCH 116/142] Fix buttons / dropdown values --- src/app/(main)/reports/ReportDeleteButton.tsx | 2 +- .../teams/[teamId]/members/TeamMemberEditButton.tsx | 2 +- .../teams/[teamId]/members/TeamMemberEditForm.tsx | 8 ++++---- .../teams/[teamId]/members/TeamMemberRemoveButton.tsx | 2 +- src/components/messages.ts | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/app/(main)/reports/ReportDeleteButton.tsx b/src/app/(main)/reports/ReportDeleteButton.tsx index 7ad9c465..d51f7144 100644 --- a/src/app/(main)/reports/ReportDeleteButton.tsx +++ b/src/app/(main)/reports/ReportDeleteButton.tsx @@ -30,7 +30,7 @@ export function ReportDeleteButton({ return ( - + + {(close: () => void) => ( + + )} + + + void; + onClose?: () => void; +}) { + const { user } = useLogin(); + const website = useContext(WebsiteContext); + const [teamId, setTeamId] = useState(null); + const { formatMessage, labels, messages } = useMessages(); + const { post, useMutation } = useApi(); + const { mutate, isPending, error } = useMutation({ + mutationFn: (data: any) => post(`/websites/${websiteId}/transfer`, data), + }); + const { result, query } = useTeams(user.id); + const isTeamWebsite = !!website?.teamId; + const { showToast } = useToasts(); + + const handleSubmit = async () => { + mutate( + { + userId: website.teamId ? user.id : undefined, + teamId: website.userId ? teamId : undefined, + }, + { + onSuccess: async () => { + showToast({ message: formatMessage(messages.saved), variant: 'success' }); + onSave?.(); + onClose?.(); + }, + }, + ); + }; + + const handleChange = (key: Key) => { + setTeamId(key as string); + }; + + const renderValue = (teamId: string) => result?.data?.find(({ id }) => id === teamId)?.name; + + if (query.isLoading) { + return ; + } + + return ( +
+ + + {formatMessage( + isTeamWebsite ? messages.transferTeamWebsiteToUser : messages.transferUserWebsiteToTeam, + )} + {!isTeamWebsite && ( + + {result.data + .filter(({ teamUser }) => + teamUser.find( + ({ role, userId }) => role === ROLES.teamOwner && userId === user.id, + ), + ) + .map(({ id, name }) => { + return {name}; + })} + + )} + + + + + {formatMessage(labels.transfer)} + + + +
+ ); +} + +export default WebsiteTransferForm; diff --git a/src/components/common/DataTable.tsx b/src/components/common/DataTable.tsx index 9ef41875..4bca7fc3 100644 --- a/src/components/common/DataTable.tsx +++ b/src/components/common/DataTable.tsx @@ -5,7 +5,7 @@ import { useMessages } from 'components/hooks'; import Empty from 'components/common/Empty'; import Pager from 'components/common/Pager'; import styles from './DataTable.module.css'; -import { FilterQueryResult } from 'components/hooks'; +import { FilterQueryResult } from 'lib/types'; const DEFAULT_SEARCH_DELAY = 600; @@ -64,7 +64,7 @@ export function DataTable({ className={classNames(styles.body, { [styles.status]: isLoading || noResults || !hasData })} > {hasData ? (typeof children === 'function' ? children(result) : children) : null} - {isLoading && } + {isLoading && } {!isLoading && !hasData && !query && } {noResults && }
diff --git a/src/components/hooks/queries/useFilterQuery.ts b/src/components/hooks/queries/useFilterQuery.ts index 7e4c9a86..e51d70a1 100644 --- a/src/components/hooks/queries/useFilterQuery.ts +++ b/src/components/hooks/queries/useFilterQuery.ts @@ -1,14 +1,7 @@ import { UseQueryOptions } from '@tanstack/react-query'; -import { useState, Dispatch, SetStateAction } from 'react'; +import { useState } from 'react'; import { useApi } from './useApi'; -import { FilterResult, SearchFilter } from 'lib/types'; - -export interface FilterQueryResult { - result: FilterResult; - query: any; - params: SearchFilter; - setParams: Dispatch>; -} +import { FilterResult, SearchFilter, FilterQueryResult } from 'lib/types'; export function useFilterQuery({ queryKey, diff --git a/src/components/layout/SideNav.module.css b/src/components/layout/SideNav.module.css index ba347916..5d9af915 100644 --- a/src/components/layout/SideNav.module.css +++ b/src/components/layout/SideNav.module.css @@ -17,5 +17,4 @@ .selected { font-weight: 700; - background: var(--base75); } diff --git a/src/components/messages.ts b/src/components/messages.ts index b201c198..f9d518ed 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -53,6 +53,7 @@ export const labels = defineMessages({ websiteId: { id: 'label.website-id', defaultMessage: 'Website ID' }, resetWebsite: { id: 'label.reset-website', defaultMessage: 'Reset website' }, deleteWebsite: { id: 'label.delete-website', defaultMessage: 'Delete website' }, + transferWebsite: { id: 'label.transfer-website', defaultMessage: 'Transfer website' }, deleteReport: { id: 'label.delete-report', defaultMessage: 'Delete report' }, reset: { id: 'label.reset', defaultMessage: 'Reset' }, addWebsite: { id: 'label.add-website', defaultMessage: 'Add website' }, @@ -207,7 +208,7 @@ export const labels = defineMessages({ }, select: { id: 'label.select', defaultMessage: 'Select' }, myAccount: { id: 'label.my-account', defaultMessage: 'My account' }, - switch: { id: 'label.switch', defaultMessage: 'Switch' }, + transfer: { id: 'label.transfer', defaultMessage: 'Transfer' }, }); export const messages = defineMessages({ @@ -327,4 +328,16 @@ export const messages = defineMessages({ id: 'message.new-version-available', defaultMessage: 'A new version of Umami {version} is available!', }, + transferWebsite: { + id: 'message.transfer-website', + defaultMessage: 'Transfer website ownership to another user or team.', + }, + transferTeamWebsiteToUser: { + id: 'message.transfer-team-website-to-user', + defaultMessage: 'Do you want to transfer this website to your account?', + }, + transferUserWebsiteToTeam: { + id: 'message.transfer-user-website-to-team', + defaultMessage: 'Which team do you want to transfer this website to?', + }, }); diff --git a/src/lib/auth.ts b/src/lib/auth.ts index eb310015..ee3defea 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,7 +1,7 @@ import { Report } from '@prisma/client'; import redis from '@umami/redis-client'; import debug from 'debug'; -import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants'; +import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER, ROLES } from 'lib/constants'; import { secret } from 'lib/crypto'; import { NextApiRequest } from 'next'; import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics'; @@ -101,6 +101,38 @@ export async function canUpdateWebsite({ user }: Auth, websiteId: string) { return false; } +export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string, userId: string) { + if (user.isAdmin) { + return true; + } + + const website = await loadWebsite(websiteId); + + if (website.teamId && user.id === userId) { + const teamUser = await getTeamUser(website.teamId, userId); + + return teamUser?.role === ROLES.teamOwner; + } + + return false; +} + +export async function canTransferWebsiteToTeam({ user }: Auth, websiteId: string, teamId: string) { + if (user.isAdmin) { + return true; + } + + const website = await loadWebsite(websiteId); + + if (website.userId === user.id) { + const teamUser = await getTeamUser(teamId, user.id); + + return teamUser?.role === ROLES.teamOwner; + } + + return false; +} + export async function canDeleteWebsite({ user }: Auth, websiteId: string) { if (user.isAdmin) { return true; diff --git a/src/lib/types.ts b/src/lib/types.ts index b885d1ae..ecba0a6f 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -10,6 +10,7 @@ import { } from './constants'; import * as yup from 'yup'; import { TIME_UNIT } from './date'; +import { Dispatch, SetStateAction } from 'react'; type ObjectValues = T[keyof T]; @@ -64,6 +65,13 @@ export interface FilterResult { sortDescending?: boolean; } +export interface FilterQueryResult { + result: FilterResult; + query: any; + params: SearchFilter; + setParams: Dispatch>; +} + export interface DynamicData { [key: string]: number | string | DynamicData | number[] | string[] | DynamicData[]; } diff --git a/src/pages/api/websites/[websiteId]/transfer.ts b/src/pages/api/websites/[websiteId]/transfer.ts new file mode 100644 index 00000000..56cf6bac --- /dev/null +++ b/src/pages/api/websites/[websiteId]/transfer.ts @@ -0,0 +1,66 @@ +import { NextApiRequestQueryBody } from 'lib/types'; +import { canTransferWebsiteToTeam, canTransferWebsiteToUser } from 'lib/auth'; +import { useAuth, useCors, useValidate } from 'lib/middleware'; +import { NextApiResponse } from 'next'; +import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; +import { updateWebsite } from 'queries'; +import * as yup from 'yup'; + +export interface WebsiteTransferRequestQuery { + websiteId: string; +} + +export interface WebsiteTransferRequestBody { + userId?: string; + teamId?: string; +} + +const schema = { + POST: yup.object().shape({ + websiteId: yup.string().uuid().required(), + userId: yup.string().uuid(), + teamId: yup.string().uuid(), + }), +}; + +export default async ( + req: NextApiRequestQueryBody, + res: NextApiResponse, +) => { + await useCors(req, res); + await useAuth(req, res); + await useValidate(schema, req, res); + + const { websiteId } = req.query; + const { userId, teamId } = req.body; + + if (req.method === 'POST') { + if (userId) { + if (!(await canTransferWebsiteToUser(req.auth, websiteId, userId))) { + return unauthorized(res); + } + + const website = await updateWebsite(websiteId, { + userId, + teamId: null, + }); + + return ok(res, website); + } else if (teamId) { + if (!(await canTransferWebsiteToTeam(req.auth, websiteId, teamId))) { + return unauthorized(res); + } + + const website = await updateWebsite(websiteId, { + userId: null, + teamId, + }); + + return ok(res, website); + } + + return badRequest(res); + } + + return methodNotAllowed(res); +}; From 0be4a9b41654bdad34603a6aba704b459683fb5f Mon Sep 17 00:00:00 2001 From: Maxime-J Date: Sat, 10 Feb 2024 12:47:02 +0000 Subject: [PATCH 124/142] Render correct OS names globally. --- src/components/hooks/useFormat.ts | 22 ++++++++++++++-------- src/components/metrics/OSTable.tsx | 10 +++------- src/lib/constants.ts | 8 ++++++++ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/components/hooks/useFormat.ts b/src/components/hooks/useFormat.ts index 06585e49..2b4d0200 100644 --- a/src/components/hooks/useFormat.ts +++ b/src/components/hooks/useFormat.ts @@ -1,5 +1,5 @@ import useMessages from './useMessages'; -import { BROWSERS } from 'lib/constants'; +import { BROWSERS, OS_NAMES } from 'lib/constants'; import useLocale from './useLocale'; import useCountryNames from './useCountryNames'; import regions from 'public/iso-3166-2.json'; @@ -9,10 +9,18 @@ export function useFormat() { const { locale } = useLocale(); const countryNames = useCountryNames(locale); + const formatOS = (value: string): string => { + return OS_NAMES[value] || value; + }; + const formatBrowser = (value: string): string => { return BROWSERS[value] || value; }; + const formatDevice = (value: string): string => { + return formatMessage(labels[value] || labels.unknown); + }; + const formatCountry = (value: string): string => { return countryNames[value] || value; }; @@ -26,28 +34,26 @@ export function useFormat() { return `${value}, ${countryNames[country]}`; }; - const formatDevice = (value: string): string => { - return formatMessage(labels[value] || labels.unknown); - }; - const formatValue = (value: string, type: string, data?: { [key: string]: any }): string => { switch (type) { + case 'os': + return formatOS(value); case 'browser': return formatBrowser(value); + case 'device': + return formatDevice(value); case 'country': return formatCountry(value); case 'region': return formatRegion(value); case 'city': return formatCity(value, data?.country); - case 'device': - return formatDevice(value); default: return value; } }; - return { formatBrowser, formatCountry, formatRegion, formatDevice, formatValue }; + return { formatOS, formatBrowser, formatDevice, formatCountry, formatRegion, formatValue }; } export default useFormat; diff --git a/src/components/metrics/OSTable.tsx b/src/components/metrics/OSTable.tsx index 102bafd3..d262c36a 100644 --- a/src/components/metrics/OSTable.tsx +++ b/src/components/metrics/OSTable.tsx @@ -1,19 +1,15 @@ import MetricsTable, { MetricsTableProps } from './MetricsTable'; import FilterLink from 'components/common/FilterLink'; import useMessages from 'components/hooks/useMessages'; - -const names = { - 'Mac OS': 'macOS', - 'Chrome OS': 'ChromeOS', - 'Sun OS': 'SunOS', -}; +import useFormat from 'components/hooks/useFormat'; export function OSTable(props: MetricsTableProps) { const { formatMessage, labels } = useMessages(); + const { formatOS } = useFormat(); function renderLink({ x: os }) { return ( - + Date: Sat, 10 Feb 2024 08:57:23 -0800 Subject: [PATCH 125/142] Added exports to components lib. --- src/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 3f577bc4..465de67e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -43,10 +43,11 @@ export * from 'app/(main)/settings/websites/WebsitesTable'; export * from 'app/(main)/teams/[teamId]/TeamProvider'; export * from 'app/(main)/websites/[websiteId]/WebsiteProvider'; -export * from 'components/common/TypeConfirmationForm'; +export * from 'components/common/ConfirmationForm'; export * from 'components/common/DataTable'; export * from 'components/common/Empty'; export * from 'components/common/ErrorBoundary'; +export * from 'components/common/ErrorMessage'; export * from 'components/common/Favicon'; export * from 'components/common/FilterButtons'; export * from 'components/common/FilterLink'; @@ -55,6 +56,7 @@ export * from 'components/common/HoverTooltip'; export * from 'components/common/LinkButton'; export * from 'components/common/MobileMenu'; export * from 'components/common/Pager'; +export * from 'components/common/TypeConfirmationForm'; export * from 'components/input/TeamsButton'; export * from 'components/input/ThemeButton'; From a3f73826738bf639da8a23c8ba698234249da50b Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 10 Feb 2024 23:47:26 -0800 Subject: [PATCH 126/142] Added additional logic for handling website transfers. --- .../websites/[websiteId]/WebsiteData.tsx | 63 ++++++++++--------- .../websites/[websiteId]/WebsiteSettings.tsx | 11 +++- src/components/messages.ts | 6 +- src/lib/auth.ts | 8 --- 4 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx index 410f1783..c43b29bf 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteData.tsx @@ -1,53 +1,54 @@ -import { Button, Modal, ModalTrigger, ActionForm, useToasts } from 'react-basics'; +import { Button, Modal, ModalTrigger, ActionForm } from 'react-basics'; import { useRouter } from 'next/navigation'; -import { useMessages, useModified, useTeamUrl } from 'components/hooks'; +import { useLogin, useMessages, useModified, useTeamUrl } from 'components/hooks'; import WebsiteDeleteForm from './WebsiteDeleteForm'; import WebsiteResetForm from './WebsiteResetForm'; import WebsiteTransferForm from './WebsiteTransferForm'; +import { ROLES } from 'lib/constants'; export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); - const router = useRouter(); - const { showToast } = useToasts(); + const { user } = useLogin(); const { touch } = useModified(); const { teamId, renderTeamUrl } = useTeamUrl(); + const router = useRouter(); + const hasTeams = user?.teams?.length > 0; + const isTeamOwner = + (!teamId && hasTeams) || + (hasTeams && + user?.teams + ?.find(({ id }) => id === teamId) + ?.teamUser.find(({ role, userId }) => role === ROLES.teamOwner && userId === user.id)); - const handleTransfer = () => { + const handleSave = () => { touch('websites'); - + onSave?.(); router.push(renderTeamUrl(`/settings/websites`)); }; const handleReset = async () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); onSave?.(); }; - const handleDelete = async () => { - touch('websites'); - - if (teamId) { - router.push(renderTeamUrl('/settings/websites')); - } else { - router.push('/settings/websites'); - } - }; - return ( <> - - - - - {(close: () => void) => ( - - )} - - - + {process.env.cloudMode && ( + + + + + {(close: () => void) => ( + + )} + + + + )} {formatMessage(labels.delete)} {(close: () => void) => ( - + )} diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx index 24bf3d02..af7723ae 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx @@ -1,5 +1,5 @@ import { useState, Key, useContext } from 'react'; -import { Item, Tabs, Button, Text, Icon } from 'react-basics'; +import { Item, Tabs, Button, Text, Icon, useToasts } from 'react-basics'; import Link from 'next/link'; import Icons from 'components/icons'; import PageHeader from 'components/layout/PageHeader'; @@ -12,8 +12,13 @@ import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider' export function WebsiteSettings({ websiteId, openExternal = false }) { const website = useContext(WebsiteContext); - const { formatMessage, labels } = useMessages(); + const { formatMessage, labels, messages } = useMessages(); const [tab, setTab] = useState('details'); + const { showToast } = useToasts(); + + const handleSave = () => { + showToast({ message: formatMessage(messages.saved), variant: 'success' }); + }; return ( <> @@ -36,7 +41,7 @@ export function WebsiteSettings({ websiteId, openExternal = false }) { {tab === 'details' && } {tab === 'tracking' && } {tab === 'share' && } - {tab === 'data' && } + {tab === 'data' && } ); } diff --git a/src/components/messages.ts b/src/components/messages.ts index f9d518ed..2710e99d 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -330,14 +330,14 @@ export const messages = defineMessages({ }, transferWebsite: { id: 'message.transfer-website', - defaultMessage: 'Transfer website ownership to another user or team.', + defaultMessage: 'Transfer website ownership to your account or another team.', }, transferTeamWebsiteToUser: { id: 'message.transfer-team-website-to-user', - defaultMessage: 'Do you want to transfer this website to your account?', + defaultMessage: 'Transfer this website to your account?', }, transferUserWebsiteToTeam: { id: 'message.transfer-user-website-to-team', - defaultMessage: 'Which team do you want to transfer this website to?', + defaultMessage: 'Select the team to transfer this website to.', }, }); diff --git a/src/lib/auth.ts b/src/lib/auth.ts index ee3defea..92ec23bb 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -102,10 +102,6 @@ export async function canUpdateWebsite({ user }: Auth, websiteId: string) { } export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string, userId: string) { - if (user.isAdmin) { - return true; - } - const website = await loadWebsite(websiteId); if (website.teamId && user.id === userId) { @@ -118,10 +114,6 @@ export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string } export async function canTransferWebsiteToTeam({ user }: Auth, websiteId: string, teamId: string) { - if (user.isAdmin) { - return true; - } - const website = await loadWebsite(websiteId); if (website.userId === user.id) { From d5f91763e5c01978838b6350d78f34d907ca1f3a Mon Sep 17 00:00:00 2001 From: GimliForge <159722618+GimliForge@users.noreply.github.com> Date: Sun, 11 Feb 2024 19:58:42 -0500 Subject: [PATCH 127/142] Update nextjs version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f437c35..4eec520f 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ }, "devDependencies": { "@formatjs/cli": "^4.2.29", - "@netlify/plugin-nextjs": "^4.27.3", + "@netlify/plugin-nextjs": "^4.41.3", "@rollup/plugin-alias": "^5.0.0", "@rollup/plugin-buble": "^1.0.2", "@rollup/plugin-commonjs": "^25.0.4", From c10e9779512fb464a76afc2d228022c74e685a84 Mon Sep 17 00:00:00 2001 From: jermanuts <109705802+jermanuts@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:53:24 +0300 Subject: [PATCH 128/142] Update ar-SA.json --- src/lang/ar-SA.json | 222 ++++++++++++++++++++++---------------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/src/lang/ar-SA.json b/src/lang/ar-SA.json index 311e5430..46c035c5 100644 --- a/src/lang/ar-SA.json +++ b/src/lang/ar-SA.json @@ -2,153 +2,153 @@ "label.access-code": "كود الدعوة", "label.actions": "الإجراءات", "label.activity-log": "سجل الأحداث", - "label.add": "Add", - "label.add-description": "Add description", + "label.add": "أضِف", + "label.add-description": "أضِف وصف", "label.add-website": "إضافة موقع", "label.admin": "مدير", - "label.after": "After", + "label.after": "يعد", "label.all": "الكل", "label.all-time": "كل الوقت", "label.analytics": "تحليلات", - "label.average": "Average", + "label.average": "المتوسط", "label.average-visit-time": "متوسط وقت الزيارة", "label.back": "للخلف", - "label.before": "Before", + "label.before": "قبل", "label.bounce-rate": "معدل الارتداد", - "label.breakdown": "Breakdown", - "label.browser": "Browser", + "label.breakdown": "التصنيف", + "label.browser": "المتصفح", "label.browsers": "المتصفحات", - "label.cancel": "إلغاء", + "label.cancel": "ألغِ", "label.change-password": "تغيير كلمة المرور", "label.cities": "المدن", - "label.city": "City", + "label.city": "المدينة", "label.clear-all": "مسح الكل", "label.confirm": "تأكيد", "label.confirm-password": "تأكيد كلمة المرور", - "label.contains": "Contains", - "label.continue": "متابعة", + "label.contains": "يحتوي", + "label.continue": "تابع", "label.countries": "الدول", - "label.country": "Country", - "label.create": "Create", - "label.create-report": "Create report", - "label.create-team": "انشاء مجموعة", - "label.create-user": "انشاء مستخدم", - "label.created": "تم الانشاء", + "label.country": "الدولة", + "label.create": "أنشِئ", + "label.create-report": "أنشِئ تقرير", + "label.create-team": "أنشِئ فريق", + "label.create-user": "أنشِئ مستخدم", + "label.created": "أُنشئت", "label.current-password": "كلمة المرور الحالية", - "label.custom-range": "فترة مخصصة", + "label.custom-range": "فترة مخصّصة", "label.dashboard": "الشاشة الرئيسية", "label.data": "البيانات", - "label.date": "Date", - "label.date-range": "فترة مخصصة", - "label.day": "Day", - "label.default-date-range": "الفترة المخصصة الافتراضية", + "label.date": "التاريخ", + "label.date-range": "فترة مخصّصة", + "label.day": "يوم", + "label.default-date-range": "الفترة المخصّصة الافتراضية", "label.delete": "حذف", - "label.delete-team": "حذف مجموعة", + "label.delete-team": "حذف الفريق", "label.delete-user": "جذف مستخدم", "label.delete-website": "حذف الموقع", - "label.description": "Description", + "label.description": "الوصف", "label.desktop": "كمبيوتر", "label.details": "تفاصيل", - "label.device": "Device", + "label.device": "الجهاز", "label.devices": "الأجهزة", - "label.dismiss": "اخفاء", + "label.dismiss": "تجاهل", "label.does-not-contain": "Does not contain", "label.domain": "النطاق", - "label.dropoff": "Dropoff", - "label.edit": "تعديل", - "label.edit-dashboard": "تعديل لوحة التحكم", - "label.enable-share-url": "تفعيل مشاركة الرابط", - "label.event": "Event", + "label.dropoff": "إنزال", + "label.edit": "عدّل", + "label.edit-dashboard": "عدّل لوحة التحكم", + "label.enable-share-url": "فعّل مشاركة الرابط", + "label.event": "الحدث", "label.event-data": "Event data", "label.events": "الأحداث", - "label.false": "False", - "label.field": "Field", - "label.fields": "Fields", - "label.filter": "Filter", - "label.filter-combined": "مجمعة", - "label.filter-raw": "مفصلة", - "label.filters": "Filters", - "label.funnel": "Funnel", - "label.funnel-description": "Understand the conversion and drop-off rate of users.", - "label.greater-than": "Greater than", - "label.greater-than-equals": "Greater than or equals", - "label.insights": "Insights", - "label.insights-description": "Dive deeper into your data by using segments and filters.", - "label.is": "Is", - "label.is-not": "Is not", - "label.is-not-set": "Is not set", - "label.is-set": "Is set", - "label.join": "انضمام", - "label.join-team": "الانضمام للمجموعة", + "label.false": "خطأ", + "label.field": "الحقل", + "label.fields": "الحقول", + "label.filter": "تصفيَة", + "label.filter-combined": "مُجمّعة", + "label.filter-raw": "خام", + "label.filters": "التصفيات", + "label.funnel": "قمع", + "label.funnel-description": "فهم معدل التحويل والانقطاع عن المستخدمين.", + "label.greater-than": "أكبَر مِن", + "label.greater-than-equals": "أكبَر مِن أو يساوي", + "label.insights": "نتائج التحليلات", + "label.insights-description": "تعمق في بياناتك باستخدام الشرائح والتصفيات.", + "label.is": "هو", + "label.is-not": "لم", + "label.is-not-set": "لم ضُبط", + "label.is-set": "ضُبط", + "label.join": "انضم", + "label.join-team": "انضم للفريق", "label.language": "اللغة", "label.languages": "اللغات", "label.laptop": "لابتوب", - "label.last-days": "اخر {x} يوم/ايام", - "label.last-hours": "اخر {x} ساعة/ساعات", - "label.leave": "مغادرة", + "label.last-days": "آخر {x} يوم/ايام", + "label.last-hours": "آخر {x} ساعة", + "label.leave": "غادر", "label.leave-team": "مغادرة المجموعة", - "label.less-than": "Less than", - "label.less-than-equals": "Less than or equals", + "label.less-than": "أقل مِن", + "label.less-than-equals": "أقل مِن أو يساوي", "label.login": "تسجيل الدخول", "label.logout": "تسجيل الخروج", - "label.max": "Max", + "label.max": "الحد الأقصى", "label.members": "الأعضاء", - "label.min": "Min", + "label.min": "الحد الأدنى", "label.mobile": "جوال", "label.more": "المزيد", - "label.my-websites": "My websites", - "label.name": "الإسم", + "label.my-websites": "مواقعي", + "label.name": "الاسم", "label.new-password": "كلمة مرور جديدة", - "label.none": "غير معرف", - "label.os": "OS", - "label.overview": "Overview", + "label.none": "غير معرّف", + "label.os": "نظام التشغيل", + "label.overview": "نظرة عامة", "label.owner": "المالك", - "label.page-of": "Page {current} of {total}", + "label.page-of": "صفحة {current} من {total}", "label.page-views": "مشاهدات الصفحة", - "label.pageTitle": "Page title", + "label.pageTitle": "عنوان الصفحة", "label.pages": "الصفحات", "label.password": "كلمة المرور", "label.powered-by": "مشغل بواسطة {name}", "label.profile": "الملف الشخصي", "label.queries": "استعلامات", - "label.query": "Query", + "label.query": "استعلام", "label.query-parameters": "متغيرات الرابط", "label.realtime": "الوقت الفعلي", - "label.referrer": "Referrer", + "label.referrer": "المرجع", "label.referrers": "التحويلات", "label.refresh": "تحديث", - "label.regenerate": "اعادة انشاء", - "label.region": "Region", + "label.regenerate": "إعادة توليد", + "label.region": "المنطقة", "label.regions": "المناطق", - "label.remove": "إزالة", - "label.reports": "Reports", + "label.remove": "أزِل", + "label.reports": "التقارير", "label.required": "اجباري", "label.reset": "اعادة تعيين", "label.reset-website": "اعادة تعيين الإحصائيات", - "label.retention": "Retention", - "label.retention-description": "Measure your website stickiness by tracking how often users return.", + "label.retention": "الاحتفاظ", + "label.retention-description": "قس مدى ثبات موقعك على الويب من خلال تتبع عدد مرات عودة المستخدمين.", "label.role": "الصلاحية", - "label.run-query": "Run query", + "label.run-query": "شغّل الاستعلام", "label.save": "حفظ", "label.screens": "الشاشات", - "label.search": "Search", - "label.select-date": "Select date", - "label.select-website": "اختيار موقع", + "label.search": "بحث", + "label.select-date": "حدد التاريخ", + "label.select-website": "حدد موقع", "label.sessions": "الزيارات", - "label.settings": "اعدادات", + "label.settings": "الإعدادات", "label.share-url": "مشاركة الرابط", "label.single-day": "يوم واحد", - "label.sum": "Sum", + "label.sum": "المجموع", "label.tablet": "تابلت", - "label.team": "مجموعة", - "label.team-guest": "زائر للمجموعة", - "label.team-id": "معرف المجموعة", - "label.team-member": "عضو المجموعة", - "label.team-name": "Team name", - "label.team-owner": "مدير المجموعة", - "label.team-websites": "Team websites", - "label.teams": "المجموعات", - "label.theme": "المظهر", + "label.team": "الفريق", + "label.team-guest": "ضيف الفريق", + "label.team-id": "معرّف الفريق", + "label.team-member": "عضو الفريق", + "label.team-name": "اسم الفريق", + "label.team-owner": "مدير الفريق", + "label.team-websites": "مواقع الفريق", + "label.teams": "الفرق", + "label.theme": "السمة", "label.this-month": "الشهر الحالي", "label.this-week": "الاسبوع الحالي", "label.this-year": "السنة الحالية", @@ -156,61 +156,61 @@ "label.title": "العنوان", "label.today": "اليوم", "label.toggle-charts": "تغيير الإحصائيات", - "label.total": "Total", - "label.total-records": "Total records", + "label.total": "الإجمالي", + "label.total-records": "إجمالي السجلات", "label.tracking-code": "كود التتبع", - "label.true": "True", - "label.type": "Type", - "label.unique": "Unique", + "label.true": "حقيقي", + "label.type": "النوع", + "label.unique": "فريد", "label.unique-visitors": "زائرون فريدون", "label.unknown": "غير معروف", - "label.untitled": "Untitled", + "label.untitled": "بدون عنوان", "label.url": "URL", "label.urls": "URLs", - "label.user": "مستخدم", + "label.user": "المستخدم", "label.username": "اسم المستخدم", "label.users": "المستخدمين", - "label.value": "Value", + "label.value": "القيمة", "label.view": "عرض", "label.view-details": "عرض التفاصيل", - "label.view-only": "View only", + "label.view-only": "عرض فقط", "label.views": "المشاهدات", "label.visitors": "الزوار", - "label.website": "Website", - "label.website-id": "معرف الموقع", + "label.website": "الموقع", + "label.website-id": "معرّف الموقع", "label.websites": "المواقع", - "label.window": "Window", + "label.window": "النافذة", "label.yesterday": "الأمس", "message.active-users": "{x} حاليا {x, plural, one {زائر واحد} other {زوار}}", "message.confirm-delete": "هل أنت متأكد من حذف {target}?", "message.confirm-leave": "هل أنت متأكد من مغادرة {target}?", "message.confirm-reset": "هل أنت متأكد من اعادة تعيين الإحصائيات لـ {target}؟", - "message.delete-account": "To delete this account, type {confirmation} in the box below to confirm.", - "message.delete-website": "To delete this website, type {confirmation} in the box below to confirm.", - "message.delete-website-warning": "كافة البيانات المرتبطة سيم حذفها ايضا.", + "message.delete-account": "لحذف هذا الحساب، اكتب {confirmation} في المربع أدناه للتأكيد.", + "message.delete-website": "لحذف هذا الموقع، اكتب {confirmation} في المربع أدناه للتأكيد.", + "message.delete-website-warning": "سيتم حذف كافة بيانات الموقع.", "message.error": "حدث خطأ ما.", "message.event-log": "{event} في {url}", "message.go-to-settings": "الذهاب إلى الإعدادات", "message.incorrect-username-password": "اسم المستخدم او كلمة المرور غير صحيحة.", "message.invalid-domain": "النطاق غير صحيح", "message.min-password-length": "اقل عدد مسموح به {n} حرف/أحرف", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "إصدار جديد من Umami {version} متاح!", "message.no-data-available": "لا توجد بيانات متاحة.", - "message.no-event-data": "No event data is available.", + "message.no-event-data": "لا توجد بيانات الحدث متاحة.", "message.no-match-password": "كلمة المرور غير متطابقة", - "message.no-results-found": "No results were found.", - "message.no-team-websites": "هذه المجموعة ليس لديه اي موقع.", - "message.no-teams": "لم تقم بإنشاء اي مجموعة.", + "message.no-results-found": "لا توجد نتائج.", + "message.no-team-websites": "هذا الفريق ليس لديه أي مواقع.", + "message.no-teams": "لم تنشِئ اي فرق.", "message.no-users": "لا يوجد مستخدمين.", "message.no-websites-configured": "لم تقم بإعداد اي موقع.", "message.page-not-found": "الصفحة غير موجودة.", - "message.reset-website": "To reset this website, type {confirmation} in the box below to confirm.", + "message.reset-website": "لإعادة ضبط موقع الويب هذا، اكتب {confirmation} في المربع أدناه للتأكيد.", "message.reset-website-warning": "سيتم اعادة تعيين كافة الإحصائيات لهذا الموقع، لكن لن يتم تعيير كود التتبع", "message.saved": "تم الحفظ بنجاح.", "message.share-url": "هذا الرابط الذي تم مشاركته بشكل عام لـ {target}.", - "message.team-already-member": "أنت عضو في المجموعة", - "message.team-not-found": "لم يتم العثور على المجموعة", - "message.team-websites-info": "يمكن مشاهدة الموقع من اي عضو في المجموعة.", + "message.team-already-member": "أنت عضو في الفريق", + "message.team-not-found": "لم يتم العثور على الفريق", + "message.team-websites-info": "يمكن مشاهدة الموقع من اي عضو في الفريق.", "message.tracking-code": "كود التتبع", "message.user-deleted": "تم حذف المستخدم.", "message.visitor-log": "زائر من {country} يستخدم {browser} على {os} {device}" From 928fb3ee8993e4793dd328c445d5f1114c1f6f1d Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 13 Feb 2024 23:53:06 -0800 Subject: [PATCH 129/142] remove cloudMode condition --- src/app/(main)/settings/websites/WebsitesHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(main)/settings/websites/WebsitesHeader.tsx b/src/app/(main)/settings/websites/WebsitesHeader.tsx index e0d3860a..6f322371 100644 --- a/src/app/(main)/settings/websites/WebsitesHeader.tsx +++ b/src/app/(main)/settings/websites/WebsitesHeader.tsx @@ -12,7 +12,7 @@ export function WebsitesHeader({ teamId, allowCreate = true }: WebsitesHeaderPro return ( - {allowCreate && !process.env.cloudMode && } + {allowCreate && } ); } From 413583527034acbedae685d4dcff145b6bd91ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Achim=20Kr=C3=A4mer?= <39946364+pxlfrk@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:42:12 +0100 Subject: [PATCH 130/142] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20add=20OCI=20doc?= =?UTF-8?q?ker=20labels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Achim Krämer <39946364+pxlfrk@users.noreply.github.com> --- .github/workflows/cd.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 0660bcba..e1a32cce 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -2,6 +2,10 @@ name: Create docker images on: [create] +env: + # set Docker OCI Labels + DOCKER_LABELS: org.opencontainers.image.title=${{github.event.repository.name}}, org.opencontainers.image.description="Umami is a simple, fast, privacy-focused alternative to Google Analytics", org.opencontainers.image.vendor=${{github.repository_owner}}, org.opencontainers.image.licenses="MIT", org.opencontainers.image.version=${{github.ref_name}}, org.opencontainers.image.created=${{ env.NOW }}, org.opencontainers.image.source=${{github.server_url}}/${{github.repository}}, org.opencontainers.image.revision=${{github.sha}}, org.opencontainers.image.url="https://umami.is/", org.opencontainers.image.documentation="https://umami.is/docs", org.opencontainers.image.base.name="docker.io/library/node:18-alpine" + jobs: build: name: Build, push, and deploy @@ -16,13 +20,16 @@ jobs: - uses: actions/checkout@v3 - name: Set env - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + run: | + echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + echo "NOW=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV - uses: mr-smithers-excellent/docker-build-push@v6 name: Build & push Docker image to ghcr.io for ${{ matrix.db-type }} with: image: umami tags: ${{ matrix.db-type }}-${{ env.RELEASE_VERSION }}, ${{ matrix.db-type }}-latest + labels: $DOCKER_LABELS buildArgs: DATABASE_TYPE=${{ matrix.db-type }} registry: ghcr.io multiPlatform: true @@ -30,11 +37,13 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - uses: mr-smithers-excellent/docker-build-push@v6 name: Build & push Docker image to docker.io for ${{ matrix.db-type }} with: image: umamisoftware/umami tags: ${{ matrix.db-type }}-${{ env.RELEASE_VERSION }}, ${{ matrix.db-type }}-latest + labels: $DOCKER_LABELS buildArgs: DATABASE_TYPE=${{ matrix.db-type }} registry: docker.io username: ${{ secrets.DOCKER_USERNAME }} From 2170f876745849f237de1c09d0f65e8c43b3fd21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Achim=20Kr=C3=A4mer?= <39946364+pxlfrk@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:52:46 +0100 Subject: [PATCH 131/142] =?UTF-8?q?=F0=9F=8E=A8=20improve=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Achim Krämer <39946364+pxlfrk@users.noreply.github.com> --- .github/workflows/cd.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index e1a32cce..0cd82a07 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -4,7 +4,18 @@ on: [create] env: # set Docker OCI Labels - DOCKER_LABELS: org.opencontainers.image.title=${{github.event.repository.name}}, org.opencontainers.image.description="Umami is a simple, fast, privacy-focused alternative to Google Analytics", org.opencontainers.image.vendor=${{github.repository_owner}}, org.opencontainers.image.licenses="MIT", org.opencontainers.image.version=${{github.ref_name}}, org.opencontainers.image.created=${{ env.NOW }}, org.opencontainers.image.source=${{github.server_url}}/${{github.repository}}, org.opencontainers.image.revision=${{github.sha}}, org.opencontainers.image.url="https://umami.is/", org.opencontainers.image.documentation="https://umami.is/docs", org.opencontainers.image.base.name="docker.io/library/node:18-alpine" + DOCKER_LABELS: > + org.opencontainers.image.title=${{github.event.repository.name}}, + org.opencontainers.image.description="Umami is a simple, fast, privacy-focused alternative to Google Analytics", + org.opencontainers.image.vendor=${{github.repository_owner}}, + org.opencontainers.image.licenses="MIT", + org.opencontainers.image.version=${{github.ref_name}}, + org.opencontainers.image.created=${{ env.NOW }}, + org.opencontainers.image.source=${{github.server_url}}/${{github.repository}}, + org.opencontainers.image.revision=${{github.sha}}, + org.opencontainers.image.url="https://umami.is/", + org.opencontainers.image.documentation="https://umami.is/docs", + org.opencontainers.image.base.name="docker.io/library/node:18-alpine" jobs: build: From ee3f7cb6186dc4d7375a776892e37408fbe19dfb Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 13 Feb 2024 12:36:55 -0800 Subject: [PATCH 132/142] Updated root layout. --- src/app/(main)/App.tsx | 1 + src/app/(main)/NavBar.tsx | 1 + src/app/(main)/UpdateNotice.tsx | 1 + src/app/(main)/layout.tsx | 1 - src/components/layout/Page.tsx | 1 + 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/(main)/App.tsx b/src/app/(main)/App.tsx index a906739c..74be8292 100644 --- a/src/app/(main)/App.tsx +++ b/src/app/(main)/App.tsx @@ -1,3 +1,4 @@ +'use client'; import { Loading } from 'react-basics'; import Script from 'next/script'; import { usePathname } from 'next/navigation'; diff --git a/src/app/(main)/NavBar.tsx b/src/app/(main)/NavBar.tsx index ed29df13..86d1db71 100644 --- a/src/app/(main)/NavBar.tsx +++ b/src/app/(main)/NavBar.tsx @@ -1,3 +1,4 @@ +'use client'; import { Icon, Text } from 'react-basics'; import Link from 'next/link'; import classNames from 'classnames'; diff --git a/src/app/(main)/UpdateNotice.tsx b/src/app/(main)/UpdateNotice.tsx index 54ad05c9..c56d3ce4 100644 --- a/src/app/(main)/UpdateNotice.tsx +++ b/src/app/(main)/UpdateNotice.tsx @@ -1,3 +1,4 @@ +'use client'; import { useEffect, useCallback, useState } from 'react'; import { createPortal } from 'react-dom'; import { Button } from 'react-basics'; diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx index bcc86bff..f5aeab67 100644 --- a/src/app/(main)/layout.tsx +++ b/src/app/(main)/layout.tsx @@ -1,4 +1,3 @@ -'use client'; import App from './App'; import NavBar from './NavBar'; import Page from 'components/layout/Page'; diff --git a/src/components/layout/Page.tsx b/src/components/layout/Page.tsx index c2a0e241..83312d12 100644 --- a/src/components/layout/Page.tsx +++ b/src/components/layout/Page.tsx @@ -1,3 +1,4 @@ +'use client'; import { ReactNode } from 'react'; import classNames from 'classnames'; import { Banner, Loading } from 'react-basics'; From 1955166bdf7f7c23f0898226e938c21c9f16f742 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 14 Feb 2024 15:13:53 -0800 Subject: [PATCH 133/142] Bump query limit to 500. --- .../settings/websites/[websiteId]/WebsiteTransferForm.tsx | 3 --- src/queries/analytics/eventData/getEventDataEvents.ts | 6 +++--- src/queries/analytics/eventData/getEventDataFields.ts | 4 ++-- src/queries/analytics/getValues.ts | 4 ++-- src/queries/analytics/pageviews/getPageviewMetrics.ts | 4 ++-- src/queries/analytics/sessions/getSessionMetrics.ts | 4 ++-- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteTransferForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteTransferForm.tsx index d5ded108..db46c212 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteTransferForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteTransferForm.tsx @@ -9,7 +9,6 @@ import { Dropdown, Item, Flexbox, - useToasts, } from 'react-basics'; import { useApi, useLogin, useMessages, useTeams } from 'components/hooks'; import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; @@ -34,7 +33,6 @@ export function WebsiteTransferForm({ }); const { result, query } = useTeams(user.id); const isTeamWebsite = !!website?.teamId; - const { showToast } = useToasts(); const handleSubmit = async () => { mutate( @@ -44,7 +42,6 @@ export function WebsiteTransferForm({ }, { onSuccess: async () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); onSave?.(); onClose?.(); }, diff --git a/src/queries/analytics/eventData/getEventDataEvents.ts b/src/queries/analytics/eventData/getEventDataEvents.ts index 683d9558..3eeb3702 100644 --- a/src/queries/analytics/eventData/getEventDataEvents.ts +++ b/src/queries/analytics/eventData/getEventDataEvents.ts @@ -53,7 +53,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { and event_data.created_at between {{startDate}} and {{endDate}} group by website_event.event_name, event_data.event_key, event_data.data_type order by 1 asc, 2 asc - limit 100 + limit 500 `, params, ); @@ -82,7 +82,7 @@ async function clickhouseQuery( and event_name = {event:String} group by event_key, data_type, string_value, event_name order by 1 asc, 2 asc, 3 asc, 4 desc - limit 100 + limit 500 `, params, ).then(a => { @@ -110,7 +110,7 @@ async function clickhouseQuery( and created_at between {startDate:DateTime64} and {endDate:DateTime64} group by event_key, data_type, event_name order by 1 asc, 2 asc - limit 100 + limit 500 `, params, ).then(a => { diff --git a/src/queries/analytics/eventData/getEventDataFields.ts b/src/queries/analytics/eventData/getEventDataFields.ts index df5a8874..293aed24 100644 --- a/src/queries/analytics/eventData/getEventDataFields.ts +++ b/src/queries/analytics/eventData/getEventDataFields.ts @@ -31,7 +31,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters & { fiel ${filterQuery} group by event_key, data_type, string_value order by 3 desc, 2 desc, 1 asc - limit 100 + limit 500 `, params, ); @@ -59,7 +59,7 @@ async function clickhouseQuery( ${filterQuery} group by event_key, data_type, string_value order by 3 desc, 2 desc, 1 asc - limit 100 + limit 500 `, params, ).then(a => { diff --git a/src/queries/analytics/getValues.ts b/src/queries/analytics/getValues.ts index c270727e..44955423 100644 --- a/src/queries/analytics/getValues.ts +++ b/src/queries/analytics/getValues.ts @@ -22,7 +22,7 @@ async function relationalQuery(websiteId: string, column: string, startDate: Dat on session.session_id = website_event.session_id where website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} - limit 100 + limit 500 `, { websiteId, @@ -41,7 +41,7 @@ async function clickhouseQuery(websiteId: string, column: string, startDate: Dat from website_event where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - limit 100 + limit 500 `, { websiteId, diff --git a/src/queries/analytics/pageviews/getPageviewMetrics.ts b/src/queries/analytics/pageviews/getPageviewMetrics.ts index b7aef81c..0bf931fd 100644 --- a/src/queries/analytics/pageviews/getPageviewMetrics.ts +++ b/src/queries/analytics/pageviews/getPageviewMetrics.ts @@ -17,7 +17,7 @@ async function relationalQuery( websiteId: string, column: string, filters: QueryFilters, - limit: number = 100, + limit: number = 500, ) { const { rawQuery, parseFilters } = prisma; const { filterQuery, joinSession, params } = await parseFilters( @@ -57,7 +57,7 @@ async function clickhouseQuery( websiteId: string, column: string, filters: QueryFilters, - limit: number = 100, + limit: number = 500, ): Promise<{ x: string; y: number }[]> { const { rawQuery, parseFilters } = clickhouse; const { filterQuery, params } = await parseFilters(websiteId, { diff --git a/src/queries/analytics/sessions/getSessionMetrics.ts b/src/queries/analytics/sessions/getSessionMetrics.ts index c6877a3f..be414b1c 100644 --- a/src/queries/analytics/sessions/getSessionMetrics.ts +++ b/src/queries/analytics/sessions/getSessionMetrics.ts @@ -17,7 +17,7 @@ async function relationalQuery( websiteId: string, column: string, filters: QueryFilters, - limit: number = 100, + limit: number = 500, ) { const { parseFilters, rawQuery } = prisma; const { filterQuery, joinSession, params } = await parseFilters( @@ -56,7 +56,7 @@ async function clickhouseQuery( websiteId: string, column: string, filters: QueryFilters, - limit: number = 100, + limit: number = 500, ): Promise<{ x: string; y: number }[]> { const { parseFilters, rawQuery } = clickhouse; const { filterQuery, params } = await parseFilters(websiteId, { From f01073c46afd8f3a6db21e8f181854937c224a09 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 14 Feb 2024 22:13:13 -0800 Subject: [PATCH 134/142] Update redirects for teams. --- next.config.js | 24 +++++++++++++++++++----- src/app/(main)/NavBar.tsx | 2 +- src/app/(main)/settings/layout.tsx | 4 ++++ src/components/input/TeamsButton.tsx | 3 ++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/next.config.js b/next.config.js index f353b1f9..dce49100 100644 --- a/next.config.js +++ b/next.config.js @@ -70,7 +70,7 @@ if (trackerScriptName) { const redirects = [ { source: '/settings', - destination: cloudMode ? `${cloudUrl}/settings/websites` : '/settings/websites', + destination: '/settings/websites', permanent: true, }, { @@ -80,17 +80,31 @@ const redirects = [ }, { source: '/teams/:id/settings', - destination: cloudMode ? `${cloudUrl}/teams/:id/settings` : '/teams/:id/settings/team', + destination: '/teams/:id/settings/team', permanent: true, }, ]; -if (cloudMode && cloudUrl && disableLogin) { +if (cloudMode && cloudUrl) { redirects.push({ - source: '/login', - destination: cloudUrl, + source: '/settings/:path*', + destination: `${cloudUrl}/settings/:path*`, permanent: false, }); + + redirects.push({ + source: '/teams/:id/settings/:path*', + destination: `${cloudUrl}/teams/:id/settings/:path*`, + permanent: false, + }); + + if (disableLogin) { + redirects.push({ + source: '/login', + destination: cloudUrl, + permanent: false, + }); + } } /** @type {import('next').NextConfig} */ diff --git a/src/app/(main)/NavBar.tsx b/src/app/(main)/NavBar.tsx index 86d1db71..15b23355 100644 --- a/src/app/(main)/NavBar.tsx +++ b/src/app/(main)/NavBar.tsx @@ -17,7 +17,7 @@ export function NavBar() { const { pathname } = useNavigation(); const { teamId, renderTeamUrl } = useTeamUrl(); - const cloudMode = Boolean(process.env.cloudMode); + const cloudMode = !!process.env.cloudMode; const links = [ { label: formatMessage(labels.dashboard), url: renderTeamUrl('/dashboard') }, diff --git a/src/app/(main)/settings/layout.tsx b/src/app/(main)/settings/layout.tsx index eb382e3b..487a9d59 100644 --- a/src/app/(main)/settings/layout.tsx +++ b/src/app/(main)/settings/layout.tsx @@ -1,5 +1,9 @@ import SettingsLayout from './SettingsLayout'; export default function ({ children }) { + if (process.env.cloudMode) { + return null; + } + return {children}; } diff --git a/src/components/input/TeamsButton.tsx b/src/components/input/TeamsButton.tsx index a91cdb2f..c7fc535a 100644 --- a/src/components/input/TeamsButton.tsx +++ b/src/components/input/TeamsButton.tsx @@ -10,10 +10,11 @@ export function TeamsButton({ teamId }: { teamId: string }) { const { formatMessage, labels } = useMessages(); const { router } = useNavigation(); const team = user?.teams?.find(({ id }) => id === teamId); + const cloudMode = !!process.env.cloudMode; const handleSelect = (close: () => void, id: Key) => { if (id !== user.id) { - router.push(`/teams/${id}`); + router.push(cloudMode ? `${process.env.cloudUrl}/teams/${id}` : `/teams/${id}`); } else { router.push('/'); } From f50067e44fe01b4d4440c24d14fbcb88fc19b31b Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 14 Feb 2024 23:21:35 -0800 Subject: [PATCH 135/142] Fixed website refresh after save. --- .../settings/websites/[websiteId]/ShareUrl.tsx | 10 +++++----- .../websites/[websiteId]/WebsiteEditForm.tsx | 17 ++++------------- .../websites/[websiteId]/WebsiteSettings.tsx | 4 ++-- src/styles/index.css | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx index e06657d4..640c519b 100644 --- a/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/ShareUrl.tsx @@ -7,7 +7,6 @@ import { Button, Toggle, LoadingButton, - useToasts, } from 'react-basics'; import { useContext, useState } from 'react'; import { getRandomChars } from 'next-basics'; @@ -18,6 +17,7 @@ const generateId = () => getRandomChars(16); export function ShareUrl({ hostUrl, + onSave, }: { websiteId: string; hostUrl?: string; @@ -27,7 +27,6 @@ export function ShareUrl({ const { domain, shareId } = website; const { formatMessage, labels, messages } = useMessages(); const [id, setId] = useState(shareId); - const { showToast } = useToasts(); const { post, useMutation } = useApi(); const { mutate, error, isPending } = useMutation({ mutationFn: (data: any) => post(`/websites/${website.id}`, data), @@ -46,7 +45,8 @@ export function ShareUrl({ const data = { shareId: checked ? generateId() : null }; mutate(data, { onSuccess: async () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); + touch(`website:${website.id}`); + onSave?.(); }, }); setId(data.shareId); @@ -57,8 +57,8 @@ export function ShareUrl({ { shareId: id }, { onSuccess: async () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); - touch(`website:${website?.id}`); + touch(`website:${website.id}`); + onSave?.(); }, }, ); diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx index d7d9cef4..dac7a8d4 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteEditForm.tsx @@ -1,18 +1,10 @@ import { useContext, useRef } from 'react'; -import { - SubmitButton, - Form, - FormInput, - FormRow, - FormButtons, - TextField, - useToasts, -} from 'react-basics'; +import { SubmitButton, Form, FormInput, FormRow, FormButtons, TextField } from 'react-basics'; import { useApi, useMessages, useModified } from 'components/hooks'; import { DOMAIN_REGEX } from 'lib/constants'; import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider'; -export function WebsiteEditForm({ websiteId }: { websiteId: string }) { +export function WebsiteEditForm({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) { const website = useContext(WebsiteContext); const { formatMessage, labels, messages } = useMessages(); const { post, useMutation } = useApi(); @@ -20,15 +12,14 @@ export function WebsiteEditForm({ websiteId }: { websiteId: string }) { mutationFn: (data: any) => post(`/websites/${websiteId}`, data), }); const ref = useRef(null); - const { showToast } = useToasts(); const { touch } = useModified(); const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); ref.current.reset(data); - touch(`website:${website?.id}`); + touch(`website:${website.id}`); + onSave?.(); }, }); }; diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx index af7723ae..86491227 100644 --- a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettings.tsx @@ -38,9 +38,9 @@ export function WebsiteSettings({ websiteId, openExternal = false }) { {formatMessage(labels.shareUrl)} {formatMessage(labels.data)} - {tab === 'details' && } + {tab === 'details' && } {tab === 'tracking' && } - {tab === 'share' && } + {tab === 'share' && } {tab === 'data' && } ); diff --git a/src/styles/index.css b/src/styles/index.css index 4031851a..d337aecc 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -89,3 +89,18 @@ main::-webkit-scrollbar-track { background-color: var(--base800); background-clip: padding-box; } + +:root { + --dark50: #111111; + --dark75: #191919; + --dark100: #222222; + --dark150: #2a2a2a; + --dark200: #313131; + --dark300: #3a3a3a; + --dark400: #484848; + --dark500: #606060; + --dark600: #6e6e6e; + --dark700: #7b7b7b; + --dark800: #b4b4b4; + --dark900: #eeeeee; +} From b81f5112bc8419c81861f46f8b0cbf7b836f3c85 Mon Sep 17 00:00:00 2001 From: Maxime-J Date: Thu, 15 Feb 2024 10:59:00 +0000 Subject: [PATCH 136/142] Add basePath for telemetry. --- src/app/(main)/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(main)/App.tsx b/src/app/(main)/App.tsx index 74be8292..406c2f16 100644 --- a/src/app/(main)/App.tsx +++ b/src/app/(main)/App.tsx @@ -27,7 +27,7 @@ export function App({ children }) { {children} {process.env.NODE_ENV === 'production' && !pathname.includes('/share/') && ( -