From 002274ee0ad1285f44b2e09526de9785a54bf72f Mon Sep 17 00:00:00 2001 From: Ionut Achim Date: Thu, 15 Feb 2024 10:40:42 +0200 Subject: [PATCH] chore: remove newsfeed from start-page chore: remove cloud sync --- electron/app/ipc/ipcListeners.ts | 1 - electron/app/services/cloud/authenticator.ts | 25 -- electron/app/services/cloud/client-config.ts | 18 -- electron/app/services/cloud/ipc.ts | 11 - electron/app/services/cloud/login.ts | 28 --- electron/app/services/cloud/policy.ts | 23 -- electron/app/services/cloud/project.ts | 26 --- electron/app/services/cloud/synchronizer.ts | 23 -- electron/app/services/cloud/user.ts | 45 ---- package-lock.json | 93 +------- package.json | 1 - src/assets/CloudIcon.svg | 14 -- src/assets/CloudIconWhite.svg | 4 - src/assets/CloudManaged.png | Bin 7212 -> 0 bytes src/assets/CloudSync.svg | 101 -------- src/assets/CloudSynced.png | Bin 4635 -> 0 bytes src/assets/CloudUnsynced.png | Bin 4763 -> 0 bytes .../PageHeader/CloudSync/CloudSync.tsx | 217 ------------------ .../organisms/PageHeader/CloudSync/index.tsx | 1 - .../organisms/PageHeader/PageHeader.tsx | 2 - .../CloudConnect/CloudConnect.styled.tsx | 26 --- .../CloudConnect/CloudConnect.tsx | 85 ------- .../SettingsPane/CloudConnect/index.tsx | 1 - .../organisms/SettingsPane/SettingsPane.tsx | 13 -- .../organisms/StartPage/StartPage.styled.tsx | 125 +--------- .../organisms/StartPage/StartPage.tsx | 61 +---- .../organisms/StartPage/useNewsFeed.ts | 37 --- .../ValidationCustom/ValidationCustom.tsx | 11 +- .../ValidationCustom/useValidationTable.tsx | 11 +- .../ValidationOverview/ValidationCard.tsx | 14 +- .../ValidationCardPolicy.tsx | 65 ------ .../ValidationCardUpNext.tsx | 7 +- .../ValidationOverview/ValidationOverview.tsx | 7 +- src/hooks/menuItemsHooks/useHelpMenuItems.tsx | 4 - src/redux/cloud/ipc.ts | 12 - src/redux/initialState.ts | 4 - src/redux/reducers/cloud.ts | 24 -- src/redux/store.ts | 2 - src/redux/validation/validation.hooks.ts | 148 ------------ src/redux/validation/validation.listeners.tsx | 4 +- src/redux/validation/validation.selectors.ts | 8 +- src/redux/validation/validation.slice.ts | 7 - src/redux/validation/validation.thunks.ts | 9 +- src/shared/models/cloud.ts | 26 --- src/shared/models/rootState.ts | 2 - src/shared/models/telemetry.ts | 3 - src/shared/models/validation.ts | 2 - src/shared/utils/shell.ts | 5 - 48 files changed, 25 insertions(+), 1331 deletions(-) delete mode 100644 electron/app/services/cloud/authenticator.ts delete mode 100644 electron/app/services/cloud/client-config.ts delete mode 100644 electron/app/services/cloud/ipc.ts delete mode 100644 electron/app/services/cloud/login.ts delete mode 100644 electron/app/services/cloud/policy.ts delete mode 100644 electron/app/services/cloud/project.ts delete mode 100644 electron/app/services/cloud/synchronizer.ts delete mode 100644 electron/app/services/cloud/user.ts delete mode 100644 src/assets/CloudIcon.svg delete mode 100644 src/assets/CloudIconWhite.svg delete mode 100644 src/assets/CloudManaged.png delete mode 100644 src/assets/CloudSync.svg delete mode 100644 src/assets/CloudSynced.png delete mode 100644 src/assets/CloudUnsynced.png delete mode 100644 src/components/organisms/PageHeader/CloudSync/CloudSync.tsx delete mode 100644 src/components/organisms/PageHeader/CloudSync/index.tsx delete mode 100644 src/components/organisms/SettingsPane/CloudConnect/CloudConnect.styled.tsx delete mode 100644 src/components/organisms/SettingsPane/CloudConnect/CloudConnect.tsx delete mode 100644 src/components/organisms/SettingsPane/CloudConnect/index.tsx delete mode 100644 src/components/organisms/StartPage/useNewsFeed.ts delete mode 100644 src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardPolicy.tsx delete mode 100644 src/redux/cloud/ipc.ts delete mode 100644 src/redux/reducers/cloud.ts delete mode 100644 src/redux/validation/validation.hooks.ts delete mode 100644 src/shared/models/cloud.ts diff --git a/electron/app/ipc/ipcListeners.ts b/electron/app/ipc/ipcListeners.ts index b783325518..43cecb2dab 100644 --- a/electron/app/ipc/ipcListeners.ts +++ b/electron/app/ipc/ipcListeners.ts @@ -45,7 +45,6 @@ import { selectFileDialog, } from '../commands'; import {ProjectNameChange, StorePropagation} from '../models'; -import '../services/cloud/ipc'; import '../services/cluster/ipc'; import {downloadPlugin, updatePlugin} from '../services/pluginService'; import { diff --git a/electron/app/services/cloud/authenticator.ts b/electron/app/services/cloud/authenticator.ts deleted file mode 100644 index ff9a1ca0b7..0000000000 --- a/electron/app/services/cloud/authenticator.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {app} from 'electron'; - -import {join} from 'path'; - -import {Authenticator, StorageHandlerAuth, createMonokleAuthenticatorFromOrigin} from '@monokle/synchronizer'; -import {getClientConfig} from './client-config'; - -export const AUTH_CLIENT_ID = 'mc-cli'; - -let authenticator: Authenticator | undefined; - -const initAuthenticator = async (cloudStorageDir: string) => { - const newAuthenticator = await createMonokleAuthenticatorFromOrigin(AUTH_CLIENT_ID, getClientConfig(), undefined, new StorageHandlerAuth(cloudStorageDir)); - authenticator = newAuthenticator; - return newAuthenticator; -}; - -export const getAuthenticator = async () => { - const userDataDir = app.getPath('userData'); - const cloudStorageDir = join(userDataDir, 'cloud'); - if (!authenticator) { - await initAuthenticator(cloudStorageDir); - } - return authenticator; -}; diff --git a/electron/app/services/cloud/client-config.ts b/electron/app/services/cloud/client-config.ts deleted file mode 100644 index 73a7b06cb1..0000000000 --- a/electron/app/services/cloud/client-config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {type, release} from 'os'; -import {machineIdSync} from 'node-machine-id'; -import {app} from 'electron'; -import electronStore from '@shared/utils/electronStore'; - -const CLIENT_NAME = 'Monokle Desktop'; - -export function getClientConfig() { - const isTrackingDisabled = Boolean(electronStore.get('appConfig.disableEventTracking')); - const additionalData = isTrackingDisabled ? undefined : { machineId: machineIdSync() }; - - return { - name: CLIENT_NAME, - version: app.getVersion(), - os: `${type()} ${release()}`, - additionalData, - }; -} diff --git a/electron/app/services/cloud/ipc.ts b/electron/app/services/cloud/ipc.ts deleted file mode 100644 index 9bcd315453..0000000000 --- a/electron/app/services/cloud/ipc.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {handleIpc} from '../../utils/ipc'; -import {cloudLogin, cloudLogout} from './login'; -import {getPolicy} from './policy'; -import {getInfo} from './project'; -import {getSerializedUser} from './user'; - -handleIpc('cloud:login', cloudLogin); -handleIpc('cloud:logout', cloudLogout); -handleIpc('cloud:getUser', getSerializedUser); -handleIpc('cloud:getPolicy', getPolicy); -handleIpc('cloud:getInfo', getInfo); diff --git a/electron/app/services/cloud/login.ts b/electron/app/services/cloud/login.ts deleted file mode 100644 index 8748c9510e..0000000000 --- a/electron/app/services/cloud/login.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {shell} from 'electron'; - -import {CloudLoginResponse} from '@shared/models/cloud'; - -import {getAuthenticator} from './authenticator'; -import {serializeUser} from './user'; - -export const cloudLogin = async (): Promise => { - const authenticator = await getAuthenticator(); - if (!authenticator) { - throw new Error('Something went wrong with the authenticator'); - } - const loginResponse = await authenticator.login('device code'); - if (!loginResponse.handle) { - throw new Error('Something went wrong with the login response'); - } - shell.openExternal(loginResponse.handle.verification_uri_complete); - const user = await loginResponse.onDone; - if (!user) { - throw new Error('Login to Cloud has failed. Please try again later.'); - } - return {user: serializeUser(user)}; -}; - -export const cloudLogout = async (): Promise => { - const authenticator = await getAuthenticator(); - await authenticator?.logout(); -}; diff --git a/electron/app/services/cloud/policy.ts b/electron/app/services/cloud/policy.ts deleted file mode 100644 index 2687b75ef9..0000000000 --- a/electron/app/services/cloud/policy.ts +++ /dev/null @@ -1,23 +0,0 @@ -import log from 'loglevel'; - -import {getSynchronizer} from './synchronizer'; -import {getUser} from './user'; - -export const getPolicy = async (repoPath: string) => { - const synchronizer = await getSynchronizer(); - const user = await getUser(); - if (!user?.tokenInfo || !synchronizer) { - return null; - } - - try { - const policy = await synchronizer.getPolicy(repoPath, true, user.tokenInfo); - return policy; - } catch (e: any) { - if (e instanceof Error) { - log.warn(e.message); - } - log.warn('Failed to synchronize policy'); - } - return null; -}; diff --git a/electron/app/services/cloud/project.ts b/electron/app/services/cloud/project.ts deleted file mode 100644 index ad3170617c..0000000000 --- a/electron/app/services/cloud/project.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {CloudPolicyInfo, CloudProjectInfo} from '@shared/models/cloud'; - -import {getSynchronizer} from './synchronizer'; -import {getUser} from './user'; - -export const getInfo = async ( - repoPath: string -): Promise<{projectInfo: CloudProjectInfo; policyInfo: CloudPolicyInfo} | null> => { - const synchronizer = await getSynchronizer(); - const user = await getUser(); - if (!user?.tokenInfo || !synchronizer) { - return null; - } - - try { - const project = await synchronizer?.getProjectInfo(repoPath, user.tokenInfo, true); - return project - ? { - projectInfo: {...project, link: synchronizer.generateDeepLinkProject(project.slug)}, - policyInfo: {link: synchronizer.generateDeepLinkProjectPolicy(project.slug)}, - } - : null; - } catch { - return null; - } -}; diff --git a/electron/app/services/cloud/synchronizer.ts b/electron/app/services/cloud/synchronizer.ts deleted file mode 100644 index af6a85441a..0000000000 --- a/electron/app/services/cloud/synchronizer.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {app} from 'electron'; - -import {join} from 'path'; - -import {StorageHandlerPolicy, Synchronizer, createMonokleSynchronizerFromOrigin} from '@monokle/synchronizer'; -import {getClientConfig} from './client-config'; - -let synchronizer: Synchronizer | undefined; - -const initSynchronizer = async (cloudStorageDir: string) => { - const newSynchronizer = await createMonokleSynchronizerFromOrigin(getClientConfig(), undefined, new StorageHandlerPolicy(cloudStorageDir)); - synchronizer = newSynchronizer; - return newSynchronizer; -}; - -export const getSynchronizer = async () => { - const userDataDir = app.getPath('userData'); - const cloudStorageDir = join(userDataDir, 'cloud'); - if (!synchronizer) { - await initSynchronizer(cloudStorageDir); - } - return synchronizer; -}; diff --git a/electron/app/services/cloud/user.ts b/electron/app/services/cloud/user.ts deleted file mode 100644 index 528118b292..0000000000 --- a/electron/app/services/cloud/user.ts +++ /dev/null @@ -1,45 +0,0 @@ -import log from 'loglevel'; - -import {User} from '@monokle/synchronizer'; -import {CloudUser} from '@shared/models/cloud'; - -import {getAuthenticator} from './authenticator'; - -export const getUser = async (): Promise => { - const authenticator = await getAuthenticator(); - if (!authenticator) { - return undefined; - } - try { - const user = await authenticator.getUser(); - if (!user.isAuthenticated) { - return undefined; - } - return user; - } catch (e: any) { - log.warn(e.message); - return undefined; - } -}; - -export const getSerializedUser = async (): Promise => { - const user = await getUser(); - if (!user) { - return undefined; - } - try { - const serializedUser = serializeUser(user); - return serializedUser; - } catch { - return undefined; - } -}; - -export const serializeUser = (user: User): CloudUser => { - if (!user.email) { - throw new Error('User not found'); - } - return { - email: user.email, - }; -}; diff --git a/package-lock.json b/package-lock.json index 9a56a24a0d..70c6459cd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@dnd-kit/sortable": "7.0.2", "@kubernetes/client-node": "0.19.0", "@monokle/components": "1.7.0", - "@monokle/synchronizer": "^0.13.0", "@monokle/validation": "0.31.5", "@open-policy-agent/opa-wasm": "1.8.0", "@reduxjs/toolkit": "1.9.5", @@ -5628,64 +5627,6 @@ "use-debounced-effect": "2.0.1" } }, - "node_modules/@monokle/synchronizer": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@monokle/synchronizer/-/synchronizer-0.13.0.tgz", - "integrity": "sha512-rTfzoDC4A3mLkxYnpUeYHzLK2cIjugBarxJ3+Dyq8MgSbXcPmW5GaxbqTJRZX2KEPlj2ozJHRmXAsoxcOpwQVA==", - "dependencies": { - "@monokle/types": "*", - "env-paths": "^2.2.1", - "git-url-parse": "^13.1.0", - "mkdirp": "^3.0.1", - "node-fetch": "^2.6.13", - "normalize-url": "^4.5.1", - "openid-client": "^5.4.3", - "simple-git": "^3.19.1", - "slugify": "^1.6.6", - "yaml": "^2.3.1" - } - }, - "node_modules/@monokle/synchronizer/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/@monokle/synchronizer/node_modules/simple-git": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.21.0.tgz", - "integrity": "sha512-oTzw9248AF5bDTMk9MrxsRzEzivMlY+DWH0yWS4VYpMhNLhDWnN06pCtaUyPnqv/FpsdeNmRqmZugMABHRPdDA==", - "dependencies": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/steveukx/git-js?sponsor=1" - } - }, - "node_modules/@monokle/synchronizer/node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", - "engines": { - "node": ">= 14" - } - }, "node_modules/@monokle/types": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@monokle/types/-/types-0.3.2.tgz", @@ -22119,6 +22060,7 @@ "version": "4.15.4", "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", + "optional": true, "funding": { "url": "https://github.com/sponsors/panva" } @@ -24630,20 +24572,6 @@ "node": ">=8" } }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -25002,14 +24930,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -25295,6 +25215,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "optional": true, "engines": { "node": ">= 6" } @@ -25441,6 +25362,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", + "optional": true, "engines": { "node": "^10.13.0 || >=12.0.0" } @@ -25554,6 +25476,7 @@ "version": "5.6.1", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.1.tgz", "integrity": "sha512-PtrWsY+dXg6y8mtMPyL/namZSYVz8pjXz3yJiBNZsEdCnu9miHLB4ELVC85WvneMKo2Rg62Ay7NkuCpM0bgiLQ==", + "optional": true, "dependencies": { "jose": "^4.15.1", "lru-cache": "^6.0.0", @@ -30637,14 +30560,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/slugify": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", - "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", diff --git a/package.json b/package.json index 50d2cc196f..1ed4011d62 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,6 @@ "@dnd-kit/sortable": "7.0.2", "@kubernetes/client-node": "0.19.0", "@monokle/components": "1.7.0", - "@monokle/synchronizer": "^0.13.0", "@monokle/validation": "0.31.5", "@open-policy-agent/opa-wasm": "1.8.0", "@reduxjs/toolkit": "1.9.5", diff --git a/src/assets/CloudIcon.svg b/src/assets/CloudIcon.svg deleted file mode 100644 index 254e144f15..0000000000 --- a/src/assets/CloudIcon.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/src/assets/CloudIconWhite.svg b/src/assets/CloudIconWhite.svg deleted file mode 100644 index 761e49df82..0000000000 --- a/src/assets/CloudIconWhite.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/assets/CloudManaged.png b/src/assets/CloudManaged.png deleted file mode 100644 index 88533624efac5c5f5c147893de69908bfb0e594b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7212 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/CloudSynced.png b/src/assets/CloudSynced.png deleted file mode 100644 index 677b78efc2f7f90a91ef137d8d0cf36941891690..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4635 zcmZWtXIK+!uqH7m0%GVO#Q>pqPudB0fS)LIj9F5rHl!1iL{nA|g;yIMEe?ry`hM z4uI$q!2>Sv9N-`3YR;uUu`U58QZi71!wKHN!4ru@d);%#B>vJcB?w1RhNc)(9c>v0 zcQ+wBM|XRqkguD^g@j1XSB4O}Au)CkU$^^cFBxAL`(F$hLVU3-%ntdBf^mhho9gI6 zRNOt05D6g>ArW?YQV0Yh=jrGqgHXNmkDPD?W50*Nc*qC~`}p_>`G^a-dpZk?N=r)% zi--w}i3t)If?j@TjGeC_+Kc1wB>$U773t;RiSodp+|iJWymt2P-WV7=`$eHY$KUsf z^hNz!3GMYyTZ9IMFA!l-Arav}xd~Fai&YstlrQqWnJUVSFdjk;c}Xd`zv%xD__yGH zgr@%r#l*$`tNai0f0agFNKX}aH$p{>{J$IXkNCgfKSDX-i^l&mh`*=&*D7Jm@}zRY zf3{4XG_1;gmx$(Y-6L>XGKcgT6k9=5agwfWdeQ zs+|U))~comFC|u@m(hz}g^!M)6*Zfe?>$>BRUSTy};OpxvrOybng;T=f0vS2U&e|mAh6FXs zT*sSVX@AobudD`Ci)}M7>~R$@M$BRvQWwp~&xzouI5>W7tyC7xaA-^UHu=yv+R(+M z+!A$AMs_4mqPea7kpj@OzByIr5P_mdpvhsR*Djr&cU}6wIdm13K+&P(N)>5B_pNfx<&yZ@ONErEjxdEdd&w5}ZG%anF z`j9jglxp#HmTR-uAl+x-jgbWT(6~rkY__B`>!aCsM?F35SC;czaE?00{`Q7D`my#< zcw`Q3RJCNXAFF$I)~!a~Pml1sw8INv5zXS>Vx9)v?F0LiC8>PL*@rjdvjckMc9w23 znt##S#<`SR`E?ndT<)F!lp?)1u(zB@_BJhkHmF;`^0>+fQAkf`T(6cyqs4o?+S?m5 zF)>l$Zzl`Pf(3kadB5~ke9l8dCPgYTa68yG?({Hre5F+j-f)GQ_B4{3+w%GwcG)24 zZMxCSazT(4hQxPu#-#7?>!fvf*39HCw~*+otdr3C)l4rz-S2!qHIjBk5Q|Cy`&Z%4 z%nZ}pEkCi16QP{Flakq0*VfE$^Jc0ErF?yf5`#!VFbh#pS5Vb8NM=v-9?@6CxRt&B z20?s;t`;L#bvfo~KkO8?cb;ucPWIIUR{A6!ic%3EhQZfp5f7Z|_Fs>m%u&flsy@zw zvR=zj02=N{hYMT#Z9tA5@S? z7DVH5z6y9@2?;;SQbq7)!bS1bJ9!b`7umY@Kc(6HT78x6lw=hnA0uwvfZ;WIG(0?< z*gqH*hYjkj8R23pR*kZYd|=RkGxaa@PCYq?C4YKaFw)#;pGneV+E`Be=43{QIqKXx zqf&gHyaZy3%KyM3?j3H;5X6}E=rtS9G5=!06ce`{va6IcHrjHVADH!wXvQ#f3!U(+ zS<|&Ujkh2?hB?0_>S%EC;O;b?G!I3FYatgZy<&>RIelPRCDxiJ}>Qd%tW*>4*@!!)5FV;6+IL$qP%LL6CTshGRU4fwX9^F-VR6cRsw7zn5 zq)^oK>0uoO2zSss##Bxm_ITidGCg0kxADSk{!x_@B!)(*VmPldQc;(A6=!U@^-cMi ze3YeE1FrUoAjfNZWB(*&^47RgO8#{wC;XDh{U4;{CKKc2On!mHL<_p#41S= zf}^vhNS_G#;JReDT!al|5ue=Xv^dzX%7Qx8nwXiQ^;&ouWfoLt|5e_&o$D7iAq75G zVs6mY@OglAcx>RVD3_A8Q|ovyM=GW>H7gFn`|@m~s=xQ8xHEK4aAp`8ReCi;hkTJa zxB=}?A(>?Ged+j}%Ir7w*!rM~E`jshE;qZS=B*CO1b2GpF_LJ2*rZf{1g!tyeWiiR zoRxd0egm6}EGS{`o*D|)ALKKZ*)WgSVFMkk`1~BS5v;7inhG3XkY)<1k?Oyli01!-$O>|@1mHP0(ro!lqIs@A(C$j#S zY^-TccvrS;TeuLP9rJJKt68Fn$i%oy)T;4+ZOoaK_-VsPj0808D?( z^@#cY*+b@*v+KeBp9aKq&usf4AJXtc7O-$3!SFnhRi-w6-i>nWc;!|Lbeh}8s33{B z>xh@bHEKmgMS0fLes5hh_;_rYZK>_vFqv&%wtY!1a111~3Zpc`x{qS%C>@4Q-I?vr z3%kf+raoD8_#4i4jxI*>J;$u>^|^V@NQF;)$cRV!X#5*WIun&1im@iUp~aSUjkPOR z!C@)q0ZJ<)1tDJ|cGd+>pH|g9FD&chYKQ%9k)w{N8_EfrGplzi?V_N_p7*O>CGRe8 zzHRHTAhS#pDkzR&3j&_t2SvU19S_hitcDiehT>sAyB_i0pH-$ybtiSF65wP(PCb2m zl(Cd`Ue1j|gqT$(D>GGNxW{nNgNQ`u{8_WNV||DB``A!B-%YC1$$q~{KQ7&Kx1=}L zzN;!Z7T8}z{jg-Y;Mcr`*Js~~|s%p7+K5T1i z-&~?uPkFBynj-r?AN5DiFx4u}gO?gA}0gJiHi;S#~z+ z7%$cQMX8r{>pRor>lLOSzFc(>zT=Yhck>pBZNGt*px;MDwK+kSJwfHr*k4b+OH)w` zj7@!}&nnaxGM*_kNVAdgZ4vK!SG!^d5_OlogM6;jcA{a?Z>bRGy-5DC&|Br8MHRlL z{=qBGB=Y?gf1$cfy-$<1Abj*2N?SSUGE!^rA(C;%z4go2(@9A7jWt2V^OBMaFCN!K zTElNVp#l-(jT?f)plZS|$N@jrb!68+W?ONV+)R{R`I*aZ1_5idAbH7ntdY2GVwXo(e$;B6XVMv4~^@eGIUu-bRf(|3TMG~T?OQ;Yq` zrACQRpLn%lTa|O#dbNjwwrPiB8*?X#hJ*BWL~!JzbpKibq`$w+XZ(%tK<&(|K_-s_ zSK9a2BJq{f6`px}(fQJ}+{Cc5N)CQ!N80QoYW)foy`dP5kF%Pdn*Qu?&GqhJvrjQ# zRv-hZpD{5Dc)T+GqY$G*d@~%tYa!g45mCu%ApcWcwjrG6Vd(a}&HcuSQ++h_+-YG~ zUO1S(EmP0ma#KJh5z09T)n)0!W#5f=qulx37ryCrqnz@wV$zW3nujWf9>Suo>W-VX zzG#0zfNAeY4YyIBy=O?lem&#wAM3fB-PRSeq)MX`Y^NDHb#}IG5k|&uBo)YmitiOJE(YcbhH=qLswO6g#B4*Wqb%j*3jewKHWF;=i5~$+k+fxij?=L zforyNT=NGtQ6YjrO@u|ktxWa-E>KE=8_?ROjAWdBCpeWgtxmILr0(L!3S3QBwOrZu G$^QU>rgY8# diff --git a/src/assets/CloudUnsynced.png b/src/assets/CloudUnsynced.png deleted file mode 100644 index c0b79f281932794f36067819f07dab353e162028..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4763 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 et$Ia&q; - -const CloudSync = () => { - const {connect, cloudUser, isConnecting, isInitializing} = useCloudUser(); - const {cloudPolicy, projectInfo, policyInfo} = useCloudPolicy(); - - const dropdownRender = useCallback(() => { - if (isInitializing) { - return ( - - - Initializing... - - ); - } - - if (cloudUser) { - return ( - - - - - Connected to Monokle Cloud - - - - - <GreenCircle /> E-mail - - {cloudUser.email} - - - {projectInfo?.name ? <GreenCircle /> : <RedCircle />} Cloud project - - {projectInfo?.name ? ( - <> - openUrlInExternalBrowser(projectInfo.link)}>{projectInfo.name} - - - ) : ( - <> - Not found - - - )} - - - - {cloudPolicy ? <GreenCircle /> : <RedCircle />} Policy - - {cloudPolicy ? ( - <> - openUrlInExternalBrowser(policyInfo?.link)}>View project policy - - - ) : ( - <> - Not found - - - )} - - - - ); - } - return ( - - - - - Not Connected to Monokle Cloud - - - - - ); - }, [connect, cloudUser, isConnecting, cloudPolicy, isInitializing, projectInfo, policyInfo]); - - return ( - - document.getElementById('monokleCloudSync')!} - > -
- - - {projectInfo?.name} - -
-
-
- - ); -}; - -export default CloudSync; - -const Info = (props: {description: string}) => { - const {description} = props; - return ( - - - - ); -}; - -const Container = styled.div<{$hasText: boolean}>` - display: flex; - align-items: center; - border-radius: 4px; - padding: 0 0.5rem; - background: ${Colors.grey3b}; - border: none; - min-width: fit-content; -`; - -const Icon = styled.img` - cursor: pointer; - height: 20px; - width: 20px; - margin-right: 4px; -`; - -const Image = styled.img` - margin-bottom: 8px; - margin-left: -4px; -`; - -const DropdownContent = styled.div` - padding: 28px; - margin-top: 10px; - background-color: ${Colors.grey2}; -`; - -const GreenSpan = styled.span` - color: ${Colors.polarGreen}; -`; - -const RedSpan = styled.span` - color: ${Colors.red7}; -`; - -const GraySpan = styled.span` - color: ${Colors.grey7}; -`; - -const GreenCircle = styled(CheckCircleFilled)` - font-size: 12px; - color: ${Colors.polarGreen}; - margin-right: 4px; -`; - -const RedCircle = styled(CloseCircleFilled)` - font-size: 12px; - color: ${Colors.red7}; - margin-right: 4px; -`; - -const Item = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 8px; -`; - -const Title = styled.div` - width: 120px; - margin-right: 8px; - color: ${Colors.grey7}; -`; - -const Value = styled.div` - flex: 1; - text-align: left; - margin-left: 8px; -`; - -const InfoIcon = styled(InfoCircleFilled)` - color: ${Colors.grey6}; - margin-left: 8px; - cursor: pointer; -`; - -const Link = styled.span` - cursor: pointer; - color: ${Colors.blue7}; -`; diff --git a/src/components/organisms/PageHeader/CloudSync/index.tsx b/src/components/organisms/PageHeader/CloudSync/index.tsx deleted file mode 100644 index b93a69bf74..0000000000 --- a/src/components/organisms/PageHeader/CloudSync/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export {default} from './CloudSync'; diff --git a/src/components/organisms/PageHeader/PageHeader.tsx b/src/components/organisms/PageHeader/PageHeader.tsx index 98c821fe92..6d1cb8f508 100644 --- a/src/components/organisms/PageHeader/PageHeader.tsx +++ b/src/components/organisms/PageHeader/PageHeader.tsx @@ -42,7 +42,6 @@ import {Icon} from '@monokle/components'; import {isInClusterModeSelector} from '@shared/utils/selectors'; import {trackEvent} from '@shared/utils/telemetry'; -import CloudSync from './CloudSync'; import {ClusterControls} from './ClusterControl/ClusterControls'; import DownloadProgress from './DownloadProgress'; import {K8sVersionSelection} from './K8sVersionSelection'; @@ -280,7 +279,6 @@ const PageHeader = () => {
- diff --git a/src/components/organisms/SettingsPane/CloudConnect/CloudConnect.styled.tsx b/src/components/organisms/SettingsPane/CloudConnect/CloudConnect.styled.tsx deleted file mode 100644 index eeb7a64d1d..0000000000 --- a/src/components/organisms/SettingsPane/CloudConnect/CloudConnect.styled.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import {Row as RawRow} from 'antd'; - -import styled from 'styled-components'; - -import {Colors} from '@shared/styles/colors'; - -export const Row = styled(RawRow)` - overflow: hidden; - padding: 24px; - background: linear-gradient(94.81deg, rgba(42, 56, 90, 0.4) 7%, rgba(53, 35, 60, 0.4) 101.38%); -`; - -export const Heading = styled.h1` - font-size: 24px; - font-weight: 700; - color: ${Colors.geekblue8}; -`; - -export const Subheading = styled.h2` - font-weight: 700; - font-size: 14px; -`; - -export const Paragraph = styled.p` - font-size: 12px; -`; diff --git a/src/components/organisms/SettingsPane/CloudConnect/CloudConnect.tsx b/src/components/organisms/SettingsPane/CloudConnect/CloudConnect.tsx deleted file mode 100644 index 8338858f42..0000000000 --- a/src/components/organisms/SettingsPane/CloudConnect/CloudConnect.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import {Button, Col, Popconfirm, Row} from 'antd'; - -import {useCloudUser} from '@redux/validation/validation.hooks'; - -import CloudSync from '@assets/CloudSync.svg'; - -import {Spinner} from '@monokle/components'; - -import * as S from './CloudConnect.styled'; - -export default function CloudConnect(props: {wide: boolean}) { - const {wide} = props; - const {connect, disconnect, cloudUser, isInitializing, isConnecting, isDisconnecting} = useCloudUser(); - - if (isInitializing) { - return ( - - - - ); - } - - return ( - - - - - {cloudUser ? ( - <> - Connected to Monokle Cloud - - E-mail: {cloudUser.email} - - - You have successfuly connected to your Monokle Cloud Account.
- Your validation policies are now unified and synchronized across platforms. -
- - - - - ) : ( - <> - Connect with Monokle Cloud - What is Monokle Cloud? - - Monokle Cloud is our comprehensive cloud-based solution designed to seamlessly synchronize, validate, - and manage your Kubernetes configurations. By working hand-in-hand with Monokle Desktop, it ensures - that your configurations remain consistent and error-free - - Why connect? -
    -
  • - Unified Validation: Ensure that the same validation policies applied in the cloud are consistent - with those in your local projects. -
  • -
  • - Sync Seamlessly: Automatically synchronize and update your validation rules and policies between - Monokle Cloud and Desktop. -
  • -
  • - Collaborate Efficiently: Work in tandem with your team, ensuring everyone adheres to the latest and - most accurate configuration standards. -
  • -
- - - )} - - - - -
- -
- ); -} diff --git a/src/components/organisms/SettingsPane/CloudConnect/index.tsx b/src/components/organisms/SettingsPane/CloudConnect/index.tsx deleted file mode 100644 index a8fe49271f..0000000000 --- a/src/components/organisms/SettingsPane/CloudConnect/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export {default} from './CloudConnect'; diff --git a/src/components/organisms/SettingsPane/SettingsPane.tsx b/src/components/organisms/SettingsPane/SettingsPane.tsx index 50e43336b9..ee72cadcea 100644 --- a/src/components/organisms/SettingsPane/SettingsPane.tsx +++ b/src/components/organisms/SettingsPane/SettingsPane.tsx @@ -10,7 +10,6 @@ import {TitleBar} from '@monokle/components'; import {SettingsPanel} from '@shared/models/config'; import ValidationSettings from '../ValidationSettings'; -import CloudConnect from './CloudConnect'; import {CurrentProjectSettings} from './CurrentProjectSettings/CurrentProjectSettings'; import {DefaultProjectSettings} from './DefaultProjectSettings/DefaultProjectSettings'; import {GlobalSettings} from './GlobalSettings/GlobalSettings'; @@ -95,18 +94,6 @@ const SettingsPane = () => { }, ] : []), - - ...[ - { - key: 'cloud-connect', - label: Sync with Cloud, - children: ( - - - - ), - }, - ], ], [activeProject, isInQuickClusterMode, isOnStartProjectPage, isStartProjectPaneVisible] ); diff --git a/src/components/organisms/StartPage/StartPage.styled.tsx b/src/components/organisms/StartPage/StartPage.styled.tsx index 996bf3f7a8..45d082c3f3 100644 --- a/src/components/organisms/StartPage/StartPage.styled.tsx +++ b/src/components/organisms/StartPage/StartPage.styled.tsx @@ -103,9 +103,8 @@ export const StartPageContainer = styled.div<{$height: number}>` } `; -export const NewsFeedContainer = styled.div` +export const AsideContainer = styled.div` display: flex; - flex-direction: column; height: 100%; width: 310px; @@ -113,125 +112,3 @@ export const NewsFeedContainer = styled.div` display: none; } `; - -export const NewsFeed = styled.div` - display: flex; - flex-direction: column; - margin-left: 10px; - border-radius: 5px; - border: 1px solid ${Colors.grey10}; - height: 320px; -`; - -export const NewsFeedBottom = styled.div` - display: none; - - @media (max-width: 944px) { - display: flex; - flex-direction: column; - border-radius: 5px; - border: 1px solid ${Colors.grey10}; - height: 150px; - } -`; - -export const NewsFeedHeader = styled.div` - display: flex; - align-items: center; - padding: 10px; - color: ${Colors.geekblue9}; - font-weight: 900; - margin: 10px 0 10px 0; -`; - -export const NewsFeedIcon = styled.div` - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - background: ${Colors.grey10}; - margin-left: 10px; - margin-right: 15px; - border-radius: 30px; -`; - -export const NewsFeedContent = styled.div` - display: flex; - flex-direction: column; - padding: 0 20px 20px 20px; - color: ${Colors.grey1000}; - overflow-y: scroll; - /* Make the scrollbar appear only on hover */ - ::-webkit-scrollbar { - width: 0px; - background: transparent; - } - - &:hover { - ::-webkit-scrollbar { - width: 8px; - background: transparent; - } - ::-webkit-scrollbar-thumb { - background: ${Colors.grey10}; - border-radius: 5px; - } - } -`; - -export const NewsFeedItemTime = styled.div` - font-weight: 400; - color: ${Colors.grey6}; - font-size: 12px; - line-height: 20px; -`; - -export const NewsFeedItemTimeBottom = styled.div` - font-weight: 400; - color: ${Colors.grey6}; - font-size: 12px; - line-height: 20px; - width: 80px; -`; - -export const NewsFeedItemTitle = styled.div` - font-weight: 400; - font-size: 13px; - color: ${Colors.grey7}; - line-height: 20px; -`; - -export const NewsFeeditem = styled.div` - display: flex; - flex-direction: column; - margin: 10px 0 10px 0; - padding: 5px; - border-radius: 5px; - - &:hover { - cursor: pointer; - ${NewsFeedItemTime} { - color: ${Colors.grey7}; - } - ${NewsFeedItemTitle} { - color: ${Colors.grey9}; - } - } -`; - -export const NewsFeeditemBottom = styled.div` - display: flex; - margin: 2px 0 2px 0; - border-radius: 5px; - - &:hover { - cursor: pointer; - ${NewsFeedItemTime} { - color: ${Colors.grey7}; - } - ${NewsFeedItemTitle} { - color: ${Colors.grey9}; - } - } -`; diff --git a/src/components/organisms/StartPage/StartPage.tsx b/src/components/organisms/StartPage/StartPage.tsx index e64dce7879..e2bbaac533 100644 --- a/src/components/organisms/StartPage/StartPage.tsx +++ b/src/components/organisms/StartPage/StartPage.tsx @@ -1,5 +1,3 @@ -import {shell} from 'electron'; - import {useEffect} from 'react'; import {useAppDispatch, useAppSelector} from '@redux/hooks'; @@ -18,14 +16,11 @@ import {useStartPageOptions} from '@hooks/useStartPageOptions'; import {useWindowSize} from '@utils/hooks'; -import AnnotationHeart from '@assets/AnnotationHeart.svg'; - import {StartPageMenuOptions} from '@shared/models/ui'; import {trackEvent} from '@shared/utils/telemetry'; import * as S from './StartPage.styled'; import StartPageHeader from './StartPageHeader'; -import {useNewsFeed} from './useNewsFeed'; export interface NewsFeedItem { title: string; @@ -44,8 +39,6 @@ const StartPage: React.FC = () => { const selectedOption = useAppSelector(state => state.ui.startPage.selectedMenuOption); const isFromBackToStart = useAppSelector(state => state.ui.startPage.fromBackToStart); - const newsFeed = useNewsFeed(); - const {height, width} = useWindowSize(); const options = useStartPageOptions(); @@ -83,11 +76,6 @@ const StartPage: React.FC = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const openNewsFeedItem = (url: string) => { - trackEvent('app_start/select_news_item', {itemUrl: url}); - shell.openExternal(url); - }; - return ( @@ -125,56 +113,9 @@ const StartPage: React.FC = () => { {options[selectedOption].title} {options[selectedOption].content} - - - - news feed icon - - What‘s New? - - - {newsFeed.map(item => ( - { - openNewsFeedItem(item.url); - }} - > - - {Math.floor((new Date().getTime() - new Date(item.date).getTime()) / (1000 * 60 * 60 * 24))} - {' days'} - - {item.title} - - ))} - - - - - - - news feed icon - - What‘s New? - - - {newsFeed.map(item => ( - { - openNewsFeedItem(item.url); - }} - > - - {Math.floor((new Date().getTime() - new Date(item.date).getTime()) / (1000 * 60 * 60 * 24))} - {' days ago'} - - {item.title} - - ))} - - - + ); diff --git a/src/components/organisms/StartPage/useNewsFeed.ts b/src/components/organisms/StartPage/useNewsFeed.ts deleted file mode 100644 index 1f85e7ad6a..0000000000 --- a/src/components/organisms/StartPage/useNewsFeed.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {useState} from 'react'; -import {useAsync} from 'react-use'; - -import log from 'loglevel'; - -import {NewsFeedItem} from '@shared/models/newsfeed'; - -let cachedNewsFeed: NewsFeedItem[] | undefined; - -export function useNewsFeed() { - const [newsFeed, setNewsFeed] = useState(cachedNewsFeed || []); - - useAsync(async () => { - if (cachedNewsFeed) { - setNewsFeed(cachedNewsFeed); - return; - } - const newsFeedUrl = process.env.REACT_APP_NEWS_FEED_URL; - if (!newsFeedUrl) { - return; - } - - try { - const response = await fetch(newsFeedUrl); - const data: NewsFeedItem[] = await response.json(); - const sortedFeed = data - .filter(item => Date.parse(item.date) - Date.now() < 0) - .sort((item1, item2) => Date.parse(item2.date) - Date.parse(item1.date)); - setNewsFeed(sortedFeed); - cachedNewsFeed = sortedFeed; - } catch (e: any) { - log.warn('Error retrieving news feed', e.toString()); - } - }); - - return newsFeed; -} diff --git a/src/components/organisms/ValidationSettings/ValidationCustom/ValidationCustom.tsx b/src/components/organisms/ValidationSettings/ValidationCustom/ValidationCustom.tsx index a5e0126795..0ce11ca104 100644 --- a/src/components/organisms/ValidationSettings/ValidationCustom/ValidationCustom.tsx +++ b/src/components/organisms/ValidationSettings/ValidationCustom/ValidationCustom.tsx @@ -4,8 +4,7 @@ import {Button, Space, Switch, Tooltip} from 'antd'; import {TOOLTIP_DELAY} from '@constants/constants'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {isUsingCloudPolicySelector} from '@redux/validation/validation.selectors'; +import {useAppDispatch} from '@redux/hooks'; import {toggleRule, toggleValidation} from '@redux/validation/validation.slice'; import {PluginMetadataWithConfig} from '@monokle/validation'; @@ -24,8 +23,6 @@ const ValidationCustom: React.FC = props => { const dispatch = useAppDispatch(); - const isUsingCloudPolicy = useAppSelector(isUsingCloudPolicySelector); - const toggleEnabled = useCallback(() => { dispatch(toggleValidation(name)); trackEvent('configure/toggle_validation', {id: name}); @@ -60,15 +57,15 @@ const ValidationCustom: React.FC = props => { Enable plugin - + - - diff --git a/src/components/organisms/ValidationSettings/ValidationCustom/useValidationTable.tsx b/src/components/organisms/ValidationSettings/ValidationCustom/useValidationTable.tsx index 02803d930d..71692e7a13 100644 --- a/src/components/organisms/ValidationSettings/ValidationCustom/useValidationTable.tsx +++ b/src/components/organisms/ValidationSettings/ValidationCustom/useValidationTable.tsx @@ -7,8 +7,7 @@ import styled from 'styled-components'; import {TOOLTIP_DELAY} from '@constants/constants'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {isUsingCloudPolicySelector} from '@redux/validation/validation.selectors'; +import {useAppDispatch} from '@redux/hooks'; import {changeRuleLevel, toggleRule} from '@redux/validation/validation.slice'; import {Icon, IconNames} from '@monokle/components'; @@ -25,8 +24,6 @@ const VALIDATION_HIDING_LABELS_WIDTH = 450; export function useValidationTable(plugin: PluginMetadataWithConfig, width: number) { const dispatch = useAppDispatch(); - const isUsingCloudPolicy = useAppSelector(isUsingCloudPolicySelector); - const handleToggle = useCallback( (rule: Rule) => { dispatch(toggleRule({plugin: plugin.name, rule: rule.name})); @@ -94,14 +91,14 @@ export function useValidationTable(plugin: PluginMetadataWithConfig, width: numb return ( handleToggle(rule)} /> @@ -112,7 +109,7 @@ export function useValidationTable(plugin: PluginMetadataWithConfig, width: numb }), }, ]; - }, [width, plugin.configuration.enabled, changeLevel, handleToggle, isUsingCloudPolicy]); + }, [width, plugin.configuration.enabled, changeLevel, handleToggle]); return columns; } diff --git a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCard.tsx b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCard.tsx index aea1d7708d..7c76015a30 100644 --- a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCard.tsx +++ b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCard.tsx @@ -2,12 +2,8 @@ import {shell} from 'electron'; import {useCallback, useState} from 'react'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import { - isUsingCloudPolicySelector, - pluginRulesSelector, - useValidationSelector, -} from '@redux/validation/validation.selectors'; +import {useAppDispatch} from '@redux/hooks'; +import {pluginRulesSelector, useValidationSelector} from '@redux/validation/validation.selectors'; import {toggleValidation, updateSelectedPluginConfiguration} from '@redux/validation/validation.slice'; import {IconNames} from '@monokle/components'; @@ -35,8 +31,6 @@ const ValidationCard: React.FC = ({configurable, plugin}) => { const dispatch = useAppDispatch(); const hasRules = useValidationSelector(s => pluginRulesSelector(s, name).length > 0); - const isUsingCloudPolicy = useAppSelector(isUsingCloudPolicySelector); - const [isChecked, setIsChecked] = useState(enabled); const openLearnMore = useCallback(() => shell.openExternal(learnMoreUrl || ''), [learnMoreUrl]); @@ -67,11 +61,11 @@ const ValidationCard: React.FC = ({configurable, plugin}) => { {hasRules && configurable && ( - {isUsingCloudPolicy ? 'View' : 'Configure'} + Configure )} - + ); }; diff --git a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardPolicy.tsx b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardPolicy.tsx deleted file mode 100644 index 18e9a29278..0000000000 --- a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardPolicy.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import styled from 'styled-components'; - -import CloudManaged from '@assets/CloudManaged.png'; - -import {Colors} from '@shared/styles'; - -export function ValidationCardPolicy() { - return ( - - - - -
- A Monokle Cloud policy manages this repository - - - Policies add compliancy across your project's repositories by providing consistent validation. The - configuration can no longer be adjusted in this pane. Set up below is read-only. - -
-
- ); -} - -const CardContainer = styled.div` - border-radius: 2px; - background-color: ${Colors.geekblue4}; - padding: 12px; - display: flex; - gap: 12px; - margin-bottom: 20px; - align-items: center; - padding-right: 32px; -`; - -const Description = styled.div` - color: ${Colors.grey9}; - line-height: 22px; - - & span { - color: ${Colors.blue7}; - font-weight: 700; - cursor: pointer; - transition: all 0.2s ease-in; - - &:hover { - color: ${Colors.blue6}; - } - } -`; - -const ImageContainer = styled.div` - padding: 24px; -`; - -const Image = styled.img` - height: 60px; -`; - -const Title = styled.div` - font-weight: 700; - line-height: 22px; - color: ${Colors.whitePure}; - margin-bottom: 12px; -`; diff --git a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardUpNext.tsx b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardUpNext.tsx index 7d5e9eac08..c3bac552a3 100644 --- a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardUpNext.tsx +++ b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationCardUpNext.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {LET_US_KNOW_URL} from '@constants/constants'; -import {openMonokleCloud, openUrlInExternalBrowser} from '@shared/utils/shell'; +import {openUrlInExternalBrowser} from '@shared/utils/shell'; import * as S from './ValidationCardUpNext.styled'; @@ -12,10 +12,7 @@ const ValidationCardUpNext: React.FC = () => { New Validation Policies coming up soon! - openUrlInExternalBrowser(LET_US_KNOW_URL)}>Let us know your favorites or check - out  - openMonokleCloud()}>Monokle Cloud for centralized Policy Management across the - entire lifecycle. + openUrlInExternalBrowser(LET_US_KNOW_URL)}>Let us know your favorites. ); diff --git a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationOverview.tsx b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationOverview.tsx index 8336b73f86..33f538c31b 100644 --- a/src/components/organisms/ValidationSettings/ValidationOverview/ValidationOverview.tsx +++ b/src/components/organisms/ValidationSettings/ValidationOverview/ValidationOverview.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import {useAppSelector} from '@redux/hooks'; -import {isUsingCloudPolicySelector, useValidationSelector} from '@redux/validation/validation.selectors'; +import {useValidationSelector} from '@redux/validation/validation.selectors'; import {CRD_SCHEMA_INTEGRATION} from '@shared/models/validationPlugins'; @@ -9,18 +8,14 @@ import {VALIDATION_CONFIGURATION_COMPONENTS} from './ConfigurationComponents'; import CustomValidationCard from './CustomValidationCard'; import ValidationCard from './ValidationCard'; import {ValidationCardPlugins} from './ValidationCardPlugins'; -import {ValidationCardPolicy} from './ValidationCardPolicy'; import ValidationCardUpNext from './ValidationCardUpNext'; import * as S from './ValidationOverview.styled'; const ValidationOverview: React.FC = () => { const plugins = useValidationSelector(s => Object.values(s.metadata ?? {})); - const isUsingCloudPolicy = useAppSelector(isUsingCloudPolicySelector); return ( - {isUsingCloudPolicy && } - {plugins.map(plugin => ( , false, false)} - openMonokleCloud()}> - Monokle Cloud - openGitHubAction()}> Monokle GitHub Action diff --git a/src/redux/cloud/ipc.ts b/src/redux/cloud/ipc.ts deleted file mode 100644 index 8265258517..0000000000 --- a/src/redux/cloud/ipc.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {invokeIpc} from '@utils/ipc'; - -import type {PolicyData} from '@monokle/synchronizer'; -import {CloudLoginResponse, CloudPolicyInfo, CloudProjectInfo, CloudUser} from '@shared/models/cloud'; - -export const startCloudLogin = invokeIpc('cloud:login'); -export const logoutFromCloud = invokeIpc('cloud:logout'); -export const getCloudUser = invokeIpc('cloud:getUser'); -export const getCloudPolicy = invokeIpc('cloud:getPolicy'); -export const getCloudInfo = invokeIpc( - 'cloud:getInfo' -); diff --git a/src/redux/initialState.ts b/src/redux/initialState.ts index 0fbcc6f3a8..2ee12b58dc 100644 --- a/src/redux/initialState.ts +++ b/src/redux/initialState.ts @@ -5,7 +5,6 @@ import {DEFAULT_PANE_CONFIGURATION} from '@constants/constants'; import {PREDEFINED_K8S_VERSION} from '@shared/constants/k8s'; import {AlertState} from '@shared/models/alert'; import {AppState} from '@shared/models/appState'; -import {CloudState} from '@shared/models/cloud'; import {AppConfig, NewVersionCode, SettingsPanel} from '@shared/models/config'; import {ExtensionState} from '@shared/models/extension'; import {TerminalState} from '@shared/models/terminal'; @@ -270,8 +269,6 @@ const initialTerminalState: TerminalState = { terminalsMap: {}, }; -const initialCloudState: CloudState = {}; - export default { alert: initialAlertState, config: initialAppConfigState, @@ -279,5 +276,4 @@ export default { main: initialAppState, terminal: initialTerminalState, ui: initialUiState, - cloud: initialCloudState, }; diff --git a/src/redux/reducers/cloud.ts b/src/redux/reducers/cloud.ts deleted file mode 100644 index 7769e34805..0000000000 --- a/src/redux/reducers/cloud.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Draft, PayloadAction, createSlice} from '@reduxjs/toolkit'; - -import initialState from '@redux/initialState'; - -import {CloudPolicyInfo, CloudProjectInfo, CloudState, CloudUser} from '@shared/models/cloud'; - -export const cloudSlice = createSlice({ - name: 'cloud', - initialState: initialState.cloud, - reducers: { - setCloudUser: (state: Draft, action: PayloadAction) => { - state.user = action.payload; - }, - setCloudProjectInfo: (state: Draft, action: PayloadAction) => { - state.projectInfo = action.payload; - }, - setCloudPolicyInfo: (state: Draft, action: PayloadAction) => { - state.policyInfo = action.payload; - }, - }, -}); - -export const {setCloudUser, setCloudPolicyInfo, setCloudProjectInfo} = cloudSlice.actions; -export default cloudSlice.reducer; diff --git a/src/redux/store.ts b/src/redux/store.ts index 34d7d66d67..61c2932a13 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -18,7 +18,6 @@ import {formSlice} from './forms'; import {gitSlice} from './git'; import {combineListeners, listenerMiddleware} from './listeners/base'; import {alertSlice} from './reducers/alert'; -import {cloudSlice} from './reducers/cloud'; import {extensionSlice} from './reducers/extension'; import {mainSlice} from './reducers/main'; import {imageListParserListener} from './reducers/main/mainListeners'; @@ -74,7 +73,6 @@ const appReducer = combineReducers({ dashboard: dashboardSlice.reducer, cluster: clusterSlice.reducer, editor: editorSlice.reducer, - cloud: cloudSlice.reducer, }); const rootReducer: typeof appReducer = (state, action) => { diff --git a/src/redux/validation/validation.hooks.ts b/src/redux/validation/validation.hooks.ts deleted file mode 100644 index e04e102f1f..0000000000 --- a/src/redux/validation/validation.hooks.ts +++ /dev/null @@ -1,148 +0,0 @@ -import {useCallback, useEffect, useState} from 'react'; -import {useStore} from 'react-redux'; -import {useAsync, useInterval, useMount} from 'react-use'; - -import {isEqual} from 'lodash'; - -import {getCloudInfo, getCloudPolicy, getCloudUser, logoutFromCloud, startCloudLogin} from '@redux/cloud/ipc'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {setAlert} from '@redux/reducers/alert'; -import {setCloudPolicyInfo, setCloudProjectInfo, setCloudUser} from '@redux/reducers/cloud'; -import {rootFolderSelector} from '@redux/selectors'; - -import {ROOT_FILE_ENTRY} from '@shared/constants/fileEntry'; -import {AlertEnum} from '@shared/models/alert'; -import {AppDispatch} from '@shared/models/appDispatch'; -import {RootState} from '@shared/models/rootState'; -import {trackEvent} from '@shared/utils'; - -import {setCloudPolicy} from './validation.slice'; - -/** - * Used as a telemetry cache to avoid sending multiple events for the same project - */ -const cloudProjectsThisSession = new Set(); - -export const pollCloudPolicy = async (state: RootState, dispatch: AppDispatch) => { - const rootFileEntry = state.main.fileMap[ROOT_FILE_ENTRY]; - const rootFolderPath = rootFileEntry?.filePath; - const cloudPolicy = rootFolderPath ? await getCloudPolicy(rootFolderPath) : undefined; - const previousCloudPolicy = state.validation.cloudPolicy; - - if (!cloudPolicy) { - if (previousCloudPolicy) { - dispatch(setCloudPolicy(undefined)); - } - return; - } - - if (previousCloudPolicy && isEqual(previousCloudPolicy, cloudPolicy)) { - return; - } - - if (!previousCloudPolicy) { - dispatch( - setAlert({ - type: AlertEnum.Success, - title: 'Repository connected to Cloud Project', - message: - 'This repository has been connected successfully to a Cloud Project. The Policy is now being synchronized.', - silent: true, - }) - ); - } else { - dispatch( - setAlert({ - type: AlertEnum.Success, - title: 'Cloud Policy updated', - message: 'The Policy has been changed in the Cloud Project and is now being synchronized.', - silent: true, - }) - ); - } - - dispatch(setCloudPolicy(cloudPolicy)); -}; - -export const useCloudPolicy = () => { - const dispatch = useAppDispatch(); - const store = useStore(); - const cloudPolicy = useAppSelector(state => state.validation.cloudPolicy); - const rootFolderPath = useAppSelector(rootFolderSelector); - - const projectInfo = useAppSelector(state => state.cloud.projectInfo); - const policyInfo = useAppSelector(state => state.cloud.policyInfo); - - const updateProjectInfo = useCallback(async () => { - const cloudInfo = await getCloudInfo(rootFolderPath); - dispatch(setCloudProjectInfo(cloudInfo?.projectInfo)); - dispatch(setCloudPolicyInfo(cloudInfo?.policyInfo)); - - if (cloudPolicy && cloudInfo?.projectInfo && !cloudProjectsThisSession.has(cloudInfo.projectInfo.slug)) { - trackEvent('cloud_sync/policy', {projectSlug: cloudInfo.projectInfo.slug}); - cloudProjectsThisSession.add(cloudInfo.projectInfo.slug); - } - }, [rootFolderPath, cloudPolicy, dispatch]); - - useMount(() => { - pollCloudPolicy(store.getState(), dispatch); - updateProjectInfo(); - }); - - useEffect(() => { - pollCloudPolicy(store.getState(), dispatch); - updateProjectInfo(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [rootFolderPath]); - - useInterval(() => { - pollCloudPolicy(store.getState(), dispatch); - }, 20 * 1000); - - return {cloudPolicy, projectInfo, policyInfo}; -}; - -export const useCloudUser = () => { - const store = useStore(); - const dispatch = useAppDispatch(); - const [isInitializing, setIsInitializing] = useState(false); - const [isConnecting, setIsConnecting] = useState(false); - const [isDisconnecting, setIsDisconnecting] = useState(false); - const cloudUser = useAppSelector(state => state.cloud.user); - - useAsync(async () => { - setIsInitializing(true); - const user = await getCloudUser(undefined); - dispatch(setCloudUser(user)); - setIsInitializing(false); - }, []); - - const connect = async () => { - setIsConnecting(true); - const {user} = await startCloudLogin(undefined); - trackEvent('cloud_sync/login'); - dispatch(setCloudUser(user)); - pollCloudPolicy(store.getState(), dispatch); - setIsConnecting(false); - }; - - const disconnect = async () => { - setIsDisconnecting(true); - await logoutFromCloud(undefined); - trackEvent('cloud_sync/logout'); - dispatch(setCloudUser(undefined)); - dispatch(setCloudPolicy(undefined)); - dispatch(setCloudProjectInfo(undefined)); - dispatch(setCloudPolicyInfo(undefined)); - setIsDisconnecting(false); - }; - - return { - connect, - disconnect, - cloudUser, - isInitializing, - isConnecting, - isDisconnecting, - }; -}; diff --git a/src/redux/validation/validation.listeners.tsx b/src/redux/validation/validation.listeners.tsx index 40bdbf8c32..218ced739f 100644 --- a/src/redux/validation/validation.listeners.tsx +++ b/src/redux/validation/validation.listeners.tsx @@ -55,7 +55,6 @@ import { addValidationPlugin, changeRuleLevel, removeValidationPlugin, - setCloudPolicy, setConfigK8sSchemaVersion, toggleRule, toggleValidation, @@ -83,8 +82,7 @@ const loadListener: AppListenerFn = listen => { toggleValidation, changeRuleLevel, addValidationPlugin, - removeValidationPlugin, - setCloudPolicy + removeValidationPlugin ), async effect(_action, {dispatch, delay, signal, cancelActiveListeners}) { trackEvent('validation/load_config', {actionType: _action.type}); diff --git a/src/redux/validation/validation.selectors.ts b/src/redux/validation/validation.selectors.ts index 30a9552525..ec64e7742b 100644 --- a/src/redux/validation/validation.selectors.ts +++ b/src/redux/validation/validation.selectors.ts @@ -219,8 +219,7 @@ export const activePluginsSelector = createDeepEqualSelector( ); export const pluginEnabledSelector = createDeepEqualSelector( - (state: RootState, id: string) => - state.validation.cloudPolicy?.policy?.plugins?.[id] ?? state.validation.config?.plugins?.[id], + (state: RootState, id: string) => state.validation.config?.plugins?.[id], (_: RootState, id: string) => id, (_config, id): boolean => VALIDATOR.getPlugin(id)?.enabled ?? false ); @@ -281,8 +280,3 @@ export const problemResourceAndRangeSelector = createDeepEqualSelector( return {resourceId, storage, range}; } ); - -export const isUsingCloudPolicySelector = createSelector( - (state: RootState) => state.validation.cloudPolicy, - cloudPolicy => Boolean(cloudPolicy?.policy && cloudPolicy?.valid) -); diff --git a/src/redux/validation/validation.slice.ts b/src/redux/validation/validation.slice.ts index e988816037..ff746c5997 100644 --- a/src/redux/validation/validation.slice.ts +++ b/src/redux/validation/validation.slice.ts @@ -7,7 +7,6 @@ import {stopClusterConnection} from '@redux/thunks/cluster'; import {setRootFolder} from '@redux/thunks/setRootFolder'; import {ValidationFiltersValueType} from '@monokle/components'; -import type {PolicyData} from '@monokle/synchronizer'; import {CORE_PLUGINS, PluginMetadataWithConfig} from '@monokle/validation'; import {SelectedProblem, ValidationState} from '@shared/models/validation'; import {CustomValidationPlugin} from '@shared/models/validationPlugins'; @@ -175,16 +174,11 @@ export const validationSlice = createSlice({ state.config.plugins = pick(state.config.plugins, CORE_PLUGINS); } }, - - setCloudPolicy(state, {payload}: PayloadAction) { - state.cloudPolicy = payload; - }, }, extraReducers: builder => { builder.addCase(setRootFolder.fulfilled, state => { state.validationOverview.selectedProblem = undefined; state.lastResponse = undefined; - state.cloudPolicy = undefined; state.validationOverview.newProblemsIntroducedType = 'initial'; }); @@ -243,6 +237,5 @@ export const { updateSelectedPluginConfiguration, addValidationPlugin, removeValidationPlugin, - setCloudPolicy, } = validationSlice.actions; export default validationSlice.reducer; diff --git a/src/redux/validation/validation.thunks.ts b/src/redux/validation/validation.thunks.ts index b33cd271c2..d56896dcbf 100644 --- a/src/redux/validation/validation.thunks.ts +++ b/src/redux/validation/validation.thunks.ts @@ -9,7 +9,7 @@ import {activeResourceStorageSelector} from '@redux/selectors/resourceMapSelecto import {getResourceKindHandler} from '@src/kindhandlers'; -import {CORE_PLUGINS, Config, ResourceRefType, ValidationResponse} from '@monokle/validation'; +import {CORE_PLUGINS, ResourceRefType, ValidationResponse} from '@monokle/validation'; import {K8sResource, ResourceMeta} from '@shared/models/k8sResource'; import type {ThunkApi} from '@shared/models/thunk'; import type {LoadValidationResult, ValidationArgs, ValidationResource} from '@shared/models/validation'; @@ -30,12 +30,7 @@ export const loadValidation = createAsyncThunk