From f901f203b09accad5135d204e0b6c912d70ad524 Mon Sep 17 00:00:00 2001 From: Darren Clarke Date: Tue, 18 Jul 2023 12:26:57 +0000 Subject: [PATCH] Develop --- .gitlab-ci.yml | 3 +- .vscode/settings.json | 3 + apps/leafcutter/Dockerfile | 2 +- .../(login)/login/_components/Login.tsx} | 26 +- apps/leafcutter/app/(login)/login/page.tsx | 16 + .../(main)/about/_components/About.tsx} | 34 +- .../(main)/about/_components}/AboutBox.tsx | 4 +- .../about/_components}/AboutFeature.tsx | 4 +- apps/leafcutter/app/(main)/about/page.tsx | 5 + .../(main)/create/_components/Create.tsx} | 40 +- apps/leafcutter/app/(main)/create/page.tsx | 8 + .../(main)/faq/_components/FAQ.tsx} | 32 +- apps/leafcutter/app/(main)/faq/page.tsx | 5 + apps/leafcutter/app/(main)/layout.tsx | 22 + .../_components/Preview.tsx | 23 + .../preview/[...visualizationID]/page.tsx} | 23 +- .../(main)/setup/_components/Setup.tsx} | 10 +- apps/leafcutter/app/(main)/setup/page.tsx | 6 + .../(main)/trends/_components/Trends.tsx} | 34 +- apps/leafcutter/app/(main)/trends/page.tsx | 8 + .../[...visualizationID]/page.tsx | 46 + .../_components}/AccountButton.tsx | 2 + .../_components}/AppProvider.tsx | 4 +- .../_components}/Button.tsx | 2 + .../_components}/Footer.tsx | 2 + .../_components}/GettingStartedDialog.tsx | 12 +- .../_components}/HelpButton.tsx | 7 +- .../index.tsx => app/_components/Home.tsx} | 51 +- .../_components/InternalLayout.tsx} | 4 +- .../_components}/LanguageSelect.tsx | 9 +- .../_components}/LiveDataViewer.tsx | 2 + .../_components}/MetricSelectCard.tsx | 2 + .../app/_components/MultiProvider.tsx | 49 + .../_components}/OpenSearchWrapper.tsx | 2 + .../_components}/PageHeader.tsx | 2 + .../_components}/QueryBuilder.tsx | 6 +- .../_components}/QueryBuilderSection.tsx | 2 + .../_components}/QueryDateRangeSelector.tsx | 4 +- .../_components}/QueryListSelector.tsx | 2 + .../_components}/QueryText.tsx | 6 +- .../_components}/Question.tsx | 2 + .../_components}/RawDataViewer.tsx | 2 + .../_components}/Sidebar.tsx | 12 +- .../_components}/Tooltip.tsx | 12 +- .../_components}/TopNav.tsx | 8 +- .../_components}/VisualizationBuilder.tsx | 12 +- .../_components}/VisualizationCard.tsx | 6 +- .../_components}/VisualizationDetail.tsx | 6 +- .../VisualizationDetailDialog.tsx | 4 +- .../_components}/VisualizationSelectCard.tsx | 2 + .../_components}/Welcome.tsx | 5 + .../_components}/WelcomeDialog.tsx | 7 +- .../{config => app/_config}/taxonomy.json | 0 .../{config => app/_config}/unRegions.json | 0 .../_config}/visualizationMap.json | 0 .../_config}/visualizations/dataTable.json | 0 .../visualizations/horizontalBar.json | 0 .../visualizations/horizontalBarStacked.json | 0 .../_config}/visualizations/line.json | 0 .../_config}/visualizations/lineStacked.json | 0 .../_config}/visualizations/metric.json | 0 .../_config}/visualizations/pieDonut.json | 0 .../_config}/visualizations/tagCloud.json | 0 .../_config}/visualizations/verticalBar.json | 0 .../visualizations/verticalBarStacked.json | 0 .../[...nextauth].ts => app/_lib/auth.ts} | 6 +- .../{lib => app/_lib}/opensearch.ts | 12 +- .../{locales => app/_locales}/en.json | 0 .../{locales => app/_locales}/fr.json | 0 .../{styles => app/_styles}/global.css | 0 .../{styles => app/_styles}/theme.ts | 0 .../app/api/auth/[...nextauth]/route.ts | 6 + .../{pages => app}/api/proxy/[[...path]].ts | 0 .../app/api/searches/create/route.ts | 22 + .../app/api/searches/delete/route.ts | 19 + .../leafcutter/app/api/searches/list/route.ts | 12 + .../app/api/trends/recent/_route.ts | 9 + .../{pages => app}/api/upload/index.ts | 15 +- .../app/api/visualizations/create/route.ts | 20 + .../app/api/visualizations/delete/route.ts | 15 + .../app/api/visualizations/query/route.ts | 12 + .../app/api/visualizations/update/route.ts | 21 + apps/leafcutter/app/layout.tsx | 32 + apps/leafcutter/app/page.tsx | 14 + apps/leafcutter/lib/createEmotionCache.ts | 5 - apps/leafcutter/lib/utils.ts | 4 - apps/leafcutter/middleware.ts | 94 +- apps/leafcutter/next.config.js | 39 +- apps/leafcutter/package.json | 39 +- apps/leafcutter/pages/_app.tsx | 63 - apps/leafcutter/pages/_document.tsx | 50 - apps/leafcutter/pages/api/searches/create.ts | 33 - apps/leafcutter/pages/api/searches/delete.ts | 31 - apps/leafcutter/pages/api/searches/list.ts | 25 - apps/leafcutter/pages/api/trends/recent.ts | 19 - .../pages/api/visualizations/create.ts | 32 - .../pages/api/visualizations/delete.ts | 26 - .../pages/api/visualizations/query.ts | 23 - .../pages/api/visualizations/update.ts | 32 - .../visualizations/[...visualizationID].tsx | 62 - apps/leafcutter/tsconfig.json | 11 +- apps/link/Dockerfile | 4 +- .../(login)/login/_components/Login.tsx} | 22 +- apps/link/app/(login)/login/page.tsx | 12 + apps/link/app/(main)/_components/Home.tsx | 6 + .../(main)/_components/InternalLayout.tsx} | 8 +- .../(main)/_components}/Sidebar.tsx | 37 +- .../(main)/_components}/StyledDataGrid.tsx | 2 + .../(main)/_components/ZammadWrapper.tsx} | 15 +- .../_components/LabelStudioWrapper.tsx | 24 + .../app/(main)/admin/label-studio/page.tsx | 10 + .../_components/MetamigoWrapper.tsx} | 29 +- .../(main)/admin/metamigo/[...path]/page.tsx | 16 + apps/link/app/(main)/admin/zammad/page.tsx | 10 + .../(main)/api/auth/[...nextauth]/route.ts} | 5 +- apps/link/app/(main)/api/v1/users/route.ts | 7 + apps/link/app/(main)/knowledge/page.tsx | 10 + apps/link/app/(main)/layout.tsx | 15 + .../[view]/_components/LeafcutterWrapper.tsx | 36 + .../app/(main)/leafcutter/[view]/page.tsx | 11 + apps/link/app/(main)/leafcutter/page.tsx | 5 + .../[overview]/_components}/TicketList.tsx | 44 +- .../[overview]/_components/ZammadOverview.tsx | 32 + .../app/(main)/overview/[overview]/error.tsx | 11 + .../app/(main)/overview/[overview]/page.tsx | 41 + apps/link/app/(main)/page.tsx | 10 + apps/link/app/(main)/profile/page.tsx | 10 + .../app/(main)/setup/_components/Setup.tsx | 14 + apps/link/app/(main)/setup/page.tsx | 10 + .../_components/ArticleCreateDialog.tsx | 102 + .../[id]/@detail/_components/TicketDetail.tsx | 186 + .../app/(main)/tickets/[id]/@detail/page.tsx | 11 + .../[id]/@edit/_components/TicketEdit.tsx | 186 + .../app/(main)/tickets/[id]/@edit/page.tsx | 11 + apps/link/app/(main)/tickets/[id]/error.tsx | 11 + apps/link/app/(main)/tickets/[id]/layout.tsx | 24 + .../app/(main)/tickets/[id]/not-found.tsx | 15 + .../(main)/tickets/[id]/notpage.tsx} | 27 +- .../_components}/Button.tsx | 5 +- apps/link/app/_components/DisplayError.tsx | 22 + apps/link/app/_components/MultiProvider.tsx | 62 + .../app/_graphql/getTicketArticlesQuery.ts | 21 + .../_graphql}/getTicketOverviewCountsQuery.ts | 0 .../_graphql}/getTicketQuery.ts | 21 +- .../_graphql}/getTicketsByOverviewQuery.ts | 0 .../_graphql}/updateTicketMutation.ts | 0 apps/link/{styles => app/_styles}/global.css | 0 apps/link/{styles => app/_styles}/theme.ts | 0 apps/link/app/error.tsx | 11 + apps/link/app/layout.tsx | 27 + apps/link/components/ArticleCreateDialog.tsx | 69 - apps/link/components/LeafcutterWrapper.tsx | 41 - apps/link/components/MetamigoWrapper.tsx | 41 - apps/link/components/TicketDetail.tsx | 153 - apps/link/components/TicketEdit.tsx | 94 - apps/link/components/ZammadWrapper.tsx | 19 - apps/link/lib/createEmotionCache.ts | 5 - apps/link/middleware.ts | 12 +- apps/link/next.config.js | 8 + apps/link/package.json | 36 +- apps/link/pages/.DS_Store | Bin 6148 -> 0 bytes apps/link/pages/404.tsx | 13 - apps/link/pages/500.tsx | 13 - apps/link/pages/_app.tsx | 73 - apps/link/pages/_document.tsx | 50 - apps/link/pages/admin/metamigo.tsx | 38 - apps/link/pages/admin/zammad.tsx | 31 - apps/link/pages/api/v1/users | 5 - apps/link/pages/index.tsx | 30 - apps/link/pages/knowledge.tsx | 31 - apps/link/pages/leafcutter/about.tsx | 6 - apps/link/pages/leafcutter/create.tsx | 6 - apps/link/pages/leafcutter/faq.tsx | 6 - apps/link/pages/leafcutter/index.tsx | 6 - apps/link/pages/leafcutter/trends.tsx | 6 - apps/link/pages/profile.tsx | 31 - apps/link/pages/tickets/assigned.tsx | 32 - apps/link/pages/tickets/pending.tsx | 32 - apps/link/pages/tickets/unassigned.tsx | 32 - apps/link/pages/tickets/urgent.tsx | 32 - apps/link/tsconfig.json | 29 +- apps/metamigo-api/package.json | 22 +- .../metamigo-api/src/app/services/whatsapp.ts | 9 +- apps/metamigo-cli/Dockerfile | 2 +- apps/metamigo-cli/package.json | 8 +- apps/metamigo-frontend/Dockerfile | 3 +- .../_components}/AdminLogin.tsx | 6 +- .../{components => app/_components}/Auth.tsx | 4 +- .../DigitInput/DigitInput.module.css | 0 .../_components}/DigitInput/index.tsx | 2 + .../_components}/MetamigoAdmin.tsx | 11 +- .../app/_components/MultiProvider.tsx | 8 + .../_components}/accounts/AccountEdit.tsx | 7 +- .../_components}/accounts/AccountList.tsx | 6 +- .../_components}/accounts/index.ts | 2 + .../_components}/layout/AppBar.tsx | 11 +- .../_components}/layout/Layout.tsx | 9 +- .../_components}/layout/Logo.tsx | 2 + .../_components}/layout/Menu.tsx | 2 + .../_components}/layout/SubMenu.tsx | 2 + .../_components}/layout/index.ts | 4 +- .../_components}/layout/themes.ts | 0 .../signal/bots/Digits.module.css | 0 .../signal/bots/SignalBotCreate.tsx | 7 +- .../signal/bots/SignalBotEdit.tsx | 5 +- .../signal/bots/SignalBotList.tsx | 5 +- .../signal/bots/SignalBotShow.tsx | 28 +- .../_components}/signal/bots/index.ts | 2 + .../app/_components/signal/bots/shared.tsx | 34 + .../_components}/users/UserCreate.tsx | 2 + .../_components}/users/UserEdit.tsx | 2 + .../_components}/users/UserList.tsx | 5 +- .../_components}/users/index.ts | 2 + .../_components}/users/shared.tsx | 2 + .../voice/providers/ProviderCreate.tsx | 2 + .../voice/providers/ProviderEdit.tsx | 2 + .../voice/providers/ProviderList.tsx | 2 + .../_components}/voice/providers/index.ts | 2 + .../_components}/voice/providers/shared.tsx | 2 + .../voice/voicelines/MicInput.module.css | 0 .../voice/voicelines/MicInput.tsx | 2 + .../voice/voicelines/VoiceLineCreate.tsx | 2 + .../voice/voicelines/VoiceLineEdit.tsx | 2 + .../voice/voicelines/VoiceLineList.tsx | 2 + .../_components}/voice/voicelines/index.ts | 2 + .../voice/voicelines/recorder.module.css | 0 .../_components}/voice/voicelines/shared.tsx | 4 +- .../voice/voicelines/twilio-languages.ts | 0 .../_components}/webhooks/WebhookCreate.tsx | 2 + .../_components}/webhooks/WebhookEdit.tsx | 2 + .../_components}/webhooks/WebhookList.tsx | 2 + .../_components}/webhooks/index.ts | 2 + .../_components}/webhooks/shared.tsx | 2 + .../attachments/WhatsappAttachmentList.tsx | 2 + .../attachments/WhatsappAttachmentShow.tsx | 2 + .../whatsapp/attachments/index.ts | 2 + .../whatsapp/bots/WhatsappBotCreate.tsx | 19 +- .../whatsapp/bots/WhatsappBotEdit.tsx | 2 + .../whatsapp/bots/WhatsappBotList.tsx | 2 + .../whatsapp/bots/WhatsappBotShow.tsx | 2 + .../_components}/whatsapp/bots/index.ts | 2 + .../_components}/whatsapp/bots/shared.tsx | 2 + .../whatsapp/messages/WhatsappMessageList.tsx | 2 + .../whatsapp/messages/WhatsappMessageShow.tsx | 2 + .../_components}/whatsapp/messages/index.ts | 2 + .../{i18n => app/_i18n}/en.ts | 0 .../{lib => app/_lib}/absolute-url.ts | 0 .../{lib => app/_lib}/apollo-client.ts | 0 .../{lib => app/_lib}/cloudflare.ts | 0 .../{lib => app/_lib}/dataprovider.ts | 0 .../{lib => app/_lib}/graphql-schema.json | 0 .../{lib => app/_lib}/nextauth-adapter.ts | 0 .../{lib => app/_lib}/phone-numbers.ts | 0 .../{styles => app/_styles}/Home.module.css | 0 .../{styles => app/_styles}/globals.css | 0 .../app/admin/_components/Admin.tsx | 16 + apps/metamigo-frontend/app/admin/page.tsx | 5 + .../api/auth/[...nextauth]/route.ts} | 24 +- .../api/graphql/[[...path]]/route.ts} | 8 +- .../api/proxy/[[...path]]/route.js} | 8 +- apps/metamigo-frontend/app/layout.tsx | 20 + .../login/_components/Login.tsx} | 6 +- apps/metamigo-frontend/app/login/page.tsx | 5 + apps/metamigo-frontend/app/page.tsx | 3 + .../components/signal/bots/shared.tsx | 27 - apps/metamigo-frontend/package.json | 26 +- apps/metamigo-frontend/pages/_app.tsx | 13 - apps/metamigo-frontend/pages/admin.tsx | 15 - apps/metamigo-frontend/pages/index.tsx | 29 - apps/metamigo-frontend/tsconfig.json | 29 +- apps/metamigo-worker/package.json | 24 +- docker-compose.link.yml | 7 +- docker-compose.metamigo.yml | 28 +- docker-compose.zammad.yml | 58 +- docker/elasticsearch/Dockerfile | 2 +- docker/memcached/Dockerfile | 2 +- docker/postgresql/Dockerfile | 2 +- docker/redis/Dockerfile | 2 +- docker/zammad/Dockerfile | 23 +- docker/zammad/install.rb | 77 + package-lock.json | 15172 ++++++++-------- package.json | 16 +- packages/babel-preset-link/package.json | 6 +- packages/eslint-config-link/package.json | 16 +- packages/hapi-nextauth/package.json | 2 +- packages/jest-config-link/package.json | 4 +- packages/metamigo-common/package.json | 8 +- packages/metamigo-config/package.json | 12 +- packages/metamigo-db/package.json | 16 +- packages/montar/package.json | 2 +- packages/node-signald/package.json | 2 +- .../app/jobs/communicate_cdr_signal_job.rb | 117 + .../app/jobs/communicate_cdr_whatsapp_job.rb | 117 + .../ticket/article/communicate_cdr_signal.rb | 25 - .../communicate_cdr_signal/background_job.rb | 137 - .../article/communicate_cdr_whatsapp.rb | 25 - .../background_job.rb | 137 - .../enqueue_communicate_cdr_signal_job.rb | 31 + .../enqueue_communicate_cdr_whatsapp_job.rb | 31 + .../src/config/initializers/cdr_signal.rb | 2 +- .../src/config/initializers/cdr_whatsapp.rb | 2 +- .../src/db/addon/pgp/20220403000001_pgp.rb | 18 +- 302 files changed, 9897 insertions(+), 10332 deletions(-) create mode 100644 .vscode/settings.json rename apps/leafcutter/{pages/login.tsx => app/(login)/login/_components/Login.tsx} (86%) create mode 100644 apps/leafcutter/app/(login)/login/page.tsx rename apps/leafcutter/{pages/about.tsx => app/(main)/about/_components/About.tsx} (85%) rename apps/leafcutter/{components => app/(main)/about/_components}/AboutBox.tsx (87%) rename apps/leafcutter/{components => app/(main)/about/_components}/AboutFeature.tsx (95%) create mode 100644 apps/leafcutter/app/(main)/about/page.tsx rename apps/leafcutter/{pages/create.tsx => app/(main)/create/_components/Create.tsx} (62%) create mode 100644 apps/leafcutter/app/(main)/create/page.tsx rename apps/leafcutter/{pages/faq.tsx => app/(main)/faq/_components/FAQ.tsx} (77%) create mode 100644 apps/leafcutter/app/(main)/faq/page.tsx create mode 100644 apps/leafcutter/app/(main)/layout.tsx create mode 100644 apps/leafcutter/app/(main)/preview/[...visualizationID]/_components/Preview.tsx rename apps/leafcutter/{pages/preview/[...visualizationID].tsx => app/(main)/preview/[...visualizationID]/page.tsx} (81%) rename apps/leafcutter/{pages/setup.tsx => app/(main)/setup/_components/Setup.tsx} (84%) create mode 100644 apps/leafcutter/app/(main)/setup/page.tsx rename apps/leafcutter/{pages/trends.tsx => app/(main)/trends/_components/Trends.tsx} (65%) create mode 100644 apps/leafcutter/app/(main)/trends/page.tsx create mode 100644 apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx rename apps/leafcutter/{components => app/_components}/AccountButton.tsx (98%) rename apps/leafcutter/{components => app/_components}/AppProvider.tsx (98%) rename apps/leafcutter/{components => app/_components}/Button.tsx (98%) rename apps/leafcutter/{components => app/_components}/Footer.tsx (99%) rename apps/leafcutter/{components => app/_components}/GettingStartedDialog.tsx (92%) rename apps/leafcutter/{components => app/_components}/HelpButton.tsx (88%) rename apps/leafcutter/{pages/index.tsx => app/_components/Home.tsx} (64%) rename apps/leafcutter/{components/Layout.tsx => app/_components/InternalLayout.tsx} (96%) rename apps/leafcutter/{components => app/_components}/LanguageSelect.tsx (89%) rename apps/leafcutter/{components => app/_components}/LiveDataViewer.tsx (97%) rename apps/leafcutter/{components => app/_components}/MetricSelectCard.tsx (99%) create mode 100644 apps/leafcutter/app/_components/MultiProvider.tsx rename apps/leafcutter/{components => app/_components}/OpenSearchWrapper.tsx (98%) rename apps/leafcutter/{components => app/_components}/PageHeader.tsx (98%) rename apps/leafcutter/{components => app/_components}/QueryBuilder.tsx (98%) rename apps/leafcutter/{components => app/_components}/QueryBuilderSection.tsx (99%) rename apps/leafcutter/{components => app/_components}/QueryDateRangeSelector.tsx (98%) rename apps/leafcutter/{components => app/_components}/QueryListSelector.tsx (99%) rename apps/leafcutter/{components => app/_components}/QueryText.tsx (97%) rename apps/leafcutter/{components => app/_components}/Question.tsx (99%) rename apps/leafcutter/{components => app/_components}/RawDataViewer.tsx (99%) rename apps/leafcutter/{components => app/_components}/Sidebar.tsx (96%) rename apps/leafcutter/{components => app/_components}/Tooltip.tsx (92%) rename apps/leafcutter/{components => app/_components}/TopNav.tsx (94%) rename apps/leafcutter/{components => app/_components}/VisualizationBuilder.tsx (97%) rename apps/leafcutter/{components => app/_components}/VisualizationCard.tsx (92%) rename apps/leafcutter/{components => app/_components}/VisualizationDetail.tsx (91%) rename apps/leafcutter/{components => app/_components}/VisualizationDetailDialog.tsx (98%) rename apps/leafcutter/{components => app/_components}/VisualizationSelectCard.tsx (99%) rename apps/leafcutter/{components => app/_components}/Welcome.tsx (96%) rename apps/leafcutter/{components => app/_components}/WelcomeDialog.tsx (96%) rename apps/leafcutter/{config => app/_config}/taxonomy.json (100%) rename apps/leafcutter/{config => app/_config}/unRegions.json (100%) rename apps/leafcutter/{config => app/_config}/visualizationMap.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/dataTable.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/horizontalBar.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/horizontalBarStacked.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/line.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/lineStacked.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/metric.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/pieDonut.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/tagCloud.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/verticalBar.json (100%) rename apps/leafcutter/{config => app/_config}/visualizations/verticalBarStacked.json (100%) rename apps/leafcutter/{pages/api/auth/[...nextauth].ts => app/_lib/auth.ts} (80%) rename apps/leafcutter/{lib => app/_lib}/opensearch.ts (98%) rename apps/leafcutter/{locales => app/_locales}/en.json (100%) rename apps/leafcutter/{locales => app/_locales}/fr.json (100%) rename apps/leafcutter/{styles => app/_styles}/global.css (100%) rename apps/leafcutter/{styles => app/_styles}/theme.ts (100%) create mode 100644 apps/leafcutter/app/api/auth/[...nextauth]/route.ts rename apps/leafcutter/{pages => app}/api/proxy/[[...path]].ts (100%) create mode 100644 apps/leafcutter/app/api/searches/create/route.ts create mode 100644 apps/leafcutter/app/api/searches/delete/route.ts create mode 100644 apps/leafcutter/app/api/searches/list/route.ts create mode 100644 apps/leafcutter/app/api/trends/recent/_route.ts rename apps/leafcutter/{pages => app}/api/upload/index.ts (78%) create mode 100644 apps/leafcutter/app/api/visualizations/create/route.ts create mode 100644 apps/leafcutter/app/api/visualizations/delete/route.ts create mode 100644 apps/leafcutter/app/api/visualizations/query/route.ts create mode 100644 apps/leafcutter/app/api/visualizations/update/route.ts create mode 100644 apps/leafcutter/app/layout.tsx create mode 100644 apps/leafcutter/app/page.tsx delete mode 100644 apps/leafcutter/lib/createEmotionCache.ts delete mode 100644 apps/leafcutter/lib/utils.ts delete mode 100644 apps/leafcutter/pages/_app.tsx delete mode 100644 apps/leafcutter/pages/_document.tsx delete mode 100644 apps/leafcutter/pages/api/searches/create.ts delete mode 100644 apps/leafcutter/pages/api/searches/delete.ts delete mode 100644 apps/leafcutter/pages/api/searches/list.ts delete mode 100644 apps/leafcutter/pages/api/trends/recent.ts delete mode 100644 apps/leafcutter/pages/api/visualizations/create.ts delete mode 100644 apps/leafcutter/pages/api/visualizations/delete.ts delete mode 100644 apps/leafcutter/pages/api/visualizations/query.ts delete mode 100644 apps/leafcutter/pages/api/visualizations/update.ts delete mode 100644 apps/leafcutter/pages/visualizations/[...visualizationID].tsx rename apps/link/{pages/login.tsx => app/(login)/login/_components/Login.tsx} (83%) create mode 100644 apps/link/app/(login)/login/page.tsx create mode 100644 apps/link/app/(main)/_components/Home.tsx rename apps/link/{components/Layout.tsx => app/(main)/_components/InternalLayout.tsx} (67%) rename apps/link/{components => app/(main)/_components}/Sidebar.tsx (93%) rename apps/link/{components => app/(main)/_components}/StyledDataGrid.tsx (99%) rename apps/link/{components/InternalZammadWrapper.tsx => app/(main)/_components/ZammadWrapper.tsx} (84%) create mode 100644 apps/link/app/(main)/admin/label-studio/_components/LabelStudioWrapper.tsx create mode 100644 apps/link/app/(main)/admin/label-studio/page.tsx rename apps/link/{pages/admin/label-studio.tsx => app/(main)/admin/metamigo/[...path]/_components/MetamigoWrapper.tsx} (54%) create mode 100644 apps/link/app/(main)/admin/metamigo/[...path]/page.tsx create mode 100644 apps/link/app/(main)/admin/zammad/page.tsx rename apps/link/{pages/api/auth/[...nextauth].ts => app/(main)/api/auth/[...nextauth]/route.ts} (86%) create mode 100644 apps/link/app/(main)/api/v1/users/route.ts create mode 100644 apps/link/app/(main)/knowledge/page.tsx create mode 100644 apps/link/app/(main)/layout.tsx create mode 100644 apps/link/app/(main)/leafcutter/[view]/_components/LeafcutterWrapper.tsx create mode 100644 apps/link/app/(main)/leafcutter/[view]/page.tsx create mode 100644 apps/link/app/(main)/leafcutter/page.tsx rename apps/link/{components => app/(main)/overview/[overview]/_components}/TicketList.tsx (60%) create mode 100644 apps/link/app/(main)/overview/[overview]/_components/ZammadOverview.tsx create mode 100644 apps/link/app/(main)/overview/[overview]/error.tsx create mode 100644 apps/link/app/(main)/overview/[overview]/page.tsx create mode 100644 apps/link/app/(main)/page.tsx create mode 100644 apps/link/app/(main)/profile/page.tsx create mode 100644 apps/link/app/(main)/setup/_components/Setup.tsx create mode 100644 apps/link/app/(main)/setup/page.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/@detail/_components/ArticleCreateDialog.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/@detail/_components/TicketDetail.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/@detail/page.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/@edit/_components/TicketEdit.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/@edit/page.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/error.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/layout.tsx create mode 100644 apps/link/app/(main)/tickets/[id]/not-found.tsx rename apps/link/{pages/tickets/[id].tsx => app/(main)/tickets/[id]/notpage.tsx} (77%) rename apps/link/{components => app/_components}/Button.tsx (89%) create mode 100644 apps/link/app/_components/DisplayError.tsx create mode 100644 apps/link/app/_components/MultiProvider.tsx create mode 100644 apps/link/app/_graphql/getTicketArticlesQuery.ts rename apps/link/{graphql => app/_graphql}/getTicketOverviewCountsQuery.ts (100%) rename apps/link/{graphql => app/_graphql}/getTicketQuery.ts (63%) rename apps/link/{graphql => app/_graphql}/getTicketsByOverviewQuery.ts (100%) rename apps/link/{graphql => app/_graphql}/updateTicketMutation.ts (100%) rename apps/link/{styles => app/_styles}/global.css (100%) rename apps/link/{styles => app/_styles}/theme.ts (100%) create mode 100644 apps/link/app/error.tsx create mode 100644 apps/link/app/layout.tsx delete mode 100644 apps/link/components/ArticleCreateDialog.tsx delete mode 100644 apps/link/components/LeafcutterWrapper.tsx delete mode 100644 apps/link/components/MetamigoWrapper.tsx delete mode 100644 apps/link/components/TicketDetail.tsx delete mode 100644 apps/link/components/TicketEdit.tsx delete mode 100644 apps/link/components/ZammadWrapper.tsx delete mode 100644 apps/link/lib/createEmotionCache.ts delete mode 100644 apps/link/pages/.DS_Store delete mode 100644 apps/link/pages/404.tsx delete mode 100644 apps/link/pages/500.tsx delete mode 100644 apps/link/pages/_app.tsx delete mode 100644 apps/link/pages/_document.tsx delete mode 100644 apps/link/pages/admin/metamigo.tsx delete mode 100644 apps/link/pages/admin/zammad.tsx delete mode 100644 apps/link/pages/api/v1/users delete mode 100644 apps/link/pages/index.tsx delete mode 100644 apps/link/pages/knowledge.tsx delete mode 100644 apps/link/pages/leafcutter/about.tsx delete mode 100644 apps/link/pages/leafcutter/create.tsx delete mode 100644 apps/link/pages/leafcutter/faq.tsx delete mode 100644 apps/link/pages/leafcutter/index.tsx delete mode 100644 apps/link/pages/leafcutter/trends.tsx delete mode 100644 apps/link/pages/profile.tsx delete mode 100644 apps/link/pages/tickets/assigned.tsx delete mode 100644 apps/link/pages/tickets/pending.tsx delete mode 100644 apps/link/pages/tickets/unassigned.tsx delete mode 100644 apps/link/pages/tickets/urgent.tsx rename apps/metamigo-frontend/{components => app/_components}/AdminLogin.tsx (94%) rename apps/metamigo-frontend/{components => app/_components}/Auth.tsx (89%) rename apps/metamigo-frontend/{components => app/_components}/DigitInput/DigitInput.module.css (100%) rename apps/metamigo-frontend/{components => app/_components}/DigitInput/index.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/MetamigoAdmin.tsx (93%) create mode 100644 apps/metamigo-frontend/app/_components/MultiProvider.tsx rename apps/metamigo-frontend/{components => app/_components}/accounts/AccountEdit.tsx (91%) rename apps/metamigo-frontend/{components => app/_components}/accounts/AccountList.tsx (92%) rename apps/metamigo-frontend/{components => app/_components}/accounts/index.ts (95%) rename apps/metamigo-frontend/{components => app/_components}/layout/AppBar.tsx (88%) rename apps/metamigo-frontend/{components => app/_components}/layout/Layout.tsx (73%) rename apps/metamigo-frontend/{components => app/_components}/layout/Logo.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/layout/Menu.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/layout/SubMenu.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/layout/index.ts (63%) rename apps/metamigo-frontend/{components => app/_components}/layout/themes.ts (100%) rename apps/metamigo-frontend/{components => app/_components}/signal/bots/Digits.module.css (100%) rename apps/metamigo-frontend/{components => app/_components}/signal/bots/SignalBotCreate.tsx (80%) rename apps/metamigo-frontend/{components => app/_components}/signal/bots/SignalBotEdit.tsx (77%) rename apps/metamigo-frontend/{components => app/_components}/signal/bots/SignalBotList.tsx (83%) rename apps/metamigo-frontend/{components => app/_components}/signal/bots/SignalBotShow.tsx (94%) rename apps/metamigo-frontend/{components => app/_components}/signal/bots/index.ts (96%) create mode 100644 apps/metamigo-frontend/app/_components/signal/bots/shared.tsx rename apps/metamigo-frontend/{components => app/_components}/users/UserCreate.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/users/UserEdit.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/users/UserList.tsx (88%) rename apps/metamigo-frontend/{components => app/_components}/users/index.ts (95%) rename apps/metamigo-frontend/{components => app/_components}/users/shared.tsx (96%) rename apps/metamigo-frontend/{components => app/_components}/voice/providers/ProviderCreate.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/voice/providers/ProviderEdit.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/voice/providers/ProviderList.tsx (96%) rename apps/metamigo-frontend/{components => app/_components}/voice/providers/index.ts (95%) rename apps/metamigo-frontend/{components => app/_components}/voice/providers/shared.tsx (93%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/MicInput.module.css (100%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/MicInput.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/VoiceLineCreate.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/VoiceLineEdit.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/VoiceLineList.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/index.ts (96%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/recorder.module.css (100%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/shared.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/voice/voicelines/twilio-languages.ts (100%) rename apps/metamigo-frontend/{components => app/_components}/webhooks/WebhookCreate.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/webhooks/WebhookEdit.tsx (98%) rename apps/metamigo-frontend/{components => app/_components}/webhooks/WebhookList.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/webhooks/index.ts (95%) rename apps/metamigo-frontend/{components => app/_components}/webhooks/shared.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/attachments/WhatsappAttachmentList.tsx (94%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/attachments/WhatsappAttachmentShow.tsx (95%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/attachments/index.ts (96%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/bots/WhatsappBotCreate.tsx (77%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/bots/WhatsappBotEdit.tsx (95%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/bots/WhatsappBotList.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/bots/WhatsappBotShow.tsx (99%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/bots/index.ts (96%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/bots/shared.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/messages/WhatsappMessageList.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/messages/WhatsappMessageShow.tsx (97%) rename apps/metamigo-frontend/{components => app/_components}/whatsapp/messages/index.ts (95%) rename apps/metamigo-frontend/{i18n => app/_i18n}/en.ts (100%) rename apps/metamigo-frontend/{lib => app/_lib}/absolute-url.ts (100%) rename apps/metamigo-frontend/{lib => app/_lib}/apollo-client.ts (100%) rename apps/metamigo-frontend/{lib => app/_lib}/cloudflare.ts (100%) rename apps/metamigo-frontend/{lib => app/_lib}/dataprovider.ts (100%) rename apps/metamigo-frontend/{lib => app/_lib}/graphql-schema.json (100%) rename apps/metamigo-frontend/{lib => app/_lib}/nextauth-adapter.ts (100%) rename apps/metamigo-frontend/{lib => app/_lib}/phone-numbers.ts (100%) rename apps/metamigo-frontend/{styles => app/_styles}/Home.module.css (100%) rename apps/metamigo-frontend/{styles => app/_styles}/globals.css (100%) create mode 100644 apps/metamigo-frontend/app/admin/_components/Admin.tsx create mode 100644 apps/metamigo-frontend/app/admin/page.tsx rename apps/metamigo-frontend/{pages/api/auth/[...nextauth].ts => app/api/auth/[...nextauth]/route.ts} (77%) rename apps/metamigo-frontend/{pages/api/graphql/[[...path]].ts => app/api/graphql/[[...path]]/route.ts} (89%) rename apps/metamigo-frontend/{pages/api/proxy/[[...path]].js => app/api/proxy/[[...path]]/route.js} (89%) create mode 100644 apps/metamigo-frontend/app/layout.tsx rename apps/metamigo-frontend/{pages/login.tsx => app/login/_components/Login.tsx} (90%) create mode 100644 apps/metamigo-frontend/app/login/page.tsx create mode 100644 apps/metamigo-frontend/app/page.tsx delete mode 100644 apps/metamigo-frontend/components/signal/bots/shared.tsx delete mode 100644 apps/metamigo-frontend/pages/_app.tsx delete mode 100644 apps/metamigo-frontend/pages/admin.tsx delete mode 100644 apps/metamigo-frontend/pages/index.tsx create mode 100644 docker/zammad/install.rb create mode 100644 packages/zammad-addon-metamigo/src/app/jobs/communicate_cdr_signal_job.rb create mode 100644 packages/zammad-addon-metamigo/src/app/jobs/communicate_cdr_whatsapp_job.rb delete mode 100644 packages/zammad-addon-metamigo/src/app/models/observer/ticket/article/communicate_cdr_signal.rb delete mode 100644 packages/zammad-addon-metamigo/src/app/models/observer/ticket/article/communicate_cdr_signal/background_job.rb delete mode 100644 packages/zammad-addon-metamigo/src/app/models/observer/ticket/article/communicate_cdr_whatsapp.rb delete mode 100644 packages/zammad-addon-metamigo/src/app/models/observer/ticket/article/communicate_cdr_whatsapp/background_job.rb create mode 100644 packages/zammad-addon-metamigo/src/app/models/ticket/article/enqueue_communicate_cdr_signal_job.rb create mode 100644 packages/zammad-addon-metamigo/src/app/models/ticket/article/enqueue_communicate_cdr_whatsapp_job.rb diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1df352f..f8492c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: node:20-bullseye-slim +image: node:20-bookworm-slim stages: - build @@ -11,6 +11,7 @@ build-all: TURBO_TOKEN: $TURBO_TOKEN TURBO_TEAM: $TURBO_TEAM script: + - npm install npm@latest -g - npm install -g turbo - npm ci - turbo build diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4183c4a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "prettier.prettierPath": "" +} diff --git a/apps/leafcutter/Dockerfile b/apps/leafcutter/Dockerfile index cd94308..a682ef0 100644 --- a/apps/leafcutter/Dockerfile +++ b/apps/leafcutter/Dockerfile @@ -15,7 +15,7 @@ WORKDIR ${APP_DIR} COPY .gitignore .gitignore COPY --from=builder ${APP_DIR}/out/json/ . COPY --from=builder ${APP_DIR}/out/package-lock.json ./package-lock.json -RUN npm ci --omit=dev +RUN npm ci COPY --from=builder ${APP_DIR}/out/full/ . ARG LINK_EMBEDDED=true diff --git a/apps/leafcutter/pages/login.tsx b/apps/leafcutter/app/(login)/login/_components/Login.tsx similarity index 86% rename from apps/leafcutter/pages/login.tsx rename to apps/leafcutter/app/(login)/login/_components/Login.tsx index 30b4dbd..fe47b5d 100644 --- a/apps/leafcutter/pages/login.tsx +++ b/apps/leafcutter/app/(login)/login/_components/Login.tsx @@ -1,20 +1,21 @@ -import Head from "next/head"; -import { NextPage } from "next"; +"use client"; + +import { FC } from "react"; import Link from "next/link"; import Image from "next/legacy/image"; import { Box, Grid, Container, IconButton } from "@mui/material"; import { Apple as AppleIcon, Google as GoogleIcon } from "@mui/icons-material"; import { useTranslate } from "react-polyglot"; -import { LanguageSelect } from "components/LanguageSelect"; +import { LanguageSelect } from "app/_components/LanguageSelect"; import LeafcutterLogoLarge from "images/leafcutter-logo-large.png"; -import { signIn, getSession } from "next-auth/react"; -import { useAppContext } from "components/AppProvider"; +import { signIn } from "next-auth/react"; +import { useAppContext } from "app/_components/AppProvider"; type LoginProps = { session: any; }; -const Login: NextPage = ({ session }) => { +export const Login: FC = ({ session }) => { const t = useTranslate(); const { colors: { leafcutterElectricBlue, lightGray }, @@ -30,9 +31,6 @@ const Login: NextPage = ({ session }) => { return ( <> - - Leafcutter: Login - @@ -114,13 +112,3 @@ const Login: NextPage = ({ session }) => { ); }; - -export default Login; - -export async function getServerSideProps(context: any) { - const session = (await getSession(context)) ?? null; - - return { - props: { session }, - }; -} diff --git a/apps/leafcutter/app/(login)/login/page.tsx b/apps/leafcutter/app/(login)/login/page.tsx new file mode 100644 index 0000000..5c8263b --- /dev/null +++ b/apps/leafcutter/app/(login)/login/page.tsx @@ -0,0 +1,16 @@ +import { Metadata } from "next"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { Login } from "./_components/Login"; + +export const metadata: Metadata = { + title: "Login", +}; + +export default async function Page() { + const session = await getServerSession(authOptions); + + return ; +} + + diff --git a/apps/leafcutter/pages/about.tsx b/apps/leafcutter/app/(main)/about/_components/About.tsx similarity index 85% rename from apps/leafcutter/pages/about.tsx rename to apps/leafcutter/app/(main)/about/_components/About.tsx index 81dfefb..c9af66a 100644 --- a/apps/leafcutter/pages/about.tsx +++ b/apps/leafcutter/app/(main)/about/_components/About.tsx @@ -1,27 +1,22 @@ -import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next"; +"use client"; + +import { FC } from "react"; import { useTranslate } from "react-polyglot"; -import Head from "next/head"; import Image from "next/legacy/image"; import Link from "next/link"; import { Grid, Container, Box, Button } from "@mui/material"; -import { Layout } from "components/Layout"; -import { useAppContext } from "components/AppProvider"; -import { PageHeader } from "components/PageHeader"; -import { AboutFeature } from "components/AboutFeature"; -import { AboutBox } from "components/AboutBox"; +import { useAppContext } from "app/_components/AppProvider"; +import { PageHeader } from "app/_components/PageHeader"; +import { AboutFeature } from "./AboutFeature"; +import { AboutBox } from "./AboutBox"; import AbstractDiagram from "images/abstract-diagram.png"; import AboutHeader from "images/about-header.png"; import Globe from "images/globe.png"; import Controls from "images/controls.png"; import CommunityBackground from "images/community-background.png"; import Bicycle from "images/bicycle.png"; -import { getEmbedded } from "lib/utils"; -type AboutProps = { - embedded: boolean; -}; - -const About: NextPage = ({ embedded }) => { +export const About: FC = () => { const t = useTranslate(); const { colors: { white, leafcutterElectricBlue, cdrLinkOrange }, @@ -29,10 +24,7 @@ const About: NextPage = ({ embedded }) => { } = useAppContext(); return ( - - - Digital Threat Dashboard – Leafcutter - + <> = ({ embedded }) => { - + ); }; - -export default About; - -export const getServerSideProps: GetServerSideProps = async ( - context: GetServerSidePropsContext -) => ({ props: { embedded: getEmbedded(context) } }); diff --git a/apps/leafcutter/components/AboutBox.tsx b/apps/leafcutter/app/(main)/about/_components/AboutBox.tsx similarity index 87% rename from apps/leafcutter/components/AboutBox.tsx rename to apps/leafcutter/app/(main)/about/_components/AboutBox.tsx index c8d06e9..1bba679 100644 --- a/apps/leafcutter/components/AboutBox.tsx +++ b/apps/leafcutter/app/(main)/about/_components/AboutBox.tsx @@ -1,6 +1,8 @@ +"use client"; + import { FC, PropsWithChildren } from "react"; import { Box } from "@mui/material"; -import { useAppContext } from "./AppProvider"; +import { useAppContext } from "../../../_components/AppProvider"; type AboutBoxProps = PropsWithChildren<{ backgroundColor: string; diff --git a/apps/leafcutter/components/AboutFeature.tsx b/apps/leafcutter/app/(main)/about/_components/AboutFeature.tsx similarity index 95% rename from apps/leafcutter/components/AboutFeature.tsx rename to apps/leafcutter/app/(main)/about/_components/AboutFeature.tsx index b8ff04c..4503625 100644 --- a/apps/leafcutter/components/AboutFeature.tsx +++ b/apps/leafcutter/app/(main)/about/_components/AboutFeature.tsx @@ -1,8 +1,10 @@ +"use client"; + import { FC } from "react"; import Image from "next/legacy/image"; import { Grid, Box, GridSize } from "@mui/material"; import AboutDots from "images/about-dots.png"; -import { useAppContext } from "./AppProvider"; +import { useAppContext } from "app/_components/AppProvider"; interface AboutFeatureProps { title: string; diff --git a/apps/leafcutter/app/(main)/about/page.tsx b/apps/leafcutter/app/(main)/about/page.tsx new file mode 100644 index 0000000..2dc1b39 --- /dev/null +++ b/apps/leafcutter/app/(main)/about/page.tsx @@ -0,0 +1,5 @@ +import { About } from './_components/About'; + +export default function Page() { + return ; +} diff --git a/apps/leafcutter/pages/create.tsx b/apps/leafcutter/app/(main)/create/_components/Create.tsx similarity index 62% rename from apps/leafcutter/pages/create.tsx rename to apps/leafcutter/app/(main)/create/_components/Create.tsx index 865bebf..738e347 100644 --- a/apps/leafcutter/pages/create.tsx +++ b/apps/leafcutter/app/(main)/create/_components/Create.tsx @@ -1,29 +1,26 @@ +"use client"; + import { FC, useEffect } from "react"; -import { GetServerSideProps, GetServerSidePropsContext } from "next"; -import Head from "next/head"; import { useTranslate } from "react-polyglot"; -import { useRouter } from "next/router"; +import { useRouter, usePathname } from "next/navigation"; import { Box, Grid } from "@mui/material"; import { useCookies } from "react-cookie"; -import { getTemplates } from "lib/opensearch"; -import { Layout } from "components/Layout"; -import { useAppContext } from "components/AppProvider"; -import { PageHeader } from "components/PageHeader"; -import { VisualizationBuilder } from "components/VisualizationBuilder"; -import { getEmbedded } from "lib/utils"; +import { useAppContext } from "app/_components/AppProvider"; +import { PageHeader } from "app/_components/PageHeader"; +import { VisualizationBuilder } from "app/_components/VisualizationBuilder"; type CreateProps = { templates: any; - embedded: boolean; }; -const Create: FC = ({ templates, embedded }) => { +export const Create: FC = ({ templates }) => { const t = useTranslate(); const { colors: { cdrLinkOrange }, typography: { h1, h4 }, } = useAppContext(); const router = useRouter(); + const pathname = usePathname(); const cookieName = "searchIntroComplete"; const [cookies, setCookie] = useCookies([cookieName]); const searchIntroComplete = parseInt(cookies[cookieName], 10) || 0; @@ -31,16 +28,12 @@ const Create: FC = ({ templates, embedded }) => { useEffect(() => { if (searchIntroComplete === 0) { setCookie(cookieName, `${1}`, { path: "/" }); - router.push(`${router.pathname}?group=search&tooltip=1&checklist=1`); + router.push(`${pathname}?group=search&tooltip=1&checklist=1`); } }, [searchIntroComplete, router, setCookie]); return ( - - - Digital Threat Dashboard – Leafcutter - - + <> {/* @@ -65,18 +58,7 @@ const Create: FC = ({ templates, embedded }) => { - - + ); }; - -export default Create; - -export const getServerSideProps: GetServerSideProps = async ( - context: GetServerSidePropsContext -) => { - const templates = await getTemplates(100); - - return { props: { templates, embedded: getEmbedded(context) } }; -}; diff --git a/apps/leafcutter/app/(main)/create/page.tsx b/apps/leafcutter/app/(main)/create/page.tsx new file mode 100644 index 0000000..98a1342 --- /dev/null +++ b/apps/leafcutter/app/(main)/create/page.tsx @@ -0,0 +1,8 @@ +import { getTemplates } from "app/_lib/opensearch"; +import { Create } from "./_components/Create"; + +export default async function Page() { + const templates = await getTemplates(100); + + return ; +} diff --git a/apps/leafcutter/pages/faq.tsx b/apps/leafcutter/app/(main)/faq/_components/FAQ.tsx similarity index 77% rename from apps/leafcutter/pages/faq.tsx rename to apps/leafcutter/app/(main)/faq/_components/FAQ.tsx index 61d976d..d5f3952 100644 --- a/apps/leafcutter/pages/faq.tsx +++ b/apps/leafcutter/app/(main)/faq/_components/FAQ.tsx @@ -1,19 +1,14 @@ -import Head from "next/head"; +"use client"; + +import { FC } from "react"; import { useTranslate } from "react-polyglot"; -import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next"; import { Box, Grid } from "@mui/material"; -import { Layout } from "components/Layout"; -import { PageHeader } from "components/PageHeader"; -import { Question } from "components/Question"; -import { useAppContext } from "components/AppProvider"; +import { PageHeader } from "app/_components/PageHeader"; +import { Question } from "app/_components/Question"; +import { useAppContext } from "app/_components/AppProvider"; import FaqHeader from "images/faq-header.svg"; -import { getEmbedded } from "lib/utils"; -type FAQProps = { - embedded: boolean; -}; - -const FAQ: NextPage = ({ embedded }) => { +export const FAQ: FC = () => { const t = useTranslate(); const { colors: { lavender }, @@ -70,10 +65,7 @@ const FAQ: NextPage = ({ embedded }) => { ]; return ( - - - Digital Threat Dashboard – Leafcutter - + <> = ({ embedded }) => { {questions.map((q: any, index: number) => ( ))} - + ); }; - -export default FAQ; - -export const getServerSideProps: GetServerSideProps = async ( - context: GetServerSidePropsContext -) => ({ props: { embedded: getEmbedded(context) } }); diff --git a/apps/leafcutter/app/(main)/faq/page.tsx b/apps/leafcutter/app/(main)/faq/page.tsx new file mode 100644 index 0000000..93c7447 --- /dev/null +++ b/apps/leafcutter/app/(main)/faq/page.tsx @@ -0,0 +1,5 @@ +import { FAQ } from "./_components/FAQ"; + +export default function Page() { + return ; +} diff --git a/apps/leafcutter/app/(main)/layout.tsx b/apps/leafcutter/app/(main)/layout.tsx new file mode 100644 index 0000000..d272093 --- /dev/null +++ b/apps/leafcutter/app/(main)/layout.tsx @@ -0,0 +1,22 @@ +import { ReactNode } from "react"; +import "app/_styles/global.css"; +import "@fontsource/poppins/400.css"; +import "@fontsource/poppins/700.css"; +import "@fontsource/roboto/400.css"; +import "@fontsource/roboto/700.css"; +import "@fontsource/playfair-display/900.css"; +// import getConfig from "next/config"; +// import { LicenseInfo } from "@mui/x-data-grid-pro"; +import { InternalLayout } from "app/_components/InternalLayout"; +import { headers } from 'next/headers' + +type LayoutProps = { + children: ReactNode; +}; + +export default function Layout({ children }: LayoutProps) { + const allHeaders = headers(); + const embedded = Boolean(allHeaders.get('x-leafcutter-embedded')); + + return {children}; +} diff --git a/apps/leafcutter/app/(main)/preview/[...visualizationID]/_components/Preview.tsx b/apps/leafcutter/app/(main)/preview/[...visualizationID]/_components/Preview.tsx new file mode 100644 index 0000000..b35b390 --- /dev/null +++ b/apps/leafcutter/app/(main)/preview/[...visualizationID]/_components/Preview.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { FC } from "react"; +/* eslint-disable no-underscore-dangle */ +import { RawDataViewer } from "app/_components/RawDataViewer"; +import { VisualizationDetail } from "app/_components/VisualizationDetail"; + +interface PreviewProps { + visualization: any; + visualizationType: string; + data: any[]; +} + +export const Preview: FC = ({ + visualization, + visualizationType, + data, +}) => + visualizationType === "rawData" ? ( + + ) : ( + + ); diff --git a/apps/leafcutter/pages/preview/[...visualizationID].tsx b/apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx similarity index 81% rename from apps/leafcutter/pages/preview/[...visualizationID].tsx rename to apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx index 6bb7188..bac4dad 100644 --- a/apps/leafcutter/pages/preview/[...visualizationID].tsx +++ b/apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx @@ -1,29 +1,12 @@ -import { FC } from "react"; /* eslint-disable no-underscore-dangle */ // import { Client } from "@opensearch-project/opensearch"; -import { RawDataViewer } from "components/RawDataViewer"; -import { VisualizationDetail } from "components/VisualizationDetail"; +import { Preview } from "./_components/Preview"; // import { createVisualization } from "lib/opensearch"; -interface PreviewProps { - visualization: any; - visualizationType: string; - data: any[]; +export default function Page() { + return ; } -const Preview: FC = ({ - visualization, - visualizationType, - data, -}) => - visualizationType === "rawData" ? ( - - ) : ( - - ); - -export default Preview; - /* export const getServerSideProps: GetServerSideProps = async ( context: GetServerSidePropsContext diff --git a/apps/leafcutter/pages/setup.tsx b/apps/leafcutter/app/(main)/setup/_components/Setup.tsx similarity index 84% rename from apps/leafcutter/pages/setup.tsx rename to apps/leafcutter/app/(main)/setup/_components/Setup.tsx index 17c1ce0..3092359 100644 --- a/apps/leafcutter/pages/setup.tsx +++ b/apps/leafcutter/app/(main)/setup/_components/Setup.tsx @@ -1,11 +1,13 @@ +"use client"; + +import { FC } from "react"; import { useLayoutEffect } from "react"; -import { NextPage } from "next"; -import { useRouter } from "next/router"; +import { useRouter } from "next/navigation"; import { Grid, CircularProgress } from "@mui/material"; import Iframe from "react-iframe"; -import { useAppContext } from "components/AppProvider"; +import { useAppContext } from "app/_components/AppProvider"; -const Setup: NextPage = () => { +export const Setup: FC = () => { const { colors: { leafcutterElectricBlue }, } = useAppContext(); diff --git a/apps/leafcutter/app/(main)/setup/page.tsx b/apps/leafcutter/app/(main)/setup/page.tsx new file mode 100644 index 0000000..544b40c --- /dev/null +++ b/apps/leafcutter/app/(main)/setup/page.tsx @@ -0,0 +1,6 @@ +import { Setup } from './_components/Setup'; + +export default function Page() { + return ; +} + diff --git a/apps/leafcutter/pages/trends.tsx b/apps/leafcutter/app/(main)/trends/_components/Trends.tsx similarity index 65% rename from apps/leafcutter/pages/trends.tsx rename to apps/leafcutter/app/(main)/trends/_components/Trends.tsx index 3ee350d..ef5a88f 100644 --- a/apps/leafcutter/pages/trends.tsx +++ b/apps/leafcutter/app/(main)/trends/_components/Trends.tsx @@ -1,20 +1,17 @@ -import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next"; -import Head from "next/head"; +"use client"; + +import { FC } from "react"; import { Grid, Box } from "@mui/material"; import { useTranslate } from "react-polyglot"; -import { Layout } from "components/Layout"; -import { getTrends } from "lib/opensearch"; -import { PageHeader } from "components/PageHeader"; -import { VisualizationCard } from "components/VisualizationCard"; -import { useAppContext } from "components/AppProvider"; -import { getEmbedded } from "lib/utils"; +import { PageHeader } from "app/_components/PageHeader"; +import { VisualizationCard } from "app/_components/VisualizationCard"; +import { useAppContext } from "app/_components/AppProvider"; type TrendsProps = { visualizations: any; - embedded: boolean; }; -const Trends: NextPage = ({ visualizations, embedded }) => { +export const Trends: FC = ({ visualizations }) => { const t = useTranslate(); const { colors: { cdrLinkOrange }, @@ -22,10 +19,7 @@ const Trends: NextPage = ({ visualizations, embedded }) => { } = useAppContext(); return ( - - - Digital Threat Dashboard – Leafcutter - + <> = ({ visualizations, embedded }) => { /> ))} - + ); }; - -export default Trends; - -export const getServerSideProps: GetServerSideProps = async ( - context: GetServerSidePropsContext -) => { - const visualizations = await getTrends(25); - - return { props: { visualizations, embedded: getEmbedded(context) } }; -}; diff --git a/apps/leafcutter/app/(main)/trends/page.tsx b/apps/leafcutter/app/(main)/trends/page.tsx new file mode 100644 index 0000000..9a33786 --- /dev/null +++ b/apps/leafcutter/app/(main)/trends/page.tsx @@ -0,0 +1,8 @@ +import { getTrends } from "app/_lib/opensearch"; +import { Trends } from "./_components/Trends"; + +export default async function Page() { + const visualizations = await getTrends(25); + + return ; +} diff --git a/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx b/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx new file mode 100644 index 0000000..aa8d839 --- /dev/null +++ b/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx @@ -0,0 +1,46 @@ +/* eslint-disable no-underscore-dangle */ +import { Client } from "@opensearch-project/opensearch"; +import { VisualizationDetail } from "app/_components/VisualizationDetail"; + +const getVisualization = async (visualizationID: string) => { + const node = `https://${process.env.OPENSEARCH_USERNAME}:${process.env.OPENSEARCH_PASSWORD}@${process.env.OPENSEARCH_URL}`; + const client = new Client({ + node, + ssl: { + rejectUnauthorized: false, + }, + }); + + const rawResponse = await client.search({ + index: ".kibana_1", + size: 200, + }); + const response = rawResponse.body; + + const hits = response.hits.hits.filter( + (hit: any) => hit._id.split(":")[1] === visualizationID[0] + ); + const hit = hits[0]; + const visualization = { + id: hit._id.split(":")[1], + title: hit._source.visualization.title, + description: hit._source.visualization.description, + url: `/app/visualize?security_tenant=global#/edit/${ + hit._id.split(":")[1] + }?embed=true`, + }; + + return visualization; +}; + +type PageProps = { + params: { + visualizationID: string; + }; +}; + +export default async function Page({ params: { visualizationID } }: PageProps) { + const visualization = await getVisualization(visualizationID); + + return ; +} diff --git a/apps/leafcutter/components/AccountButton.tsx b/apps/leafcutter/app/_components/AccountButton.tsx similarity index 98% rename from apps/leafcutter/components/AccountButton.tsx rename to apps/leafcutter/app/_components/AccountButton.tsx index 82a324b..45a3f4e 100644 --- a/apps/leafcutter/components/AccountButton.tsx +++ b/apps/leafcutter/app/_components/AccountButton.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import Image from "next/legacy/image"; import { signOut } from "next-auth/react"; diff --git a/apps/leafcutter/components/AppProvider.tsx b/apps/leafcutter/app/_components/AppProvider.tsx similarity index 98% rename from apps/leafcutter/components/AppProvider.tsx rename to apps/leafcutter/app/_components/AppProvider.tsx index f829271..e20d036 100644 --- a/apps/leafcutter/components/AppProvider.tsx +++ b/apps/leafcutter/app/_components/AppProvider.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, createContext, @@ -6,7 +8,7 @@ import { useState, PropsWithChildren, } from "react"; -import { colors, typography } from "styles/theme"; +import { colors, typography } from "app/_styles/theme"; const basePath = process.env.GITLAB_CI ? "/link/link-stack/apps/leafcutter" diff --git a/apps/leafcutter/components/Button.tsx b/apps/leafcutter/app/_components/Button.tsx similarity index 98% rename from apps/leafcutter/components/Button.tsx rename to apps/leafcutter/app/_components/Button.tsx index 923705c..461bf46 100644 --- a/apps/leafcutter/components/Button.tsx +++ b/apps/leafcutter/app/_components/Button.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import Link from "next/link"; import { Button as MUIButton } from "@mui/material"; diff --git a/apps/leafcutter/components/Footer.tsx b/apps/leafcutter/app/_components/Footer.tsx similarity index 99% rename from apps/leafcutter/components/Footer.tsx rename to apps/leafcutter/app/_components/Footer.tsx index 49ec23b..b81d54d 100644 --- a/apps/leafcutter/components/Footer.tsx +++ b/apps/leafcutter/app/_components/Footer.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import { Container, Grid, Box, Button } from "@mui/material"; import { useTranslate } from "react-polyglot"; diff --git a/apps/leafcutter/components/GettingStartedDialog.tsx b/apps/leafcutter/app/_components/GettingStartedDialog.tsx similarity index 92% rename from apps/leafcutter/components/GettingStartedDialog.tsx rename to apps/leafcutter/app/_components/GettingStartedDialog.tsx index 1e5f94c..20f688e 100644 --- a/apps/leafcutter/components/GettingStartedDialog.tsx +++ b/apps/leafcutter/app/_components/GettingStartedDialog.tsx @@ -1,7 +1,9 @@ +"use client"; + import { FC, useState } from "react"; import { Dialog, Box, Grid, Checkbox, IconButton } from "@mui/material"; import { Close as CloseIcon } from "@mui/icons-material"; -import { useRouter } from "next/router"; +import { useRouter, usePathname, useSearchParams } from "next/navigation"; import { useTranslate } from "react-polyglot"; import { useAppContext } from "./AppProvider"; @@ -60,9 +62,11 @@ export const GettingStartedDialog: FC = () => { typography: { h4 }, } = useAppContext(); const t = useTranslate(); - const [completedItems, setCompletedItems] = useState([] as any[]); const router = useRouter(); - const open = router.query.tooltip?.toString() === "checklist"; + const [completedItems, setCompletedItems] = useState([] as any[]); + const searchParams = useSearchParams(); + const pathname = usePathname(); + const open = searchParams.get("tooltip")?.toString() === "checklist"; const toggleCompletedItem = (item: any) => { if (completedItems.includes(item)) { setCompletedItems(completedItems.filter((i) => i !== item)); @@ -90,7 +94,7 @@ export const GettingStartedDialog: FC = () => { {t("getStartedChecklist")} - router.push(router.pathname)}> + router.push(pathname)}> diff --git a/apps/leafcutter/components/HelpButton.tsx b/apps/leafcutter/app/_components/HelpButton.tsx similarity index 88% rename from apps/leafcutter/components/HelpButton.tsx rename to apps/leafcutter/app/_components/HelpButton.tsx index a67b1a2..6d279dc 100644 --- a/apps/leafcutter/components/HelpButton.tsx +++ b/apps/leafcutter/app/_components/HelpButton.tsx @@ -1,18 +1,21 @@ +"use client"; + import { FC, useState } from "react"; -import { useRouter } from "next/router"; +import { useRouter, usePathname } from "next/navigation"; import { Button } from "@mui/material"; import { QuestionMark as QuestionMarkIcon } from "@mui/icons-material"; import { useAppContext } from "./AppProvider"; export const HelpButton: FC = () => { const router = useRouter(); + const pathname = usePathname(); const [helpActive, setHelpActive] = useState(false); const { colors: { leafcutterElectricBlue }, } = useAppContext(); const onClick = () => { if (helpActive) { - router.push(router.pathname); + router.push(pathname); } else { router.push("/?tooltip=welcome"); } diff --git a/apps/leafcutter/pages/index.tsx b/apps/leafcutter/app/_components/Home.tsx similarity index 64% rename from apps/leafcutter/pages/index.tsx rename to apps/leafcutter/app/_components/Home.tsx index 9432e08..33299ac 100644 --- a/apps/leafcutter/pages/index.tsx +++ b/apps/leafcutter/app/_components/Home.tsx @@ -1,31 +1,24 @@ -import { useEffect } from "react"; -import { NextPage, GetServerSideProps, GetServerSidePropsContext } from "next"; -import { useRouter } from "next/router"; -import { getSession } from "next-auth/react"; -import Head from "next/head"; +"use client"; + +import { useEffect, FC } from "react"; +import { useRouter, usePathname } from "next/navigation"; import Link from "next/link"; import ReactMarkdown from "react-markdown"; import { Grid, Button } from "@mui/material"; import { useTranslate } from "react-polyglot"; import { useCookies } from "react-cookie"; -import { Layout } from "components/Layout"; -import { getUserVisualizations } from "lib/opensearch"; -import { Welcome } from "components/Welcome"; -import { WelcomeDialog } from "components/WelcomeDialog"; -import { VisualizationCard } from "components/VisualizationCard"; -import { useAppContext } from "components/AppProvider"; -import { getEmbedded } from "lib/utils"; +import { Welcome } from "app/_components/Welcome"; +import { WelcomeDialog } from "app/_components/WelcomeDialog"; +import { VisualizationCard } from "app/_components/VisualizationCard"; +import { useAppContext } from "app/_components/AppProvider"; -type MyVisualizationsProps = { +type HomeProps = { visualizations: any; - embedded: boolean; }; -const MyVisualizations: NextPage = ({ - visualizations, - embedded, -}) => { +export const Home: FC = ({ visualizations }) => { const router = useRouter(); + const pathname = usePathname(); const cookieName = "homeIntroComplete"; const [cookies, setCookie] = useCookies([cookieName]); const t = useTranslate(); @@ -38,15 +31,12 @@ const MyVisualizations: NextPage = ({ useEffect(() => { if (homeIntroComplete === 0) { setCookie(cookieName, `${1}`, { path: "/" }); - router.push(`${router.pathname}?tooltip=welcome`); + router.push(`${pathname}?tooltip=welcome`); } }, [homeIntroComplete, router, setCookie]); return ( - - - Digital Threat Dashboard – Leafcutter - + <> = ({ ))} - + ); }; - -export default MyVisualizations; - -export const getServerSideProps: GetServerSideProps = async ( - context: GetServerSidePropsContext -) => { - const session = (await getSession(context)) ?? null; - const visualizations = await getUserVisualizations( - session?.user?.email ?? "none", - 20 - ); - return { props: { visualizations, embedded: getEmbedded(context) } }; -}; diff --git a/apps/leafcutter/components/Layout.tsx b/apps/leafcutter/app/_components/InternalLayout.tsx similarity index 96% rename from apps/leafcutter/components/Layout.tsx rename to apps/leafcutter/app/_components/InternalLayout.tsx index 29a63fc..33166f2 100644 --- a/apps/leafcutter/components/Layout.tsx +++ b/apps/leafcutter/app/_components/InternalLayout.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, PropsWithChildren } from "react"; import getConfig from "next/config"; import { Grid, Container } from "@mui/material"; @@ -13,7 +15,7 @@ type LayoutProps = PropsWithChildren<{ embedded?: boolean; }>; -export const Layout: FC = ({ +export const InternalLayout: FC = ({ embedded = false, children, }: any) => { diff --git a/apps/leafcutter/components/LanguageSelect.tsx b/apps/leafcutter/app/_components/LanguageSelect.tsx similarity index 89% rename from apps/leafcutter/components/LanguageSelect.tsx rename to apps/leafcutter/app/_components/LanguageSelect.tsx index e8b4fbf..9887691 100644 --- a/apps/leafcutter/components/LanguageSelect.tsx +++ b/apps/leafcutter/app/_components/LanguageSelect.tsx @@ -1,4 +1,6 @@ -import { useRouter } from "next/router"; +"use client"; + +import { useRouter } from "next/navigation"; import { IconButton, Menu, MenuItem, Box } from "@mui/material"; import { KeyboardArrowDown as KeyboardArrowDownIcon } from "@mui/icons-material"; import { @@ -15,6 +17,7 @@ export const LanguageSelect = () => { } = useAppContext(); const router = useRouter(); const locales: any = { en: "English", fr: "Français" }; + const locale = "en"; const popupState = usePopupState({ variant: "popover", popupId: "language" }); return ( @@ -36,7 +39,7 @@ export const LanguageSelect = () => { }, }} > - {locales[router.locale as any] ?? locales.en} + {locales[locale as any] ?? locales.en} @@ -44,7 +47,7 @@ export const LanguageSelect = () => { { - router.push(router.route, router.route, { locale }); + // router.push(router.route, router.route, { locale }); popupState.close(); }} > diff --git a/apps/leafcutter/components/LiveDataViewer.tsx b/apps/leafcutter/app/_components/LiveDataViewer.tsx similarity index 97% rename from apps/leafcutter/components/LiveDataViewer.tsx rename to apps/leafcutter/app/_components/LiveDataViewer.tsx index 9ff9436..c69f9cd 100644 --- a/apps/leafcutter/components/LiveDataViewer.tsx +++ b/apps/leafcutter/app/_components/LiveDataViewer.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useEffect, useState } from "react"; import { useAppContext } from "./AppProvider"; import { RawDataViewer } from "./RawDataViewer"; diff --git a/apps/leafcutter/components/MetricSelectCard.tsx b/apps/leafcutter/app/_components/MetricSelectCard.tsx similarity index 99% rename from apps/leafcutter/components/MetricSelectCard.tsx rename to apps/leafcutter/app/_components/MetricSelectCard.tsx index 60a08f5..f40bb92 100644 --- a/apps/leafcutter/components/MetricSelectCard.tsx +++ b/apps/leafcutter/app/_components/MetricSelectCard.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useState } from "react"; import { Card, Grid } from "@mui/material"; import { diff --git a/apps/leafcutter/app/_components/MultiProvider.tsx b/apps/leafcutter/app/_components/MultiProvider.tsx new file mode 100644 index 0000000..c6e6f04 --- /dev/null +++ b/apps/leafcutter/app/_components/MultiProvider.tsx @@ -0,0 +1,49 @@ +"use client"; + +/* eslint-disable react/jsx-props-no-spreading */ +import { FC, PropsWithChildren } from "react"; +import { SessionProvider } from "next-auth/react"; +import { CssBaseline } from "@mui/material"; +import { CookiesProvider } from "react-cookie"; +import { I18n } from "react-polyglot"; +import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; +import { LocalizationProvider } from "@mui/x-date-pickers-pro"; +import { AppProvider } from "app/_components/AppProvider"; +import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir"; +import en from "app/_locales/en.json"; +import fr from "app/_locales/fr.json"; +import "@fontsource/poppins/400.css"; +import "@fontsource/poppins/700.css"; +import "@fontsource/roboto/400.css"; +import "@fontsource/roboto/700.css"; +import "@fontsource/playfair-display/900.css"; +import "app/_styles/global.css"; +import { LicenseInfo } from "@mui/x-date-pickers-pro"; + +LicenseInfo.setLicenseKey( + "7c9bf25d9e240f76e77cbf7d2ba58a23Tz02NjU4OCxFPTE3MTU4NjIzMzQ2ODgsUz1wcm8sTE09c3Vic2NyaXB0aW9uLEtWPTI=" +); + +const messages: any = { en, fr }; + +export const MultiProvider: FC = ({ children }: any) => { + // const { locale = "en" } = useRouter(); + const locale = "en"; + + return ( + + + + + + + + {children} + + + + + + + ); +}; diff --git a/apps/leafcutter/components/OpenSearchWrapper.tsx b/apps/leafcutter/app/_components/OpenSearchWrapper.tsx similarity index 98% rename from apps/leafcutter/components/OpenSearchWrapper.tsx rename to apps/leafcutter/app/_components/OpenSearchWrapper.tsx index 4f74208..2ec8f79 100644 --- a/apps/leafcutter/components/OpenSearchWrapper.tsx +++ b/apps/leafcutter/app/_components/OpenSearchWrapper.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import Iframe from "react-iframe"; import { Box } from "@mui/material"; diff --git a/apps/leafcutter/components/PageHeader.tsx b/apps/leafcutter/app/_components/PageHeader.tsx similarity index 98% rename from apps/leafcutter/components/PageHeader.tsx rename to apps/leafcutter/app/_components/PageHeader.tsx index 46c31d2..65b60c4 100644 --- a/apps/leafcutter/components/PageHeader.tsx +++ b/apps/leafcutter/app/_components/PageHeader.tsx @@ -1,3 +1,5 @@ +"use client"; + /* eslint-disable react/require-default-props */ import { FC, PropsWithChildren } from "react"; import { Box } from "@mui/material"; diff --git a/apps/leafcutter/components/QueryBuilder.tsx b/apps/leafcutter/app/_components/QueryBuilder.tsx similarity index 98% rename from apps/leafcutter/components/QueryBuilder.tsx rename to apps/leafcutter/app/_components/QueryBuilder.tsx index bbf8846..8861da9 100644 --- a/apps/leafcutter/components/QueryBuilder.tsx +++ b/apps/leafcutter/app/_components/QueryBuilder.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useState } from "react"; import { Box, @@ -15,14 +17,14 @@ import { Group as GroupIcon, } from "@mui/icons-material"; import { useTranslate } from "react-polyglot"; -import taxonomy from "config/taxonomy.json"; +import taxonomy from "app/_config/taxonomy.json"; import { QueryBuilderSection } from "./QueryBuilderSection"; import { QueryListSelector } from "./QueryListSelector"; import { QueryDateRangeSelector } from "./QueryDateRangeSelector"; import { useAppContext } from "./AppProvider"; import { Tooltip } from "./Tooltip"; -interface QueryBuilderProps { } +interface QueryBuilderProps {} export const QueryBuilder: FC = () => { const t = useTranslate(); diff --git a/apps/leafcutter/components/QueryBuilderSection.tsx b/apps/leafcutter/app/_components/QueryBuilderSection.tsx similarity index 99% rename from apps/leafcutter/components/QueryBuilderSection.tsx rename to apps/leafcutter/app/_components/QueryBuilderSection.tsx index 99dad2e..b8ec4c7 100644 --- a/apps/leafcutter/components/QueryBuilderSection.tsx +++ b/apps/leafcutter/app/_components/QueryBuilderSection.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, PropsWithChildren, useState } from "react"; import { Box, diff --git a/apps/leafcutter/components/QueryDateRangeSelector.tsx b/apps/leafcutter/app/_components/QueryDateRangeSelector.tsx similarity index 98% rename from apps/leafcutter/components/QueryDateRangeSelector.tsx rename to apps/leafcutter/app/_components/QueryDateRangeSelector.tsx index bc8c82e..ae4fce2 100644 --- a/apps/leafcutter/components/QueryDateRangeSelector.tsx +++ b/apps/leafcutter/app/_components/QueryDateRangeSelector.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useState, useEffect } from "react"; import { Box, Grid, TextField, Select, MenuItem } from "@mui/material"; import { DatePicker } from "@mui/x-date-pickers-pro"; @@ -90,7 +92,7 @@ export const QueryDateRangeSelector: FC = () => { endDate: { values: [date] }, }); }} - // @ts-ignore + // @ts-ignore renderInput={(params) => ( { diff --git a/apps/leafcutter/components/Question.tsx b/apps/leafcutter/app/_components/Question.tsx similarity index 99% rename from apps/leafcutter/components/Question.tsx rename to apps/leafcutter/app/_components/Question.tsx index 50af2a9..a2213b0 100644 --- a/apps/leafcutter/components/Question.tsx +++ b/apps/leafcutter/app/_components/Question.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useState } from "react"; import ReactMarkdown from "react-markdown"; import { diff --git a/apps/leafcutter/components/RawDataViewer.tsx b/apps/leafcutter/app/_components/RawDataViewer.tsx similarity index 99% rename from apps/leafcutter/components/RawDataViewer.tsx rename to apps/leafcutter/app/_components/RawDataViewer.tsx index bad2385..101fd19 100644 --- a/apps/leafcutter/components/RawDataViewer.tsx +++ b/apps/leafcutter/app/_components/RawDataViewer.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import { Box, Grid } from "@mui/material"; import { DataGridPro } from "@mui/x-data-grid-pro"; diff --git a/apps/leafcutter/components/Sidebar.tsx b/apps/leafcutter/app/_components/Sidebar.tsx similarity index 96% rename from apps/leafcutter/components/Sidebar.tsx rename to apps/leafcutter/app/_components/Sidebar.tsx index 136b371..b6ddf55 100644 --- a/apps/leafcutter/components/Sidebar.tsx +++ b/apps/leafcutter/app/_components/Sidebar.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import DashboardMenuIcon from "images/dashboard-menu.png"; import AboutMenuIcon from "images/about-menu.png"; @@ -16,10 +18,10 @@ import { Drawer, } from "@mui/material"; import Link from "next/link"; -import { useRouter } from "next/router"; +import { usePathname } from "next/navigation"; import { useTranslate } from "react-polyglot"; -import { useAppContext } from "components/AppProvider"; -import { Tooltip } from "components/Tooltip"; +import { useAppContext } from "app/_components/AppProvider"; +import { Tooltip } from "app/_components/Tooltip"; // import { ArrowCircleRight as ArrowCircleRightIcon } from "@mui/icons-material"; const MenuItem = ({ @@ -99,8 +101,8 @@ interface SidebarProps { export const Sidebar: FC = ({ open }) => { const t = useTranslate(); - const router = useRouter(); - const section = router.pathname.split("/")[1]; + const pathname = usePathname(); + const section = pathname.split("/")[1]; const { colors: { white }, // leafcutterElectricBlue, leafcutterLightBlue, } = useAppContext(); diff --git a/apps/leafcutter/components/Tooltip.tsx b/apps/leafcutter/app/_components/Tooltip.tsx similarity index 92% rename from apps/leafcutter/components/Tooltip.tsx rename to apps/leafcutter/app/_components/Tooltip.tsx index b541055..aa2f25d 100644 --- a/apps/leafcutter/components/Tooltip.tsx +++ b/apps/leafcutter/app/_components/Tooltip.tsx @@ -1,6 +1,8 @@ +"use client"; + /* eslint-disable react/require-default-props */ import { FC } from "react"; -import { useRouter } from "next/router"; +import { useRouter, usePathname, useSearchParams } from "next/navigation"; import { Box, Grid, @@ -38,7 +40,9 @@ export const Tooltip: FC = ({ colors: { white, leafcutterElectricBlue, almostBlack }, } = useAppContext(); const router = useRouter(); - const activeTooltip = router.query.tooltip?.toString(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + const activeTooltip = searchParams.get('tooltip')?.toString(); const open = activeTooltip === tooltipID; const showNavigation = true; @@ -49,7 +53,7 @@ export const Tooltip: FC = ({ - router.push(router.pathname)}> + router.push(pathname)}> = ({ color: leafcutterElectricBlue, textTransform: "none", }} - onClick={() => router.push(router.pathname)} + onClick={() => router.push(pathname)} > {t("done")} diff --git a/apps/leafcutter/components/TopNav.tsx b/apps/leafcutter/app/_components/TopNav.tsx similarity index 94% rename from apps/leafcutter/components/TopNav.tsx rename to apps/leafcutter/app/_components/TopNav.tsx index f21af59..720d2b1 100644 --- a/apps/leafcutter/components/TopNav.tsx +++ b/apps/leafcutter/app/_components/TopNav.tsx @@ -1,12 +1,14 @@ +"use client"; + import { FC } from "react"; import Link from "next/link"; import Image from "next/legacy/image"; import { AppBar, Grid, Box } from "@mui/material"; import { useTranslate } from "react-polyglot"; import LeafcutterLogo from "images/leafcutter-logo.png"; -import { AccountButton } from "components/AccountButton"; -import { HelpButton } from "components/HelpButton"; -import { Tooltip } from "components/Tooltip"; +import { AccountButton } from "app/_components/AccountButton"; +import { HelpButton } from "app/_components/HelpButton"; +import { Tooltip } from "app/_components/Tooltip"; import { useAppContext } from "./AppProvider"; // import { LanguageSelect } from "./LanguageSelect"; diff --git a/apps/leafcutter/components/VisualizationBuilder.tsx b/apps/leafcutter/app/_components/VisualizationBuilder.tsx similarity index 97% rename from apps/leafcutter/components/VisualizationBuilder.tsx rename to apps/leafcutter/app/_components/VisualizationBuilder.tsx index 81f2295..96e2f4e 100644 --- a/apps/leafcutter/components/VisualizationBuilder.tsx +++ b/apps/leafcutter/app/_components/VisualizationBuilder.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useState, useEffect } from "react"; import { Box, @@ -23,11 +25,11 @@ import { RemoveCircle as RemoveCircleIcon, } from "@mui/icons-material"; import { useTranslate } from "react-polyglot"; -import { QueryBuilder } from "components/QueryBuilder"; -import { QueryText } from "components/QueryText"; -import { LiveDataViewer } from "components/LiveDataViewer"; -import { Tooltip } from "components/Tooltip"; -import visualizationMap from "config/visualizationMap.json"; +import { QueryBuilder } from "app/_components/QueryBuilder"; +import { QueryText } from "app/_components/QueryText"; +import { LiveDataViewer } from "app/_components/LiveDataViewer"; +import { Tooltip } from "app/_components/Tooltip"; +import visualizationMap from "app/_config/visualizationMap.json"; import { VisualizationSelectCard } from "./VisualizationSelectCard"; import { MetricSelectCard } from "./MetricSelectCard"; import { useAppContext } from "./AppProvider"; diff --git a/apps/leafcutter/components/VisualizationCard.tsx b/apps/leafcutter/app/_components/VisualizationCard.tsx similarity index 92% rename from apps/leafcutter/components/VisualizationCard.tsx rename to apps/leafcutter/app/_components/VisualizationCard.tsx index 5d63bd7..fcb55d1 100644 --- a/apps/leafcutter/components/VisualizationCard.tsx +++ b/apps/leafcutter/app/_components/VisualizationCard.tsx @@ -1,8 +1,10 @@ +"use client"; + import { FC, useState } from "react"; import { Grid, Card, Box } from "@mui/material"; import Iframe from "react-iframe"; -import { useAppContext } from "components/AppProvider"; -import { VisualizationDetailDialog } from "components/VisualizationDetailDialog"; +import { useAppContext } from "app/_components/AppProvider"; +import { VisualizationDetailDialog } from "app/_components/VisualizationDetailDialog"; interface VisualizationCardProps { id: string; diff --git a/apps/leafcutter/components/VisualizationDetail.tsx b/apps/leafcutter/app/_components/VisualizationDetail.tsx similarity index 91% rename from apps/leafcutter/components/VisualizationDetail.tsx rename to apps/leafcutter/app/_components/VisualizationDetail.tsx index b338cf0..0c7b025 100644 --- a/apps/leafcutter/components/VisualizationDetail.tsx +++ b/apps/leafcutter/app/_components/VisualizationDetail.tsx @@ -1,8 +1,10 @@ +"use client"; + import { FC } from "react"; // import Link from "next/link"; import { Box } from "@mui/material"; import Iframe from "react-iframe"; -import { useAppContext } from "components/AppProvider"; +import { useAppContext } from "app/_components/AppProvider"; interface VisualizationDetailProps { id: string; @@ -24,7 +26,7 @@ export const VisualizationDetail: FC = ({ typography: { h4, p }, } = useAppContext(); const finalURL = `${process.env.NEXT_PUBLIC_NEXTAUTH_URL}${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`; - + console.log({ finalURL }); return ( {!editing ? ( diff --git a/apps/leafcutter/components/VisualizationDetailDialog.tsx b/apps/leafcutter/app/_components/VisualizationDetailDialog.tsx similarity index 98% rename from apps/leafcutter/components/VisualizationDetailDialog.tsx rename to apps/leafcutter/app/_components/VisualizationDetailDialog.tsx index 8ddd296..ee82196 100644 --- a/apps/leafcutter/components/VisualizationDetailDialog.tsx +++ b/apps/leafcutter/app/_components/VisualizationDetailDialog.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC, useState } from "react"; // import Link from "next/link"; import { @@ -9,7 +11,7 @@ import { TextField, } from "@mui/material"; import { useTranslate } from "react-polyglot"; -import { useAppContext } from "components/AppProvider"; +import { useAppContext } from "app/_components/AppProvider"; import { VisualizationDetail } from "./VisualizationDetail"; interface VisualizationDetailDialogProps { diff --git a/apps/leafcutter/components/VisualizationSelectCard.tsx b/apps/leafcutter/app/_components/VisualizationSelectCard.tsx similarity index 99% rename from apps/leafcutter/components/VisualizationSelectCard.tsx rename to apps/leafcutter/app/_components/VisualizationSelectCard.tsx index 6486be8..03ae8cd 100644 --- a/apps/leafcutter/components/VisualizationSelectCard.tsx +++ b/apps/leafcutter/app/_components/VisualizationSelectCard.tsx @@ -1,3 +1,5 @@ +"use client"; + import { FC } from "react"; import Image from "next/legacy/image"; import { Card, Grid } from "@mui/material"; diff --git a/apps/leafcutter/components/Welcome.tsx b/apps/leafcutter/app/_components/Welcome.tsx similarity index 96% rename from apps/leafcutter/components/Welcome.tsx rename to apps/leafcutter/app/_components/Welcome.tsx index 7a4abe6..25f7865 100644 --- a/apps/leafcutter/components/Welcome.tsx +++ b/apps/leafcutter/app/_components/Welcome.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Box, Grid } from "@mui/material"; import { useSession } from "next-auth/react"; import { useTranslate } from "react-polyglot"; @@ -6,9 +8,12 @@ import { useAppContext } from "./AppProvider"; export const Welcome = () => { const t = useTranslate(); const { data: session } = useSession(); + /* const { user: { name }, } = session as any; + */ + const name = "Test User"; const { colors: { white, leafcutterElectricBlue }, typography: { h1, h4, p }, diff --git a/apps/leafcutter/components/WelcomeDialog.tsx b/apps/leafcutter/app/_components/WelcomeDialog.tsx similarity index 96% rename from apps/leafcutter/components/WelcomeDialog.tsx rename to apps/leafcutter/app/_components/WelcomeDialog.tsx index 5f3fddd..59cc4d4 100644 --- a/apps/leafcutter/components/WelcomeDialog.tsx +++ b/apps/leafcutter/app/_components/WelcomeDialog.tsx @@ -1,5 +1,7 @@ +"use client"; + import { Box, Grid, Dialog, Button } from "@mui/material"; -import { useRouter } from "next/router"; +import { useRouter, useSearchParams } from "next/navigation"; // import { useSession } from "next-auth/react"; // import { useTranslate } from "react-polyglot"; import { useAppContext } from "./AppProvider"; @@ -7,13 +9,14 @@ import { useAppContext } from "./AppProvider"; export const WelcomeDialog = () => { // const t = useTranslate(); const router = useRouter(); + const searchParams = useSearchParams(); // const { data: session } = useSession(); // const { user } = session; const { colors: { white, leafcutterElectricBlue }, typography: { h1, h6, p }, } = useAppContext(); - const activeTooltip = router.query.tooltip?.toString(); + const activeTooltip = searchParams.get('tooltip')?.toString(); const open = activeTooltip === "welcome"; return ( diff --git a/apps/leafcutter/config/taxonomy.json b/apps/leafcutter/app/_config/taxonomy.json similarity index 100% rename from apps/leafcutter/config/taxonomy.json rename to apps/leafcutter/app/_config/taxonomy.json diff --git a/apps/leafcutter/config/unRegions.json b/apps/leafcutter/app/_config/unRegions.json similarity index 100% rename from apps/leafcutter/config/unRegions.json rename to apps/leafcutter/app/_config/unRegions.json diff --git a/apps/leafcutter/config/visualizationMap.json b/apps/leafcutter/app/_config/visualizationMap.json similarity index 100% rename from apps/leafcutter/config/visualizationMap.json rename to apps/leafcutter/app/_config/visualizationMap.json diff --git a/apps/leafcutter/config/visualizations/dataTable.json b/apps/leafcutter/app/_config/visualizations/dataTable.json similarity index 100% rename from apps/leafcutter/config/visualizations/dataTable.json rename to apps/leafcutter/app/_config/visualizations/dataTable.json diff --git a/apps/leafcutter/config/visualizations/horizontalBar.json b/apps/leafcutter/app/_config/visualizations/horizontalBar.json similarity index 100% rename from apps/leafcutter/config/visualizations/horizontalBar.json rename to apps/leafcutter/app/_config/visualizations/horizontalBar.json diff --git a/apps/leafcutter/config/visualizations/horizontalBarStacked.json b/apps/leafcutter/app/_config/visualizations/horizontalBarStacked.json similarity index 100% rename from apps/leafcutter/config/visualizations/horizontalBarStacked.json rename to apps/leafcutter/app/_config/visualizations/horizontalBarStacked.json diff --git a/apps/leafcutter/config/visualizations/line.json b/apps/leafcutter/app/_config/visualizations/line.json similarity index 100% rename from apps/leafcutter/config/visualizations/line.json rename to apps/leafcutter/app/_config/visualizations/line.json diff --git a/apps/leafcutter/config/visualizations/lineStacked.json b/apps/leafcutter/app/_config/visualizations/lineStacked.json similarity index 100% rename from apps/leafcutter/config/visualizations/lineStacked.json rename to apps/leafcutter/app/_config/visualizations/lineStacked.json diff --git a/apps/leafcutter/config/visualizations/metric.json b/apps/leafcutter/app/_config/visualizations/metric.json similarity index 100% rename from apps/leafcutter/config/visualizations/metric.json rename to apps/leafcutter/app/_config/visualizations/metric.json diff --git a/apps/leafcutter/config/visualizations/pieDonut.json b/apps/leafcutter/app/_config/visualizations/pieDonut.json similarity index 100% rename from apps/leafcutter/config/visualizations/pieDonut.json rename to apps/leafcutter/app/_config/visualizations/pieDonut.json diff --git a/apps/leafcutter/config/visualizations/tagCloud.json b/apps/leafcutter/app/_config/visualizations/tagCloud.json similarity index 100% rename from apps/leafcutter/config/visualizations/tagCloud.json rename to apps/leafcutter/app/_config/visualizations/tagCloud.json diff --git a/apps/leafcutter/config/visualizations/verticalBar.json b/apps/leafcutter/app/_config/visualizations/verticalBar.json similarity index 100% rename from apps/leafcutter/config/visualizations/verticalBar.json rename to apps/leafcutter/app/_config/visualizations/verticalBar.json diff --git a/apps/leafcutter/config/visualizations/verticalBarStacked.json b/apps/leafcutter/app/_config/visualizations/verticalBarStacked.json similarity index 100% rename from apps/leafcutter/config/visualizations/verticalBarStacked.json rename to apps/leafcutter/app/_config/visualizations/verticalBarStacked.json diff --git a/apps/leafcutter/pages/api/auth/[...nextauth].ts b/apps/leafcutter/app/_lib/auth.ts similarity index 80% rename from apps/leafcutter/pages/api/auth/[...nextauth].ts rename to apps/leafcutter/app/_lib/auth.ts index 0705c42..a8c9426 100644 --- a/apps/leafcutter/pages/api/auth/[...nextauth].ts +++ b/apps/leafcutter/app/_lib/auth.ts @@ -1,8 +1,8 @@ -import NextAuth from "next-auth"; +import type { NextAuthOptions } from "next-auth"; import Google from "next-auth/providers/google"; import Apple from "next-auth/providers/apple"; -export default NextAuth({ +export const authOptions: NextAuthOptions = { providers: [ Google({ clientId: process.env.GOOGLE_CLIENT_ID ?? "", @@ -14,4 +14,4 @@ export default NextAuth({ }), ], secret: process.env.NEXTAUTH_SECRET, -}); +}; diff --git a/apps/leafcutter/lib/opensearch.ts b/apps/leafcutter/app/_lib/opensearch.ts similarity index 98% rename from apps/leafcutter/lib/opensearch.ts rename to apps/leafcutter/app/_lib/opensearch.ts index 10985d0..46730f6 100644 --- a/apps/leafcutter/lib/opensearch.ts +++ b/apps/leafcutter/app/_lib/opensearch.ts @@ -8,10 +8,16 @@ const globalIndex = ".kibana_1"; const dataIndexName = "sample_tagged_tickets"; const userMetadataIndexName = "user_metadata"; -const baseURL = `https://${process.env.OPENSEARCH_USERNAME}:${process.env.OPENSEARCH_PASSWORD}@${process.env.OPENSEARCH_URL}`; +// const baseURL = `https://${process.env.OPENSEARCH_USERNAME}:${process.env.OPENSEARCH_PASSWORD}@${process.env.OPENSEARCH_URL}`; + +const baseURL = `https://localhost:9200`; const createClient = () => new Client({ node: baseURL, + auth: { + username: process.env.OPENSEARCH_USERNAME!, + password: process.env.OPENSEARCH_PASSWORD!, + }, ssl: { rejectUnauthorized: false, }, @@ -532,6 +538,7 @@ export const getTrends = async (limit: number) => { export const getTemplates = async (limit: number) => { const client = createClient(); + const query = { query: { bool: { @@ -546,11 +553,14 @@ export const getTemplates = async (limit: number) => { }, }, }; + + const rawResponse = await client.search({ index: globalIndex, size: limit, body: query, }); + const response = rawResponse.body; const { hits: { hits }, diff --git a/apps/leafcutter/locales/en.json b/apps/leafcutter/app/_locales/en.json similarity index 100% rename from apps/leafcutter/locales/en.json rename to apps/leafcutter/app/_locales/en.json diff --git a/apps/leafcutter/locales/fr.json b/apps/leafcutter/app/_locales/fr.json similarity index 100% rename from apps/leafcutter/locales/fr.json rename to apps/leafcutter/app/_locales/fr.json diff --git a/apps/leafcutter/styles/global.css b/apps/leafcutter/app/_styles/global.css similarity index 100% rename from apps/leafcutter/styles/global.css rename to apps/leafcutter/app/_styles/global.css diff --git a/apps/leafcutter/styles/theme.ts b/apps/leafcutter/app/_styles/theme.ts similarity index 100% rename from apps/leafcutter/styles/theme.ts rename to apps/leafcutter/app/_styles/theme.ts diff --git a/apps/leafcutter/app/api/auth/[...nextauth]/route.ts b/apps/leafcutter/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..2f22a22 --- /dev/null +++ b/apps/leafcutter/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,6 @@ +import NextAuth from "next-auth"; +import { authOptions } from "app/_lib/auth"; + +const handler = NextAuth(authOptions); + +export { handler as GET, handler as POST }; diff --git a/apps/leafcutter/pages/api/proxy/[[...path]].ts b/apps/leafcutter/app/api/proxy/[[...path]].ts similarity index 100% rename from apps/leafcutter/pages/api/proxy/[[...path]].ts rename to apps/leafcutter/app/api/proxy/[[...path]].ts diff --git a/apps/leafcutter/app/api/searches/create/route.ts b/apps/leafcutter/app/api/searches/create/route.ts new file mode 100644 index 0000000..79551ed --- /dev/null +++ b/apps/leafcutter/app/api/searches/create/route.ts @@ -0,0 +1,22 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { getUserMetadata, saveUserMetadata } from "app/_lib/opensearch"; + +export const POST = async (req: NextRequest) => { + const session = await getServerSession(authOptions); + const { user: { email } }: any = session; + const { name, query } = await req.json(); + const result = await getUserMetadata(email); + const { savedSearches } = result; + await saveUserMetadata(email, { + savedSearches: [...savedSearches, { name, query }] + }); + const { savedSearches: updatedSavedSearches } = await getUserMetadata(email); + + return NextResponse.json(updatedSavedSearches); +}; + + + + diff --git a/apps/leafcutter/app/api/searches/delete/route.ts b/apps/leafcutter/app/api/searches/delete/route.ts new file mode 100644 index 0000000..a76c042 --- /dev/null +++ b/apps/leafcutter/app/api/searches/delete/route.ts @@ -0,0 +1,19 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { getUserMetadata, saveUserMetadata } from "app/_lib/opensearch"; + +export const POST = async (req: NextRequest) => { + const session = await getServerSession(authOptions); + const { user: { email } }: any = session; + const { name } = await req.json(); + const { savedSearches } = await getUserMetadata(email); + const updatedSavedSearches = savedSearches.filter((search: any) => search.name !== name); + const result = await saveUserMetadata(email, { savedSearches: updatedSavedSearches }); + + return NextResponse.json({ result }); +}; + + + + diff --git a/apps/leafcutter/app/api/searches/list/route.ts b/apps/leafcutter/app/api/searches/list/route.ts new file mode 100644 index 0000000..86f9dc8 --- /dev/null +++ b/apps/leafcutter/app/api/searches/list/route.ts @@ -0,0 +1,12 @@ +import { NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { getUserMetadata } from "app/_lib/opensearch"; + +export const GET = async () => { + const session = await getServerSession(authOptions); + const { user: { email } }: any = session; + const { savedSearches } = await getUserMetadata(email); + + return NextResponse.json(savedSearches); +}; diff --git a/apps/leafcutter/app/api/trends/recent/_route.ts b/apps/leafcutter/app/api/trends/recent/_route.ts new file mode 100644 index 0000000..95d78a8 --- /dev/null +++ b/apps/leafcutter/app/api/trends/recent/_route.ts @@ -0,0 +1,9 @@ +import { NextResponse } from "next/server"; +import { getTrends } from "app/_lib/opensearch"; + +export const GET = async () => { + const results = await getTrends(5); + + NextResponse.json(results); +}; + diff --git a/apps/leafcutter/pages/api/upload/index.ts b/apps/leafcutter/app/api/upload/index.ts similarity index 78% rename from apps/leafcutter/pages/api/upload/index.ts rename to apps/leafcutter/app/api/upload/index.ts index 73afd1f..4f3223e 100644 --- a/apps/leafcutter/pages/api/upload/index.ts +++ b/apps/leafcutter/app/api/upload/index.ts @@ -1,12 +1,13 @@ /* eslint-disable no-restricted-syntax */ -import { NextApiRequest, NextApiResponse } from "next"; +import { NextRequest, NextResponse } from "next/server"; import { Client } from "@opensearch-project/opensearch"; import { v4 as uuid } from "uuid"; -import taxonomy from "config/taxonomy.json"; -import unRegions from "config/unRegions.json"; +import taxonomy from "app/_config/taxonomy.json"; +import unRegions from "app/_config/unRegions.json"; -const handler = async (req: NextApiRequest, res: NextApiResponse) => { - const { headers: { authorization }, body: { tickets } } = req; +export const POST = async (req: NextRequest) => { + const { tickets } = await req.json(); + const authorization = req.headers.get("authorization"); const baseURL = `https://${process.env.OPENSEARCH_URL}`; const client = new Client({ node: baseURL, @@ -48,7 +49,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { } const results = { succeeded, failed }; - return res.json(results); + + return NextResponse.json(results); }; -export default handler; diff --git a/apps/leafcutter/app/api/visualizations/create/route.ts b/apps/leafcutter/app/api/visualizations/create/route.ts new file mode 100644 index 0000000..2269e53 --- /dev/null +++ b/apps/leafcutter/app/api/visualizations/create/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { createUserVisualization } from "app/_lib/opensearch"; + +export const POST = async (req: NextRequest) => { + const session = await getServerSession(authOptions); + const { user: { email } }: any = session; + const { visualizationID, title, description, query } = await req.json(); + const id = await createUserVisualization({ + email, + visualizationID, + title, + description, + query + }); + + return NextResponse.json({ id }); +}; + diff --git a/apps/leafcutter/app/api/visualizations/delete/route.ts b/apps/leafcutter/app/api/visualizations/delete/route.ts new file mode 100644 index 0000000..2200ed7 --- /dev/null +++ b/apps/leafcutter/app/api/visualizations/delete/route.ts @@ -0,0 +1,15 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { deleteUserVisualization } from "app/_lib/opensearch"; + +export const POST = async (req: NextRequest, res: NextResponse) => { + const session = await getServerSession(authOptions); + const { user: { email } }: any = session; + const { id } = await req.json(); + await deleteUserVisualization(email as string, id); + + return NextResponse.json({ id }); +}; + + diff --git a/apps/leafcutter/app/api/visualizations/query/route.ts b/apps/leafcutter/app/api/visualizations/query/route.ts new file mode 100644 index 0000000..b2018ae --- /dev/null +++ b/apps/leafcutter/app/api/visualizations/query/route.ts @@ -0,0 +1,12 @@ +import { NextRequest, NextResponse } from "next/server"; +import { performQuery } from "app/_lib/opensearch"; + +export const GET = async (req: NextRequest) => { + const searchQuery = req.nextUrl.searchParams.get("searchQuery"); + const rawQuery = await JSON.parse(decodeURI(searchQuery as string)); + const results = await performQuery(rawQuery, 1000); + + return NextResponse.json(results); +}; + + diff --git a/apps/leafcutter/app/api/visualizations/update/route.ts b/apps/leafcutter/app/api/visualizations/update/route.ts new file mode 100644 index 0000000..a9a4f08 --- /dev/null +++ b/apps/leafcutter/app/api/visualizations/update/route.ts @@ -0,0 +1,21 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { updateUserVisualization } from "app/_lib/opensearch"; + +export const POST = async (req: NextRequest) => { + const session = await getServerSession(authOptions); + const { user: { email } }: any = session; + const { id, title, description, query } = await req.json(); + await updateUserVisualization({ + email, + id, + title, + description, + query + }); + + return NextResponse.json({ id }); +}; + + diff --git a/apps/leafcutter/app/layout.tsx b/apps/leafcutter/app/layout.tsx new file mode 100644 index 0000000..102c9b7 --- /dev/null +++ b/apps/leafcutter/app/layout.tsx @@ -0,0 +1,32 @@ +import { ReactNode } from "react"; +import { Metadata } from "next"; +import "app/_styles/global.css"; +import "@fontsource/poppins/400.css"; +import "@fontsource/poppins/700.css"; +import "@fontsource/roboto/400.css"; +import "@fontsource/roboto/700.css"; +import "@fontsource/playfair-display/900.css"; +// import getConfig from "next/config"; +// import { LicenseInfo } from "@mui/x-data-grid-pro"; +import { MultiProvider } from "app/_components/MultiProvider"; + +export const metadata: Metadata = { + title: "Leafcutter", +}; + +type LayoutProps = { + children: ReactNode; +}; + +export default function Layout({ children }: LayoutProps) { + // const { publicRuntimeConfig } = getConfig(); + // LicenseInfo.setLicenseKey(publicRuntimeConfig.muiLicenseKey); + + return ( + + + {children} + + + ); +} diff --git a/apps/leafcutter/app/page.tsx b/apps/leafcutter/app/page.tsx new file mode 100644 index 0000000..95940b0 --- /dev/null +++ b/apps/leafcutter/app/page.tsx @@ -0,0 +1,14 @@ +import { getServerSession } from "next-auth"; +import { authOptions } from "app/_lib/auth"; +import { getUserVisualizations } from "app/_lib/opensearch"; +import { Home } from "app/_components/Home"; + +export default async function Page() { + const session = await getServerSession(authOptions); + const { + user: { email }, + }: any = session; + const visualizations = await getUserVisualizations(email ?? "none", 20); + + return ; +} diff --git a/apps/leafcutter/lib/createEmotionCache.ts b/apps/leafcutter/lib/createEmotionCache.ts deleted file mode 100644 index 79c4a1a..0000000 --- a/apps/leafcutter/lib/createEmotionCache.ts +++ /dev/null @@ -1,5 +0,0 @@ -import createCache from "@emotion/cache"; - -export default function createEmotionCache() { - return createCache({ key: "css" }); -} diff --git a/apps/leafcutter/lib/utils.ts b/apps/leafcutter/lib/utils.ts deleted file mode 100644 index 69aad81..0000000 --- a/apps/leafcutter/lib/utils.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { GetServerSidePropsContext } from "next"; - -export const getEmbedded = (context: GetServerSidePropsContext) => - context.req.headers["x-leafcutter-embedded"] === "true"; diff --git a/apps/leafcutter/middleware.ts b/apps/leafcutter/middleware.ts index 383e669..1840b93 100644 --- a/apps/leafcutter/middleware.ts +++ b/apps/leafcutter/middleware.ts @@ -1,8 +1,57 @@ -import { withAuth } from "next-auth/middleware"; +import { NextResponse } from "next/server"; +import { withAuth, NextRequestWithAuth } from "next-auth/middleware"; import getConfig from "next/config"; +const rewriteURL = (request: NextRequestWithAuth, originBaseURL: string, destinationBaseURL: string, headers: any = {}) => { + if (request.nextUrl.protocol.startsWith('ws')) { + return NextResponse.next(); + } + + if (request.nextUrl.pathname.includes('/_next/static/development/')) { + return NextResponse.next(); + } + + const destinationURL = request.url.replace(originBaseURL, destinationBaseURL); + console.log(`Rewriting ${request.url} to ${destinationURL}`); + + const requestHeaders = new Headers(request.headers); + for (const [key, value] of Object.entries(headers)) { + // @ts-ignore + requestHeaders.set(key, value); + } + requestHeaders.delete('connection'); + + // console.log({ finalHeaders: requestHeaders }); + + return NextResponse.rewrite(new URL(destinationURL), { request: { headers: requestHeaders } }); +}; + +const checkRewrites = async (request: NextRequestWithAuth) => { + console.log({ currentURL: request.nextUrl.href }); + + const leafcutterBaseURL = process.env.LEAFCUTTER_URL ?? "http://localhost:3000"; + const opensearchDashboardsURL = process.env.OPENSEARCH_URL ?? "http://localhost:5602"; + + if (request.nextUrl.pathname.startsWith('/proxy/opensearch')) { + console.log('proxying to zammad'); + const { token } = request.nextauth; + const auth = `${token?.email?.toLowerCase()}:${process.env.OPENSEARCH_USER_PASSWORD}`; + const buff = Buffer.from(auth); + const base64data = buff.toString("base64"); + const headers = { + 'X-Proxy-User': token?.email?.toLowerCase(), + "X-Proxy-Roles": "leafcutter_user", + "Authorization": `Basic ${base64data}` + }; + + console.log({ headers }); + + return rewriteURL(request, `${leafcutterBaseURL}/proxy/opensearch`, opensearchDashboardsURL, headers); + } +}; + export default withAuth( - () => { }, + checkRewrites, { pages: { signIn: `/login`, @@ -14,32 +63,21 @@ export default withAuth( headers, } = req; - return true; - /* - const { - publicRuntimeConfig: { embedded }, - } = getConfig(); - - if (embedded) { - return true; - } - - // check login page - const parsedURL = new URL(url); - if (parsedURL.pathname.startsWith('/login')) { - return true; - } - - // check session auth - const authorizedDomains = ["redaranj.com", "digiresilience.org"]; - const userDomain = token?.email?.toLowerCase().split("@").pop() ?? "unauthorized.net"; - - if (authorizedDomains.includes(userDomain)) { - return true; - } - - return false; - */ + // check login page + const parsedURL = new URL(url); + if (parsedURL.pathname.startsWith('/login')) { + return true; + } + + // check session auth + const authorizedDomains = ["redaranj.com", "digiresilience.org"]; + const userDomain = token?.email?.toLowerCase().split("@").pop() ?? "unauthorized.net"; + + if (authorizedDomains.includes(userDomain)) { + return true; + } + + return false; }, } } diff --git a/apps/leafcutter/next.config.js b/apps/leafcutter/next.config.js index 1d649c7..128e197 100644 --- a/apps/leafcutter/next.config.js +++ b/apps/leafcutter/next.config.js @@ -1,14 +1,22 @@ +const ContentSecurityPolicy = ` + default-src 'self'; + script-src 'self'; + child-src example.com; + style-src 'self' example.com; + font-src 'self'; +`; + module.exports = { publicRuntimeConfig: { embedded: true - }, + },/* basePath: "/proxy/leafcutter", assetPrefix: "/proxy/leafcutter", i18n: { locales: ["en", "fr"], defaultLocale: "en", }, - +*/ /* rewrites: async () => ({ fallback: [ { @@ -17,4 +25,31 @@ module.exports = { }, ], }) */ + async headers() { + return [ + { + source: '/:path*', + headers: [ + /* + { + key: 'Content-Security-Policy', + value: ContentSecurityPolicy.replace(/\s{2,}/g, ' ').trim() + }, + */ + { + key: 'Strict-Transport-Security', + value: 'max-age=63072000; includeSubDomains; preload' + }, + { + key: 'X-XSS-Protection', + value: '1; mode=block' + }, + { + key: 'X-Frame-Options', + value: 'SAMEORIGIN' + } + ], + }, + ] + } }; diff --git a/apps/leafcutter/package.json b/apps/leafcutter/package.json index 88189c1..14dc267 100644 --- a/apps/leafcutter/package.json +++ b/apps/leafcutter/package.json @@ -3,7 +3,7 @@ "version": "0.2.0", "scripts": { "dev": "next dev -p 3001", - "login": "aws sso login --profile cdr-leafcutter-dashboard-production", + "login": "aws sso login --sso-session cdr", "kubeconfig": "aws eks update-kubeconfig --name cdr-leafcutter-dashboard-cluster --profile cdr-leafcutter-dashboard-production", "fwd:opensearch": "kubectl port-forward opensearch-cluster-master-0 9200:9200 --namespace leafcutter", "fwd:dashboards": "kubectl port-forward opensearch-dashboards-1-59854cdb9b-vgmtf 5602:5601 --namespace leafcutter", @@ -17,19 +17,19 @@ "@emotion/react": "^11.11.1", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.11.0", - "@fontsource/playfair-display": "^5.0.3", - "@fontsource/poppins": "^5.0.3", - "@fontsource/roboto": "^5.0.3", + "@fontsource/playfair-display": "^5.0.5", + "@fontsource/poppins": "^5.0.5", + "@fontsource/roboto": "^5.0.5", "@mui/icons-material": "^5", - "@mui/lab": "^5.0.0-alpha.134", + "@mui/lab": "^5.0.0-alpha.136", "@mui/material": "^5", - "@mui/x-data-grid-pro": "^6.8.0", - "@mui/x-date-pickers-pro": "^6.8.0", - "@opensearch-project/opensearch": "^2.0.0", + "@mui/x-data-grid-pro": "^6.10.0", + "@mui/x-date-pickers-pro": "^6.10.0", + "@opensearch-project/opensearch": "^2.3.0", "date-fns": "^2.30.0", "http-proxy-middleware": "^2.0.6", "material-ui-popup-state": "^5.0.9", - "next": "13.4.6", + "next": "13.4.10", "next-auth": "^4.22.1", "next-http-proxy-middleware": "^1.2.5", "nodemailer": "^6.9.3", @@ -40,24 +40,25 @@ "react-iframe": "^1.8.5", "react-markdown": "^8.0.7", "react-polyglot": "^0.7.2", - "sharp": "^0.32.1", - "swr": "^2.1.5", + "sharp": "^0.32.3", + "swr": "^2.2.0", + "tss-react": "^4.8.8", "uuid": "^9.0.0" }, "devDependencies": { - "@babel/core": "^7.22.5", - "@types/react": "18.2.13", - "@types/node": "^20.3.1", + "@babel/core": "^7.22.9", + "@types/node": "^20.4.2", + "@types/react": "18.2.15", "@types/uuid": "^9.0.2", - "babel-loader": "^9.1.2", - "eslint": "^8.43.0", + "babel-loader": "^9.1.3", + "eslint": "^8.45.0", "eslint-config-airbnb": "^19.0.4", - "eslint-config-next": "^13.4.6", + "eslint-config-next": "^13.4.10", "eslint-config-prettier": "^8.8.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.32.2", - "typescript": "5.1.3" + "typescript": "5.1.6" } } diff --git a/apps/leafcutter/pages/_app.tsx b/apps/leafcutter/pages/_app.tsx deleted file mode 100644 index 0071367..0000000 --- a/apps/leafcutter/pages/_app.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* eslint-disable react/jsx-props-no-spreading */ -import { AppProps } from "next/app"; -import { SessionProvider } from "next-auth/react"; -import { useRouter } from "next/router"; -import Head from "next/head"; -import { CssBaseline } from "@mui/material"; -import { CacheProvider, EmotionCache } from "@emotion/react"; -import { CookiesProvider } from "react-cookie"; -import { I18n } from "react-polyglot"; -import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFns"; -import { LocalizationProvider } from "@mui/x-date-pickers-pro"; -import { AppProvider } from "components/AppProvider"; -import createEmotionCache from "lib/createEmotionCache"; -import Favicon from "images/favicon.ico"; -import en from "locales/en.json"; -import fr from "locales/fr.json"; -import "@fontsource/poppins/400.css"; -import "@fontsource/poppins/700.css"; -import "@fontsource/roboto/400.css"; -import "@fontsource/roboto/700.css"; -import "@fontsource/playfair-display/900.css"; -import "styles/global.css"; -import { LicenseInfo } from "@mui/x-data-grid-pro"; - -LicenseInfo.setLicenseKey(process.env.MUI_LICENSE_KEY ?? ""); - -const clientSideEmotionCache: any = createEmotionCache(); - -const messages: any = { en, fr }; - -interface LeafcutterWebProps extends AppProps { - // eslint-disable-next-line react/require-default-props - emotionCache?: EmotionCache; -} - -const LeafcutterWeb = (props: LeafcutterWebProps) => { - const { locale = "en" } = useRouter(); - const { Component, emotionCache = clientSideEmotionCache, pageProps } = props; - - return ( - <> - - - - - - - - - - - - - - - - - - - ); -}; - -export default LeafcutterWeb; diff --git a/apps/leafcutter/pages/_document.tsx b/apps/leafcutter/pages/_document.tsx deleted file mode 100644 index ec2ca90..0000000 --- a/apps/leafcutter/pages/_document.tsx +++ /dev/null @@ -1,50 +0,0 @@ -// eslint-disable-next-line no-use-before-define -import * as React from "react"; -import Document, { Html, Head, Main, NextScript } from "next/document"; -import createEmotionServer from "@emotion/server/create-instance"; -import createEmotionCache from "lib/createEmotionCache"; - -export default class LeafcutterDocument extends Document { - render() { - return ( - - - -
- - - - ); - } -} - -LeafcutterDocument.getInitialProps = async (ctx): Promise => { - const originalRenderPage = ctx.renderPage; - const cache = createEmotionCache(); - const { extractCriticalToChunks } = createEmotionServer(cache as any); - - ctx.renderPage = () => - originalRenderPage({ - enhanceApp: (App: any) => (props: any) => - , - }); - - const initialProps = await Document.getInitialProps(ctx); - const emotionStyles = extractCriticalToChunks(initialProps.html); - const emotionStyleTags = emotionStyles.styles.map((style) => ( -