diff --git a/.circleci/config.yml b/.circleci/config.yml index 908782d5..0fc2c128 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,17 +1,26 @@ -version: 2 +version: 2.1 references: filter_master: &filter_master filters: branches: only: master +orbs: + node: circleci/node@7.1.0 jobs: publish: macos: xcode: "15.0.0" - resource_class: macos.x86.medium.gen2 + resource_class: macos.m1.large.gen1 steps: + - run: + name: Install Rosetta 2 + command: | + softwareupdate --install-rosetta --agree-to-license - checkout + - node/install: + install-yarn: true + node-version: "24.13.0" - restore_cache: key: homebrew-cache-{{ arch }}-{{ .Environment.CACHE_VERSION }}-{{ checksum ".circleci/config.yml" }} - run: @@ -59,8 +68,8 @@ jobs: export CSC_KEY_PASSWORD=$NEW_CSC_KEY_PASSWORD # Win signing # save windows certificate locally (WIN_CERT) is base64 of our certificate - echo $WIN_EV_CERT_BASE64_22 | base64 --decode > rookout.crt - export WINDOWS_EV_CERTIFICATE_PATH=rookout.crt + echo $WIN_EV_CERT_BASE64_25 | base64 --decode > dynatrace.crt + export WINDOWS_EV_CERTIFICATE_PATH=dynatrace.crt # package code for every distribution (mac, win, linux) and publish as github release yarn run build-packages-all-distributions - run: @@ -81,27 +90,30 @@ jobs: version_validation: macos: xcode: "15.0.0" - resource_class: macos.x86.medium.gen2 + resource_class: macos.m1.large.gen1 steps: + - run: + name: Install Rosetta 2 + command: | + softwareupdate --install-rosetta --agree-to-license - checkout - run: name: Validate version has no release yet command: sh ./validate_version.sh publish_release_notes: docker: - - image: node:18.17.1 + - image: node:24.13.0 steps: - checkout - run: name: Generate release notes command: | - export EXPLOROOK_VERSION=$(node -e 'console.log(require("./package").version)') && curl -X POST https://github-enforcer.rookout.com/release -H "Content-Type: application/json" -H "X-Enforcer-Signature: $ENFORCER_SECRET" -d '{"repository":{"full_name":"Rookout/explorook"},"data":{"inner_version":"v'$EXPLOROOK_VERSION'","version_to_publish":"'$EXPLOROOK_VERSION'","component":"explorook","released_by":"CircleCI"}}' + export DYNATRACE_DESKTOP_APP_VERSION=$(node -e 'console.log(require("./package").version)') && curl -X POST https://github-enforcer.rookout.com/release -H "Content-Type: application/json" -H "X-Enforcer-Signature: $ENFORCER_SECRET" -d '{"repository":{"full_name":"Rookout/dynatrace-desktop-application"},"data":{"inner_version":"v'$DYNATRACE_DESKTOP_APP_VERSION'","version_to_publish":"'$DYNATRACE_DESKTOP_APP_VERSION'","component":"dynatrace-desktop-application","released_by":"CircleCI"}}' workflows: version: 2 publish-pipeline: jobs: - version_validation: - requires: <<: *filter_master - publish: requires: diff --git a/.gitignore b/.gitignore index 488710f6..6a1bbb2d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ dist .idea .eslintcache yarn-error.log - +pkg release-builds installers diff --git a/DEVELOPING.MD b/DEVELOPING.MD index e319c771..d447d8ab 100644 --- a/DEVELOPING.MD +++ b/DEVELOPING.MD @@ -1,15 +1,14 @@ # Introduction -Rookout's Desktop App (previously known as "Explorook") is an open-source, [Electron](https://electronjs.org/) based desktop app used by Rookout's [web app](https://app.rookout.com) to extend its usability to the user's local filesystem. -Rookout's Desktop App uses a local http server to expose its API to Rookout's web debugger. -The API is protected by a self generated token. +Dynatrace's Desktop App (previously known as "Explorook" and "Rookout Desktop App") is an open-source, [Electron](https://electronjs.org/) based desktop app used by Rookout's [web app](https://app.rookout.com) to extend its usability to the user's local filesystem. +Dynatrace's Desktop App uses a local http server to expose its API to Rookout's web debugger (and in the future, Dynatrace Live Debugging web app). # Security -Rookout's Desktop App is only accessible from localhost -Rookout's Desktop App only allows read-only access and only to folders the user specifies (and their subfolders) +Dynatrace's Desktop App is only accessible from localhost +Dynatrace's Desktop App only allows read-only access and only to folders the user specifies (and their subfolders) Folders traversal are forbidden -Rookout's Desktop App does not send any information about the user's source code to any server +Dynatrace's Desktop App does not send any information about the user's source code to any server -Rookout's Desktop App spawns three processes (one main and two renderers): +The app spawns three processes (one main and two renderers): 1. [The main process](#The-main-process) 1. [The react web app](#The-react-web-app) 1. [An invisible worker window](#The-invisible-worker-window) @@ -20,7 +19,6 @@ It helps the windows achieve functionalities they cannot access directly (e.g: d # The react web app Written in ``ES6``, and uses ``create-react-app``, The react app is the configuration window where the user can add, delete and manage its configured folders and other global settings. -[](/assets/explorook-main-window.gif) # The invisible worker window The invisible worker window runs the GraphQL server and manages all operations on repositories (CRUD operations and indexing) @@ -28,7 +26,7 @@ The reason we open an invisible window (and not use the main process for that) i # Security & Access Because we listen on http://localhost:44512 (which is the graphql endpoint we spin), every website running on the client's machine has access to our API. -In order to restrict access for Rookout's web app only - we use [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) +In order to restrict access for Rookout's and Dynatrace's web apps only - we use [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) # Project initialization 1. run ``yarn`` in ``/src/webapp`` to install webapp dependencies diff --git a/Dockerfile b/Dockerfile index c5edbfba..b2b638f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,17 @@ -FROM node:18.18.0-alpine as build +FROM node:24.13.0-alpine as build ENV env=development WORKDIR /build ADD package.json ./ ADD yarn.lock ./ -ADD patches ./patches/ RUN yarn install COPY . . RUN yarn run build-headless -FROM node:18.18.0-alpine as release +FROM node:24.13.0-alpine as release WORKDIR /app COPY --from=build /build/dist /app/dist diff --git a/README.md b/README.md index 1dcb955b..61cdd903 100644 --- a/README.md +++ b/README.md @@ -4,43 +4,44 @@

-

Rookout desktop app

+

+ + Dynatrace Logo + +

+ +

Dynatrace Desktop App

- The Rookout desktop app makes it easy to view local files in your browser. + The Dynatrace desktop app makes it easy to view local files in your browser.

## About -[![CircleCI](https://img.shields.io/circleci/build/github/Rookout/explorook.svg?style=flat-square)](https://circleci.com/gh/Rookout/explorook) -[![GitHub release](https://img.shields.io/github/release/rookout/explorook.svg?style=flat-square)](https://GitHub.com/Rookout/explorook/releases/) -[![Github all releases](https://img.shields.io/github/downloads/rookout/explorook/total.svg?style=flat-square)](https://GitHub.com/Rookout/explorook/releases/) -[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=flat-square)](https://GitHub.com//Rookout/explorook/graphs/commit-activity) -[![GitHub contributors](https://img.shields.io/github/contributors/rookout/explorook.svg?style=flat-square)](https://GitHub.com/Rookout/explorook/graphs/contributors/) -[![GitHub license](https://img.shields.io/github/license/rookout/explorook.svg?style=flat-square)](https://github.com/Rookout/explorook/blob/master/LICENSE) -[![Known Vulnerabilities](https://snyk.io/test/github/rookout/explorook/badge.svg?style=flat-square)](https://snyk.io/test/github/rookout/explorook) +[![CircleCI](https://img.shields.io/circleci/build/github/Rookout/dynatrace-desktop-application.svg?style=flat-square)](https://circleci.com/gh/Rookout/dynatrace-desktop-application) +[![GitHub release](https://img.shields.io/github/release/rookout/dynatrace-desktop-application.svg?style=flat-square)](https://GitHub.com/Rookout/dynatrace-desktop-application/releases/) +[![Github all releases](https://img.shields.io/github/downloads/rookout/dynatrace-desktop-application/total.svg?style=flat-square)](https://GitHub.com/Rookout/dynatrace-desktop-application/releases/) +[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=flat-square)](https://GitHub.com//Rookout/dynatrace-desktop-application/graphs/commit-activity) +[![GitHub contributors](https://img.shields.io/github/contributors/rookout/dynatrace-desktop-application.svg?style=flat-square)](https://GitHub.com/Rookout/dynatrace-desktop-application/graphs/contributors/) +[![GitHub license](https://img.shields.io/github/license/rookout/dynatrace-desktop-application.svg?style=flat-square)](https://github.com/Rookout/dynatrace-desktop-application/blob/master/LICENSE) +[![Known Vulnerabilities](https://snyk.io/test/github/rookout/dynatrace-desktop-application/badge.svg?style=flat-square)](https://snyk.io/test/github/rookout/dynatrace-desktop-application) [![Twitter Follow](https://img.shields.io/twitter/follow/rookoutlabs.svg?style=social)](https://twitter.com/rookoutlabs) -Rookout is a data extraction and pipelining platform, which provides the ability to collect any piece of data from live code, on-demand, using non-breaking breakpoints (Learn more about Rookout on our [website](https://www.rookout.com) or our [docs pages](https://docs.rookout.com)). -The Rookout desktop app ("explorook") allows you to navigate through your local projects in a simple and flexible manner. Use this app in combination with the Rookout web debugger to set non-breaking breakpoints in your source files, and to instantly apply them to live code. +The Dynatrace desktop app (previously known as "Explorook" or "Rookout desktop app") allows you to navigate through your local projects in a simple and flexible manner. Use this app in combination with the Rookout web debugger or Dynatrace Live Debugger app (coming soon) to set non-breaking breakpoints in your source files, and to instantly apply them to live code. + -

- Rookout Desktop App -

- Ease of use - set up once and easily access any directory or file you choose directly from the browser. No need to manually open or refresh files and folders; no additional privileges needed. - Git aware - seamlessly access your source code across all devices where the app is installed, regardless of the local paths to which you’ve cloned a git repository to. Easily collaborate with fellow developers working on the same code base. -- Security- maintain strict control over the files you open for sharing and the websites that can access them. Rookout will never collect or modify your source code. +- Security - maintain strict control over the files you open for sharing and the websites that can access them. Rookout will never collect or modify your source code. ## Security -At Rookout we take your source code security very seriously. Rookout will never collect or modify your source code. +At Dynatrace we take your source code security very seriously. Dynatrace will never collect or modify your source code. -The Rookout Desktop App was designed with security as a foremost concern, its security features are as follows: +The Dynatrace Desktop App was designed with security as a foremost concern, its security features are as follows: - The App only listens for connections from localhost. -- The App only allows access from the Rookout app. - -[Learn more about our security standards](https://www.rookout.com/solution/source-code-security/) +- The App only allows access from the Rookout and Dynatrace web apps. ## Installation @@ -50,7 +51,7 @@ https://youtu.be/watch?v=mkMpzQPNcsI ## Contributing There are many ways in which you can participate in the project, for example: -- [Submit bugs and feature requests](https://github.com/Rookout/explorook/issues), and help us verify as they are checked in. +- [Submit bugs and feature requests](https://github.com/Rookout/dynatrace-desktop-application/issues), and help us verify as they are checked in. - Review the [documentation](https://docs.rookout.com) and make pull requests for anything from typos to new content. If you are interested in fixing issues and contributing directly to the code base, please reach out to support@rookout.com. @@ -58,8 +59,8 @@ If you are interested in fixing issues and contributing directly to the code bas ## Feedback - Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/rookout) -- [Request a new feature](https://github.com/Rookout/explorook/issues) -- [File an issue](https://github.com/Rookout/explorook/issues) +- [Request a new feature](https://github.com/Rookout/dynatrace-desktop-application/issues) +- [File an issue](https://github.com/Rookout/dynatrace-desktop-application/issues) - Follow [@rookoutlabs](https://twitter.com/rookoutlabs) and let us know what you think! - Read and subscribe to the [official Rookout Blog](https://www.rookout.com/blog/) @@ -75,3 +76,4 @@ While this project is designed to run on various operating systems, it does not Copyright (c) Rookout LTD. All rights reserved. Licensed under the Apache 2.0 license. + diff --git a/assets/animated-gif.gif b/assets/animated-gif.gif deleted file mode 100644 index 81190898..00000000 Binary files a/assets/animated-gif.gif and /dev/null differ diff --git a/assets/dmg-background.png b/assets/dmg-background.png index 69f67a48..1efacd87 100644 Binary files a/assets/dmg-background.png and b/assets/dmg-background.png differ diff --git a/assets/dynatrace_web.png b/assets/dynatrace_web.png new file mode 100644 index 00000000..a9fd35a0 Binary files /dev/null and b/assets/dynatrace_web.png differ diff --git a/assets/explorook-main-window.gif b/assets/explorook-main-window.gif deleted file mode 100644 index 90a53b00..00000000 Binary files a/assets/explorook-main-window.gif and /dev/null differ diff --git a/assets/icons/logo.png b/assets/icons/logo.png index 64f0ffc1..a779f451 100644 Binary files a/assets/icons/logo.png and b/assets/icons/logo.png differ diff --git a/assets/icons/logo@128x128.png b/assets/icons/logo@128x128.png index c127b3a6..dcff9ae5 100644 Binary files a/assets/icons/logo@128x128.png and b/assets/icons/logo@128x128.png differ diff --git a/assets/icons/logo@16x16.png b/assets/icons/logo@16x16.png index 3cfa137a..417f72b9 100644 Binary files a/assets/icons/logo@16x16.png and b/assets/icons/logo@16x16.png differ diff --git a/assets/icons/logo@256x256.png b/assets/icons/logo@256x256.png index 8014433e..9f61fda5 100644 Binary files a/assets/icons/logo@256x256.png and b/assets/icons/logo@256x256.png differ diff --git a/assets/icons/logo@512x512.png b/assets/icons/logo@512x512.png index edfc5c0b..a305658b 100644 Binary files a/assets/icons/logo@512x512.png and b/assets/icons/logo@512x512.png differ diff --git a/assets/icons/mac/explorook_tray_Template.png b/assets/icons/mac/explorook_tray_Template.png index 0cbf1106..20b6e920 100644 Binary files a/assets/icons/mac/explorook_tray_Template.png and b/assets/icons/mac/explorook_tray_Template.png differ diff --git a/assets/icons/mac/explorook_tray_Template@2x.png b/assets/icons/mac/explorook_tray_Template@2x.png index 1c6d3dfd..4a2ef008 100644 Binary files a/assets/icons/mac/explorook_tray_Template@2x.png and b/assets/icons/mac/explorook_tray_Template@2x.png differ diff --git a/assets/icons/mac/icon.icns b/assets/icons/mac/icon.icns index 01ec05ac..761c277d 100644 Binary files a/assets/icons/mac/icon.icns and b/assets/icons/mac/icon.icns differ diff --git a/assets/icons/mac/icons.icns b/assets/icons/mac/icons.icns index a16f292b..761c277d 100644 Binary files a/assets/icons/mac/icons.icns and b/assets/icons/mac/icons.icns differ diff --git a/assets/icons/win/icon.ico b/assets/icons/win/icon.ico index 446b5fba..dc43b4a0 100644 Binary files a/assets/icons/win/icon.ico and b/assets/icons/win/icon.ico differ diff --git a/assets/rookout_logo_horizontal.svg b/assets/rookout_logo_horizontal.svg new file mode 100644 index 00000000..20001fb8 --- /dev/null +++ b/assets/rookout_logo_horizontal.svg @@ -0,0 +1 @@ + diff --git a/graphql/schema.graphql b/graphql/schema.graphql index d73a9cb6..d757cfd0 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -26,6 +26,12 @@ type CommitDescription { oid: String! } +type OsInfo { + type: String! + version: String! + arch: String! +} + type Query { appVersion: String! dir(repoId: String!, path: String!): [FileInfo]! @@ -37,6 +43,7 @@ type Query { repository(repoId: String!): Repository! BitbucketOnPrem: BitbucketOnPrem! recentLogs: [Log]! + osInfo: OsInfo! } input BitbucketInput { @@ -44,6 +51,7 @@ input BitbucketInput { accessToken: String! projectKey: String repoName: String + tagId: String commit: String branch: String filePath: String @@ -73,9 +81,6 @@ type BitbucketOnPrem { fileTreePageLimit(args: BitbucketInput!): Int isTreeLargerThan(args: BitbucketInput!): Boolean cacheTree(args: BitbucketInput!): Boolean - cancelCacheTree: Boolean - removeTreeFromCache(args: BitbucketTreeInput!): Boolean - cleanTreeCache: Boolean isTreeCached(args: BitbucketTreeInput!): Boolean allCachedRepos: [BitbucketRepoBeingCached] searchTree(args: BitbucketTreeInput!): [String] @@ -86,6 +91,8 @@ type BitbucketOnPrem { repos(args: BitbucketInput!): [BitbucketRepo] commits(args: BitbucketInput!): [BitbucketCommit] @deprecated(reason: "Unused") commit(args: BitbucketInput!): BitbucketCommit + tag(args: BitbucketInput!): BitbucketTag + tags(args: BitbucketInput!): [BitbucketTag] branches(args: BitbucketInput!): [BitbucketBranch] file(args: BitbucketInput!): String bitbucketProperties(args: BitbucketPropertiesInput!): BitbucketProperties @@ -135,6 +142,13 @@ type BitbucketCommit { authorTimestamp: Float! } +type BitbucketTag { + id: String! + displayId: String! + latestCommit: String! + latestChangeset: String! +} + type BitbucketBranch { id: String! displayId: String! diff --git a/package.json b/package.json index 2e217370..0f7294a2 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,9 @@ { - "name": "explorook", - "version": "1.16.5", - "description": "Rookout's site addon to support local files and folders", + "name": "dynatrace-desktop-application", + "version": "1.0.17", + "description": "dynatrace desktop application's site addon to support local files and folders", "main": "dist/index.js", "scripts": { - "postinstall": "patch-package", "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack --config webpack.main.config.js && cross-env NODE_OPTIONS=--openssl-legacy-provider webpack --config webpack.index-worker.config.js", "postbuild": "copyfiles index-worker.html ./dist/", "package-linux": "electron-builder --linux APPIMAGE", @@ -18,15 +17,15 @@ "debug": "cross-env development=1 $NODE_DEBUG_OPTION yarn run build && cross-env development=1 electron --inspect-brk ./dist/index.js" }, "build": { - "productName": "Rookout Desktop App", + "productName": "Dynatrace Desktop App", "extends": null, - "appId": "com.rookout.explorook", + "appId": "com.rookout.dynatrace-desktop-application", "afterSign": "./afterSignHook.js", "publish": [ { "provider": "github", "owner": "rookout", - "repo": "explorook" + "repo": "dynatrace-desktop-application" } ], "directories": { @@ -35,7 +34,8 @@ "protocols": { "name": "rookout", "schemes": [ - "rookout" + "rookout", + "dynatrace" ] }, "files": [ @@ -50,7 +50,8 @@ "target": "appImage", "category": "Utility", "mimeTypes": [ - "x-scheme-handler/rookout" + "x-scheme-handler/rookout", + "x-scheme-handler/dynatrace" ], "desktop": { "exec": "rookout %u" @@ -64,15 +65,16 @@ }, "win": { "publisherName": [ - "Rookout LTD" + "Dynatrace Israel LTD" ], "target": "NSIS", "sign": "./sign_windows.js", "icon": "assets/icons/logo@512x512.png" } }, - "repository": "https://github.com/rookout/explorook", + "repository": "https://github.com/rookout/dynatrace-desktop-application", "keywords": [ + "Dynatrace", "Rookout", "Explorer", "ExploRook", @@ -84,15 +86,15 @@ }, "license": "MIT", "devDependencies": { - "@bugsnag/core": "6.5.0", "@material-ui/core": "^1.2.1", "@material-ui/icons": "^1.1.0", "@playlyfe/gql": "^2.6.0", - "@types/analytics-node": "^3.1.1", "@types/auto-launch": "^5.0.0", "@types/aws-lambda": "^8.10.17", "@types/body-parser": "^1.17.0", - "@types/lodash": "^4.14.182", + "@types/cors": "^2.8.17", + "@types/express": "^5.0.3", + "@types/lodash": "^4.17.23", "@types/node": "^20.12.2", "@types/node-fetch": "^2.6.1", "@types/semver": "^7.5.3", @@ -108,31 +110,27 @@ "tslint": "^5.10.0", "typescript": "^5.4.3", "webpack": "^5.91.0", - "webpack-bugsnag-plugins": "^1.4.3", "webpack-cli": "^5.1.4", "webpack-node-externals": "^1.7.2" }, "dependencies": { - "@bugsnag/js": "6.5.2", + "@apollo/server": "^5.4.0", + "@as-integrations/express5": "^1.1.2", "@electron/notarize": "^2.1.0", "@electron/remote": "2.0.10", "@graphql-tools/schema": "^8.3.13", - "@segment/analytics-node": "^2.1.0", - "apollo-server-express": "3.13.0", "args-parser": "^1.1.0", "auto-launch": "^5.0.5", - "body-parser": "1.19.2", "cors": "^2.8.5", "electron-log": "4.4.7", "electron-store": "8.0.1", - "electron-updater": "6.1.5", - "express": "4.19.2", - "graphql": "^15.4.0", + "electron-updater": "6.6.2", + "express": "5.2.1", + "graphql": "^16.11.0", "isomorphic-git": "^1.8.2", - "lodash": "^4.17.21", + "lodash": "^4.17.23", "log4js": "6.7.1", "parse-repo": "^1.0.4", - "patch-package": "^6.4.0", "postinstall-postinstall": "^2.1.0", "semver": "7.5.4", "slash": "3.0.0", @@ -142,6 +140,10 @@ }, "resolutions": { "@playlyfe/gql/lodash": "^4.17.15", - "graphql-constraint-directive/validator": "^13.6.0" + "graphql-constraint-directive/validator": "^13.6.0", + "sha.js": "^2.4.12", + "ajv": "^8.18.0", + "js-yaml": "^4.1.1", + "qs": "^6.14.2" } } diff --git a/src/BitBucketOnPrem.ts b/src/BitBucketOnPrem.ts index 9d465843..5f20b859 100644 --- a/src/BitBucketOnPrem.ts +++ b/src/BitBucketOnPrem.ts @@ -24,6 +24,7 @@ const MAX_PAGE_SIZES = { PROJECTS: 1_000, REPOSITORIES: 1_000, BRANCHES: 1_000, + TAGS: 1_000, COMMITS: 100 }; @@ -41,6 +42,9 @@ export interface BitbucketOnPrem { repoName?: string; commit?: string; branch?: string; + tagId?: string; + tags?: string; + tag?: string; fileTree?: string[]; filePath?: string; treeSize?: number; @@ -300,16 +304,6 @@ export const cacheFileTree = async ({url, accessToken, projectKey, repoName, com } }; -export const cancelCacheBitbucketTree = async (): Promise => { - if (repoCurrentlyBeingCached) { - abortCache = true; - return true; - } else { - // Nothing to abort - return false; - } -}; - export const getIsTreeCached = async ({projectKey, repoName, commit}: BitbucketOnPremRepoProps): Promise => { logger.debug("Checking if tree is already cached", {projectKey, repoName, commit}); const currentCachedRepos = JSON.parse(store.get("bitbucketTrees", "{}")); @@ -328,27 +322,6 @@ export const idsOfAllCachedTrees = async (): Promise return ids; }; -export const removeFileTreeFromCache = async ({projectKey, repoName, commit}: BitbucketOnPremRepoProps): Promise => { - logger.debug("Trying to remove tree from cache", {projectKey, repoName, commit}); - const currentCachedRepos = JSON.parse(store.get("bitbucketTrees", "{}")); - const repoId = getRepoId({projectKey, repoName, commit}); - // Check if the tree is already cached - if (!currentCachedRepos[repoId]) { - logger.debug("Tree is not in cache", {projectKey, repoName, commit}); - return false; - } - delete currentCachedRepos[repoId]; - store.set("bitbucketTrees", JSON.stringify(currentCachedRepos)); - logger.debug("Successfully removed tree from cache", {projectKey, repoName, commit}); - return true; -}; - -export const cleanBitbucketTreeCache = async (): Promise => { - logger.debug("Cleaning tree cache"); - store.set("bitbucketTrees", "{}"); - return true; -}; - export const getCurrentlyCachedRepo = async (): Promise => { logger.debug("Checking if a tree is currently being cached"); return repoCurrentlyBeingCached; @@ -479,6 +452,42 @@ export const getBranchesForRepoFromBitbucket = async ({url, accessToken, project return branches; }; +export const getTagsForRepoFromBitbucket = async ({url, accessToken, projectKey, repoName}: BitbucketOnPrem) => { + logger.debug("Getting tags for repo", {url, projectKey, repoName}); + const tagsQuery = UrlAssembler(url).template("/rest/api/1.0/projects/:projectKey/repos/:repoName/tags").param({ + projectKey, + repoName + }).toString(); + + const tags: string[] = await fetchAllPages({ + url: tagsQuery, accessToken, maxPageSize: MAX_PAGE_SIZES.TAGS, hasQueryParams: false + }); + + logger.debug("Finished getting tags for repo", {url, projectKey, repoName, tags: JSON.stringify(tags)}); + // console.log(tags); + return tags; +}; + +export const getSpecificTagForRepoFromBitbucket = async ({url, accessToken, projectKey, repoName, tagId}: BitbucketOnPrem) => { + logger.debug(`Getting tag with ID: "${tagId}", for repo`, {url, projectKey, repoName}); + + const specificTagQuery = UrlAssembler(url).template(`/rest/api/1.0/projects/:projectKey/repos/:repoName/tags/:tagId`).param({ + projectKey, + repoName, + tagId + }).toString(); + + const tag = await fetchNoCache(specificTagQuery, { + headers: { + Authorization: `Bearer ${accessToken}` + } + }); + + logger.debug(`Finished getting tag with ID: "${tagId}", for repo`, {url, projectKey, repoName, tag: JSON.stringify(tag)}); + + return tag.json(); +}; + export const getFileContentFromBitbucket = async ({url, accessToken, projectKey, repoName, commit, filePath}: BitbucketOnPrem) => { logger.debug("Getting file content", {url, projectKey, repoName, commit, filePath}); let isLastPage = false; diff --git a/src/api.ts b/src/api.ts index cb7ee215..c86be251 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,31 +1,31 @@ import fs = require("fs"); +import * as os from "node:os"; import {posix} from "path"; import { - BitBucketOnPremInput, - BitbucketOnPremRepoProps, - BitbucketOnPremTreeInput, - BitbucketProperties, - BitbucketPropertiesInput, - cacheFileTree, - cancelCacheBitbucketTree, - cleanBitbucketTreeCache, - getBitbucketProperties, - getBranchesForRepoFromBitbucket, - getCommitDetailsFromBitbucket, - getCommitsForRepoFromBitbucket, - getCurrentlyCachedRepo, - getFileContentFromBitbucket, - getFileTreeByPath, - getFileTreeFromBitbucket, - getFileTreeLargerThan, - getFileTreePageLimit, - getIsTreeCached, - getProjectsFromBitbucket, - getReposForProjectFromBitbucket, - getUserFromBitbucket, - idsOfAllCachedTrees, - removeFileTreeFromCache, - searchBitbucketTree + BitBucketOnPremInput, + BitbucketOnPremRepoProps, + BitbucketOnPremTreeInput, + BitbucketProperties, + BitbucketPropertiesInput, + cacheFileTree, + getBitbucketProperties, + getBranchesForRepoFromBitbucket, + getCommitDetailsFromBitbucket, + getCommitsForRepoFromBitbucket, + getCurrentlyCachedRepo, + getFileContentFromBitbucket, + getFileTreeByPath, + getFileTreeFromBitbucket, + getFileTreeLargerThan, + getFileTreePageLimit, + getIsTreeCached, + getProjectsFromBitbucket, + getReposForProjectFromBitbucket, + getSpecificTagForRepoFromBitbucket, + getTagsForRepoFromBitbucket, + getUserFromBitbucket, + idsOfAllCachedTrees, + searchBitbucketTree } from "./BitBucketOnPrem"; import {Repository} from "./common/repository"; import {notify, USER_EMAIL_KEY} from "./exceptionManager"; @@ -56,6 +56,12 @@ interface FileInfo { size: number; } +interface OsInfo { + type: string; + version: string; + arch: string; +} + export const resolvers = { Repository: { lastCommitDescription: async (parent: Repository) => { @@ -210,7 +216,14 @@ export const resolvers = { const recentLogs = LogsContainer.getLogs(); LogsContainer.cleanLogs(); return recentLogs; - } + }, + osInfo: (): OsInfo => { + return { + type: os.type(), + version: os.release(), + arch: os.arch(), + }; + }, }, BitbucketOnPrem: { fileTree: async (parent: any, { args }: BitBucketOnPremInput): Promise => @@ -221,12 +234,6 @@ export const resolvers = { getFileTreeLargerThan(args), cacheTree: async (parent: any, { args }: BitBucketOnPremInput): Promise => cacheFileTree(args), - cancelCacheTree: async (parent: any): Promise => - cancelCacheBitbucketTree(), - removeTreeFromCache: async (parent: any, { args }: BitbucketOnPremTreeInput): Promise => - removeFileTreeFromCache(args), - cleanTreeCache: async (parent: any): Promise => - cleanBitbucketTreeCache(), isTreeCached: async (parent: any, { args }: BitbucketOnPremTreeInput): Promise => getIsTreeCached(args), allCachedRepos: async (parent: any): Promise => @@ -243,6 +250,10 @@ export const resolvers = { commits: async (parent: any, { args }: BitBucketOnPremInput): Promise => getCommitsForRepoFromBitbucket(args), commit: async (parent: any, { args }: BitBucketOnPremInput): Promise => getCommitDetailsFromBitbucket(args), + tags: async (parent: any, {args}: BitBucketOnPremInput): Promise => + getTagsForRepoFromBitbucket(args), + tag: async (parent: any, {args}: BitBucketOnPremInput): Promise => + getSpecificTagForRepoFromBitbucket(args), branches: async (parent: any, { args }: BitBucketOnPremInput): Promise => getBranchesForRepoFromBitbucket(args), file: async (parent: any, { args }: BitBucketOnPremInput): Promise => diff --git a/src/cors.ts b/src/cors.ts new file mode 100644 index 00000000..0cbb8292 --- /dev/null +++ b/src/cors.ts @@ -0,0 +1,46 @@ +import * as cors from "cors"; +import fetch from "node-fetch"; + + +const LOCALHOST_ORIGIN = "http://localhost:3000"; +const DYNATRACE_ORIGIN_REGEX = /^https:\/\/.*\.dynatrace(?:labs)?\.com(?::\d+)?$/; + +const ALLOW_CORS_OPTION: cors.CorsOptions = {origin: true}; +const DENY_CORS_OPTION: cors.CorsOptions = {origin: false}; + + +const verifiedOriginsCache = new Set([LOCALHOST_ORIGIN]); + + +const corsOptionsDelegate = async (req: cors.CorsRequest, callback: (err: Error | null, options?: cors.CorsOptions) => void) => { + try { + const origin = req.headers.origin; + if (verifiedOriginsCache.has(origin)) { + callback(null, ALLOW_CORS_OPTION); + return; + } + + if (!DYNATRACE_ORIGIN_REGEX.test(origin)) { + callback(null, DENY_CORS_OPTION); + return; + } + + const response = await fetch(`${origin}/platform-reserved/dob/isapprefallowed?appOrigin=${origin}`); + + if (!response.ok) { + callback(null, DENY_CORS_OPTION); + return; + } + + verifiedOriginsCache.add(origin); + callback(null, ALLOW_CORS_OPTION); + } catch (err) { + callback(err, DENY_CORS_OPTION); + } +}; + + +export const getCorsMiddleware = () => { + return cors(corsOptionsDelegate); +}; + diff --git a/src/deeplinks.ts b/src/deeplinks.ts index c2fc7e74..bd330c0d 100644 --- a/src/deeplinks.ts +++ b/src/deeplinks.ts @@ -2,23 +2,23 @@ import {dialog} from "electron"; const path = require("path"); -const PROTOCOL = "rookout"; - - +const PROTOCOLS = ["rookout", "dynatrace"]; export const initDeeplinks = (app: Electron.App) => { - if (process.defaultApp) { + PROTOCOLS.forEach(protocol => { + if (!process.defaultApp) { + app.setAsDefaultProtocolClient(protocol); + return; + } if (process.argv.length >= 2) { - app.setAsDefaultProtocolClient(PROTOCOL, process.execPath, [path.resolve(process.argv[1])]); + app.setAsDefaultProtocolClient(protocol, process.execPath, [path.resolve(process.argv[1])]); } - } else { - app.setAsDefaultProtocolClient(PROTOCOL); - } + }); app.on("open-url", deeplinkHandler); + deeplinkHandler(); }; - export const deeplinkHandler = () => { - dialog.showMessageBoxSync({title: "Rookout Desktop App", message: "Rookout Desktop App is now running"}); -}; + dialog.showMessageBoxSync({title: "Dynatrace Desktop App", message: "Dynatrace Desktop App is now running"}); +}; \ No newline at end of file diff --git a/src/exceptionManager.ts b/src/exceptionManager.ts index 3a66b12d..d456a979 100644 --- a/src/exceptionManager.ts +++ b/src/exceptionManager.ts @@ -1,78 +1,18 @@ -import { Client, INotifyOpts, NotifiableError } from "@bugsnag/core"; -import {getStoreSafe} from "./explorook-store"; -const bugsnag = require("@bugsnag/js"); -const electron = require("electron"); -const remote = process.type === "browser" || process.env.headless_mode === "true" - ? electron - : require("@electron/remote"); - -let app: Electron.App; -// check if not running in headless mode (plain nodejs process) -if (typeof electron !== "string") { - app = electron.app || remote.app; -} - -let exceptionManagerInstance: Client; - -const store = getStoreSafe(); - const ignoredErrors = new Set(["ENOENT", "ENOTDIR", "ENOTEMPTY", "ENOTFOUND", "ETIMEDOUT", "EACCES", "ECONNRESET"]); Object.freeze(ignoredErrors); // prevents anyone from changing the object -export const initExceptionManager = (getUserID: () => string) => { - if (!exceptionManagerInstance && app && (app.isPackaged || process.env.headless_mode === "true")) { - const releaseStage = app.isPackaged ? "production" : "development"; - exceptionManagerInstance = bugsnag({ - onUncaughtException: (err: any) => { - // override default behaviour to not crash - // https://docs.bugsnag.com/platforms/javascript/configuration-options/#onuncaughtexception-node-js-only - console.log(err); - }, - projectRoot: app.getAppPath(), - apiKey: "6e673fda179162f48a2c6b5d159552d2", - appType: "explorook-electron", - appVersion: app.getVersion(), - releaseStage, - beforeSend: (report: any) => { - if (getUserID) { - report.updateMetaData("user", { - userID: getUserID() - }); - } - const userEmail = store.get(USER_EMAIL_KEY, null); - if (userEmail) { - report.updateMetaData("user", { userEmail }); - } - } - }, null); - } - return exceptionManagerInstance; -}; - export const USER_EMAIL_KEY = "userEmailKey"; -export const notify = (error: NotifiableError, opts?: INotifyOpts) => { - // get the error code if exists. If no code exists then notify - const errorCode = error?.code; - if (errorCode && ignoredErrors.has(errorCode)) { - return; - } - exceptionManagerInstance?.notify(error, opts); +export const notify = (...args: any[]) => { + // This will be a NOOP until we replace Bugsnag }; - -export const leaveBreadcrumb = (name: string, metaData?: any, type?: string, timestamp?: string) => { - exceptionManagerInstance?.leaveBreadcrumb(name, metaData, type, timestamp); -}; - export class Logger { public info(message?: any) { - exceptionManagerInstance?.leaveBreadcrumb("log", { message }, "info"); console.info(message); } public warn(message?: any) { - exceptionManagerInstance?.leaveBreadcrumb("log", { message }, "warn"); console.warn(message); } public error(message?: any) { diff --git a/src/git.ts b/src/git.ts index 9d07bcbc..b71bc93b 100644 --- a/src/git.ts +++ b/src/git.ts @@ -6,7 +6,7 @@ import path = require("path"); // for normalization of windows paths to linux style paths import slash = require("slash"); import { Repository } from "./common/repository"; -import { leaveBreadcrumb, notify } from "./exceptionManager"; +import { notify } from "./exceptionManager"; import {getLogger} from "./logger"; import {getLibraryFolder} from "./utils"; const uuidv4 = require("uuid/v4"); @@ -59,7 +59,6 @@ async function getGitRootForPath(filepath: string) { logger.debug("Getting git root for path", filepath); return await igit.findRoot({ fs, filepath }); } catch (err) { - leaveBreadcrumb("Failed to find git root", { filepath, err }); logger.warn("Failed to find git root", { filepath, err }); // No git root was found, probably not a git repository return null; diff --git a/src/index-worker.ts b/src/index-worker.ts index 9bc5b1cb..6c9b6834 100644 --- a/src/index-worker.ts +++ b/src/index-worker.ts @@ -3,7 +3,7 @@ import _ = require("lodash"); import net = require("net"); import { basename } from "path"; import { Repository } from "./common/repository"; -import { initExceptionManager, notify } from "./exceptionManager"; +import { notify } from "./exceptionManager"; import {setLogLevel} from "./logger"; import { repStore } from "./repoStore"; import * as graphQlServer from "./server"; @@ -24,12 +24,6 @@ const isPortInUse = (port: number): Promise => new Promise((re .listen({ port, host: "localhost" }); }); -ipcRenderer.once("exception-manager-enabled-changed", (e: IpcRendererEvent, enabled: boolean) => { - if (enabled) { - initExceptionManager(() => ipcRenderer.sendSync("get-user-id")); - } -}); - const onAddRepoRequest = async (fullpath: string, id?: string) => { ipcRenderer.send("track", "repo-add-request", { fullpath }); if (!fullpath) { diff --git a/src/index.ts b/src/index.ts index 12af11a6..bc0bfd4d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,6 @@ import { enable as remoteEnable, initialize as initElectronRemote } from "@electron/remote/main"; -import Analytics from "@segment/analytics-node"; import { app, BrowserWindow, @@ -18,12 +17,6 @@ import * as log from "electron-log"; import * as Store from "electron-store"; import {autoUpdater, UpdateInfo} from "electron-updater"; import fs = require("fs"); -import { - arch as operatingSystemArch, - platform as operatingSystemPlatform, - userInfo, - version as operatingSystemVersion -} from "os"; import * as path from "path"; import {deeplinkHandler, initDeeplinks} from "./deeplinks"; import { ExplorookStore } from "./explorook-store"; @@ -31,7 +24,7 @@ const uuidv4 = require("uuid/v4"); import AutoLaunch = require("auto-launch"); import fetch from "node-fetch"; import {SemVer} from "semver"; -import { initExceptionManager, Logger, notify } from "./exceptionManager"; +import { Logger, notify } from "./exceptionManager"; initElectronRemote(); autoUpdater.logger = new Logger(); @@ -41,7 +34,7 @@ Store.initRenderer(); const ICONS_DIR = "../assets/icons/"; const APP_ICON = path.join(__dirname, ICONS_DIR, getAppIcon()); const TRAY_ICON = path.join(__dirname, ICONS_DIR, getTrayIcon()); -const ROOKOUT_LOGO = path.join(__dirname, ICONS_DIR, "logo.png"); +const APP_LOGO = path.join(__dirname, ICONS_DIR, "logo.png"); const CLOSE_ICON_BLACK = path.join(__dirname, ICONS_DIR, "baseline_close_black_18dp.png"); const SETTINGS_ICON_BLACK = path.join(__dirname, ICONS_DIR, "baseline_settings_black_18dp.png"); const CLOSE_ICON_WHITE = path.join(__dirname, ICONS_DIR, "baseline_close_white_18dp.png"); @@ -55,11 +48,8 @@ let firstTimeLaunch = false; let al: AutoLaunch; let store: ExplorookStore; let willUpdateOnClose: boolean = false; -let dataCollectionEnabled: boolean; const icon = nativeImage.createFromPath(APP_ICON); -let analytics: Analytics; let userId: string; -let signedEula: boolean = false; // getAppIcon resolves the right icon for the running platform function getAppIcon() { @@ -120,10 +110,6 @@ function registerIpc() { ipcMain.on("hidden", displayWindowHiddenNotification); ipcMain.on("start-server-error", (e: IpcMainEvent, err: any) => { displayNotification("Rookout Desktop App", `App failed to start local server: ${err}`); - track("start-server-error", { err }); - }); - ipcMain.on("track", (e: IpcMainEvent, trackEvent: string, props: any) => { - track(trackEvent, props); }); ipcMain.on("get-user-id", (e: IpcMainEvent) => e.returnValue = userId); ipcMain.on("get-platform", (e: IpcMainEvent) => e.returnValue = process.platform.toString()); @@ -138,25 +124,7 @@ function registerIpc() { const enabled = !(await isReadonlyVolume()) && await al.isEnabled(); e.sender.send("auto-launch-is-enabled-changed", enabled); }); - ipcMain.on("exception-manager-is-enabled-req", (e: IpcMainEvent) => { - e.sender.send("exception-manager-enabled-changed", dataCollectionEnabled); - }); - ipcMain.on("exception-manager-enabled-set", (e: IpcMainEvent, enable: boolean) => { - store.set("sentry-enabled", enable); - e.sender.send("exception-manager-enabled-changed", enable); - }); - ipcMain.on("has-signed-eula", (e: IpcMainEvent) => { - e.returnValue = store.get("has-signed-eula", false); - }); - ipcMain.on("signed-eula", (e: IpcMainEvent) => { - if (dataCollectionEnabled || process.env.development) { - initExceptionManager(() => userId); - initAnalytics(); - track("signed-eula"); - } - store.set("has-signed-eula", true); - startGraphqlServer(); - }); + ipcMain.on("auto-launch-set", (e: IpcMainEvent, enable: boolean) => { if (enable) { store.set("linux-start-with-os", true); @@ -168,44 +136,9 @@ function registerIpc() { }); } -function track(eventName: string, props: any = null, callback: (() => void) | null = null): void { - if (!analytics) { - return; - } - analytics.track({ - userId, - event: eventName, - properties: props - }, callback); -} - - async function flushAnalytics(callback: () => void) { - if (!analytics) { - return; - } - await analytics.closeAndFlush(); - callback(); -} - -function identifyAnalytics() { - const { username } = userInfo(); - const osArch = operatingSystemArch(); - const osPlatform = operatingSystemPlatform(); - const osVersion = operatingSystemVersion(); - analytics.identify({ userId, traits: { username, osPlatform, osArch, osVersion } }); -} - -function initAnalytics() { - analytics = new Analytics({ writeKey: "isfxG3NQsq3qDoNPZPvhIVlmYVGDOLdH"}); - identifyAnalytics(); - track("startup"); -} async function quitApplication() { - track("quit-application"); - await flushAnalytics(() => app.quit()); - // This timeout is here in case the callback is not called or takes too long - setTimeout(() => app.quit(), 3000); + app.quit(); } function main() { @@ -235,12 +168,6 @@ function main() { firstTimeLaunch = true; }); userId = store.getOrCreate("user-id", uuidv4()); - dataCollectionEnabled = Boolean(store.get("sentry-enabled", true)); - signedEula = Boolean(store.get("has-signed-eula", false)); - if (signedEula && (dataCollectionEnabled || process.env.development)) { - initExceptionManager(() => userId); - initAnalytics(); - } // listen to RPC's coming from windows registerIpc(); @@ -307,12 +234,13 @@ async function update() { } async function getLatestVersionName() { - const LATEST_VERSION_URL = "https://api.github.com/repos/Rookout/explorook/releases/latest"; + const LATEST_VERSION_URL = "https://api.github.com/repos/Rookout/dynatrace-desktop-application/releases/latest"; const response = await fetch(LATEST_VERSION_URL); if (!response.ok) { throw new Error(`Error fetching latest version. Got: ${response.status} status with body: ${await response.text()}`); } - return (await response.json()).name; + const data = await response.json() as { name: string }; + return data.name; } function displayWindowHiddenNotification() { @@ -336,7 +264,7 @@ function displayNotification(title: string, body: string, onClick?: (event: Elec tray.displayBalloon({ title, content: body, - icon: ROOKOUT_LOGO, + icon: APP_LOGO, }); } } @@ -379,16 +307,15 @@ function createMainWindow(indexWorkerWindow: BrowserWindow, hidden: boolean = fa webPreferences: { nodeIntegration: true, contextIsolation: false, sandbox: false } }); remoteEnable(mainWindow.webContents); - if (signedEula) { - startGraphqlServer(); - } + startGraphqlServer(); + ipcMain.on("app-window-up", (ev: IpcMainEvent) => { ev.sender.send("indexer-worker-id", indexWorker.id); if (hidden && process.platform === "darwin") { app.dock.hide(); } if (firstTimeLaunch) { - displayNotification("Rookout's Desktop App is running in the background", "You can access the app via the tray icon"); + displayNotification("Dynatrace's Desktop App is running in the background", "You can access the app via the tray icon"); } }); @@ -439,7 +366,7 @@ function openTray() { { label: "Config...", icon: darkMode ? SETTINGS_ICON_WHITE : SETTINGS_ICON_BLACK, click: maximize }, { label: "Close", icon: darkMode ? CLOSE_ICON_WHITE : CLOSE_ICON_BLACK, click: quitApplication }, ]); - tray.setToolTip("Rookout"); + tray.setToolTip("Dynatrace's Desktop App"); tray.setContextMenu(contextMenu); tray.on("double-click", maximize); if (process.platform.match("darwin")) { @@ -486,4 +413,4 @@ app.on("quit", async () => { notify(error); } } -}); \ No newline at end of file +}); diff --git a/src/logger.ts b/src/logger.ts index 6b65a53b..8747a94e 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -16,12 +16,12 @@ if (!logLevel) { logLevel = "debug"; } -const getLogFileLocation = () => path.join(getLibraryFolder(), "rookout.log"); +const getLogFileLocation = () => path.join(getLibraryFolder(), "dynatrace.log"); const customAppender = require("./logsContainerAppender"); log4js.configure({ appenders: { - file: {type: "file", filename: getLogFileLocation()}, + "file": {type: "file", filename: getLogFileLocation()}, "logs-container": { type: customAppender, } diff --git a/src/server.ts b/src/server.ts index 3ad8cde9..ad17db04 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,19 +1,19 @@ -import { makeExecutableSchema } from "@graphql-tools/schema"; -import { ApolloServerPluginLandingPageDisabled } from "apollo-server-core"; -import { ApolloServer } from "apollo-server-express"; -import * as bodyParser from "body-parser"; -import * as cors from "cors"; +import {makeExecutableSchema} from "@graphql-tools/schema"; +import {ApolloServerPluginLandingPageDisabled} from "@apollo/server/plugin/disabled"; +import {ApolloServer} from "@apollo/server"; +import {expressMiddleware} from '@as-integrations/express5'; import * as express from "express"; -import { readFileSync } from "fs"; -import { applyMiddleware } from "graphql-middleware"; +import {readFileSync} from "fs"; +import {applyMiddleware} from "graphql-middleware"; import * as http from "http"; -import { join } from "path"; -import { resolvers } from "./api"; -import { notify } from "./exceptionManager"; +import {join} from "path"; +import {resolvers} from "./api"; +import {getCorsMiddleware} from "./cors"; +import {notify} from "./exceptionManager"; import { - filterDirTraversal, - logMiddleware, - resolveRepoFromId, + filterDirTraversal, + logMiddleware, + resolveRepoFromId, } from "./middlewares"; export type onAddRepoRequestHandler = (fullpath: string, id?: string) => Promise; @@ -21,62 +21,61 @@ export type onAddRepoRequestHandler = (fullpath: string, id?: string) => Promise export type onRemoveRepoRequestHandler = (repId: string) => Promise; export interface StartOptions { - userId?: string; - port?: number; - firstTimeLaunch?: boolean; - onAddRepoRequest?: onAddRepoRequestHandler; - onRemoveRepoRequest?: onRemoveRepoRequestHandler; + userId?: string; + port?: number; + firstTimeLaunch?: boolean; + onAddRepoRequest?: onAddRepoRequestHandler; + onRemoveRepoRequest?: onRemoveRepoRequestHandler; } const defaultOptions: StartOptions = { - port: 44512 + port: 44512 }; -const corsDomainWhitelist = [ - /^https:\/\/.*\.rookout\.com$/, - /^https:\/\/.*\.rookout-dev\.com$/, - /^https:\/\/.*\.dynatracelabs\.com$/, - /^https:\/\/.*\.dynatrace\.com$/, - "https://localhost:8080" -]; +interface ApolloContext { + onAddRepoRequest: Function, + onRemoveRepoRequest: Function +} -const corsOptions = { - origin: corsDomainWhitelist -}; export const start = async (options: StartOptions) => { - const settings = { ...options, ...defaultOptions }; - const typeDefs = readFileSync(join(__dirname, `../graphql/schema.graphql`), { encoding: "utf8" }); + const settings = {...options, ...defaultOptions}; + const typeDefs = readFileSync(join(__dirname, `../graphql/schema.graphql`), {encoding: "utf8"}); + + const schema = makeExecutableSchema({typeDefs, resolvers}); + const schemaWithMiddleware = applyMiddleware(schema, logMiddleware, resolveRepoFromId, filterDirTraversal); + + const app = express(); + const httpServer = http.createServer(app); - const schema = makeExecutableSchema({ typeDefs, resolvers }); - const schemaWithMiddleware = applyMiddleware(schema, logMiddleware, resolveRepoFromId, filterDirTraversal); + const apolloServer = new ApolloServer({ + schema: schemaWithMiddleware, + plugins: [ApolloServerPluginLandingPageDisabled()], + introspection: false, + cache: "bounded", + formatError: (errors: any) => { + if (errors && !/repository\s"(.*)?"\snot\sfound/.test(errors.toString())) { + notify(`Explorook returned graphql errors to client: ${errors}`, {metaData: {errors}}); + } + return errors; + }, + }); - const app = express(); - const httpServer = http.createServer(app); + await apolloServer.start(); - const apolloServer = new ApolloServer({ - context: () => ({ - onAddRepoRequest: settings.onAddRepoRequest, - onRemoveRepoRequest: settings.onRemoveRepoRequest - }), - schema: schemaWithMiddleware, - introspection: false, - plugins: [ApolloServerPluginLandingPageDisabled()], - formatError: (errors: any) => { - if (errors && !/repository\s\"(.*)?\"\snot\sfound/.test(errors.toString())) { - notify(`Explorook returned graphql errors to client: ${errors}`, { metaData: { errors } }); - } - return errors; - }, - cache: "bounded" - }); + app.use('/', + getCorsMiddleware(), + express.json(), + expressMiddleware(apolloServer, { + context: async () => ({ + onAddRepoRequest: settings.onAddRepoRequest, + onRemoveRepoRequest: settings.onRemoveRepoRequest + }) + }) + ) - app.use(cors(corsOptions)); - app.use(bodyParser.json()); - await apolloServer.start(); - apolloServer.applyMiddleware({ app, path: "/" }); - httpServer.listen(settings.port); + httpServer.listen(settings.port); - console.log(`Server is running on http://localhost:${settings.port}`); + console.log(`Server is running on http://localhost:${settings.port}`); }; diff --git a/src/utils.ts b/src/utils.ts index 86bb81d9..5dbd9c5d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,10 +3,10 @@ import * as path from "path"; export const getLibraryFolder = () => { switch (process.platform) { case "win32": - return path.join(process.env.APPDATA, "Rookout"); + return path.join(process.env.APPDATA, "Dynatrace"); case "darwin": - return path.join(process.env.HOME, "Library/Application Support/Rookout"); + return path.join(process.env.HOME, "Library/Application Support/Dynatrace"); default: - return path.join(process.env.HOME, ".Rookout"); + return path.join(process.env.HOME, ".Dynatrace"); } }; diff --git a/src/webapp/craco.config.js b/src/webapp/craco.config.js index 5b1e1bd2..56874e28 100644 --- a/src/webapp/craco.config.js +++ b/src/webapp/craco.config.js @@ -1,15 +1,7 @@ -const { BugsnagSourceMapUploaderPlugin } = require('webpack-bugsnag-plugins'); -const package = require('../../package.json') module.exports = { webpack: { configure: { - target: 'electron-renderer', - plugins: process.env.NODE_ENV === 'development' ? [] : [new BugsnagSourceMapUploaderPlugin({ - apiKey: '6e673fda179162f48a2c6b5d159552d2', - publicPath: '*/app.asar/', - appVersion: package.version, - overwrite: true, - })] + target: 'electron-renderer' } } -} \ No newline at end of file +} diff --git a/src/webapp/package.json b/src/webapp/package.json index 97d49062..55aa0896 100644 --- a/src/webapp/package.json +++ b/src/webapp/package.json @@ -4,13 +4,11 @@ "private": true, "homepage": "./", "dependencies": { - "@bugsnag/js": "6.5.2", "@craco/craco": "^7.1.0", - "@material-ui/core": "^4.0.0", + "@material-ui/core": "^4.12.4", "isomorphic-git": "^1.8.2", "react": "16.10.2", - "react-dom": "16.10.2", - "typeface-roboto": "^0.0.54" + "react-dom": "16.10.2" }, "devDependencies": { "cross-env": "^7.0.3", @@ -19,7 +17,12 @@ "resolutions": { "**/set-value": "^3.0.1", "**/adjust-sourcemap-loader/object-path": "^0.11.5", - "react-scripts/semver": "^7.5.2" + "react-scripts/semver": "^7.5.2", + "ajv": "^8.18.0", + "sha.js": "^2.4.12", + "cross-spawn":"^7.0.5", + "diff":"^4.0.2", + "lodash":"^4.17.23" }, "scripts": { "start": "cross-env NODE_OPTIONS=--openssl-legacy-provider craco start", diff --git a/src/webapp/public/bird-on-folder.png b/src/webapp/public/bird-on-folder.png deleted file mode 100644 index 40fc5c8e..00000000 Binary files a/src/webapp/public/bird-on-folder.png and /dev/null differ diff --git a/src/webapp/public/eula.v2.html b/src/webapp/public/eula.v2.html deleted file mode 100644 index 627d66e3..00000000 --- a/src/webapp/public/eula.v2.html +++ /dev/null @@ -1 +0,0 @@ -

END USER LICENSE AGREEMENT

This End-User License Agreement (“EULA”) constitutes a binding contract between the Rookout entity identified in Section 14 below (“Rookout”) and You – a legal entity (a company, a partnership, or any other legal entity) or an individual (an employee or authorized agent of an entity; hereinafter the “Customer” or "You"). This EULA shall govern any use of the Explorook software product and other software and documentation bundled therewith (collectively, the "Software").

If You are acting on behalf of an organization to acquire a right to use the Software, then You represent and warrant that You are duly authorized to enter into this agreement on behalf of the organization and that You have the proper authority to legally bind the organization, by this agreement.

Taking any step to set-up, configure or install the Software constitutes Your assent to and acceptance of this end user license agreement. Written approval is not a prerequisite to the validity or enforceability of this agreement and no solicitation of any such written approval by or on behalf of You shall be construed as an inference to the contrary.

This EULA also applies to any update of the Software that You use.

THE VARIOUS COMPONENTS OF THE SOFTWARE ARE PROTECTED BY INTERNATIONAL INTELLECTUAL PROPERTY LAWS AND TREATIES AND ARE PROVIDED TO YOU STRICTLY IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF THIS EULA. 

PLEASE CAREFULLY READ THE TERMS AND CONDITIONS OF THIS EULA BEFORE PROCEEDING WITH INSTALLATION OR USE OF THE SOFTWARE.

  1. Definitions
  1. Documentation” means the technical specifications, user-guides and tutorials associated with the Software, as provided by Rookout;
  2. Marks” means all trademarks, service marks, logos, insignia or any other designation of source or origin, whether registered or not;
  3. "Service" means Rookout proprietary application management software, to which the Software reports, that helps organizations collect, manage, debug and enhance the performance of application in production environment;
  4. Term” means the term of this EULA as specified in section 9 below.
  1. License grant. Subject to the terms and conditions of this EULA Rookout grants Customer a limited, non-exclusive, worldwide, non-sublicense-able, non-transferrable and revocable license, to install and use the Software for Customer internal business purposes, and solely in conjunction with Your use of the Service,  (the "License"). This License is explicitly conditioned on Your having an active subscription to the Service.
  2. Authorized Use of the Software; Restrictions
  1. All rights not specifically granted to Customer herein are exclusively reserved to Rookout.
  2. The Software is available for download and installation through the user interface of the Service. Installation of the Software shall be made by the Customer. In any event, Rookout shall not be responsible or liable for installation of the Software.
  3. You will not, by Yourself or through others:
  1. Attempt to reverse engineer, decompile, disassemble, translate or otherwise seek to develop, copy or expose the Software (including the source code), the underlying ideas thereof, or any part thereof or assist or allow any third party to do the same;
  2. Use, copy, modify, merge, distribute, transfer or sublicense the Software or any part thereof, except as expressly authorized in this EULA or in the Documentation;
  3. Use or license the Software for the benefit of third parties not in accordance with this EULA or the Documentation;
  4. Represent that You possess any proprietary interest in the Software or any part thereof, nor delete, deface or otherwise erase any proprietary notice of Rookout from the Software or any part thereof;
  5. Directly or indirectly, take any action to contest Rookout's intellectual property and proprietary rights or infringe them in any way;
  6. Write or develop any derivative software or any other software program based upon all or any part of the Software (including, without limitations, any user manuals) or any other proprietary or confidential information of Rookout; or
  7. Develop, or create, or permit others to develop or create, a product or service similar to or in competition with the Software;
  8. Attempt to engage in: (i) any form of testing, scanning, scraping, probing, robotic navigating, bulk extracting or hacking of the Software; (ii) Breaching the security of the Software or identifying any security vulnerabilities thereof; (iii) Interfering with, circumventing, manipulating, impairing or disrupting the operation, or the functionality of the Software; (iv) Working around or circumventing any technical limitations in the Software; or (v) Activities which may enable features or functionalities which are otherwise disabled, inaccessible or undocumented in the Software.
  9. Use the Software for any activity that constitutes, or encourages conduct that would constitute, a criminal offense, give rise to civil liability or otherwise violate any applicable law or industry standard, including any applicable laws and regulations governing copyrights, computer hacking, privacy and export control.
  1. Fees. The Software is currently offered for Customers who are subscribed to the Service, without any additional cost, but Rookout reserves the right to charge license fees for the Software at any time subject to Rookout obtaining your consent to those fees.
  2. Data; Compliance.
  1. You acknowledge and agree that we may process information about the Software’s configuration and status ("Software Data"). Such Software Data may (but not necessarily) include identifiable information. You further acknowledge and agree that we will handle and use (by Rookout or using trusted third-party service providers such as cloud service providers) the Software Data and as follows:
  1. To provide the Software to you, conduct administrative and technical activities necessary to maintain and provide the Software and to improve and customize the Software;
  2. To provide you support services related to the Software;
  3. To conduct analysis or generate metrics related to the Software;
  4. For commercial and marketing purposes, publication of case studies and white papers;
  1. You undertake that Your use of the Software shall, at all time, comply with all applicable laws, including export control laws. You may not use the Software for any activity that constitutes, or encourages conduct that would constitute, a criminal offense, give rise to civil liability or otherwise violate any applicable law.
  1. Open Source. The Software may use or include open source software components (“OSS”). To the extent so stipulated by the license that governs each OSS ("OSS License"), each such OSS is subject to its respective OSS License, not this EULA, and is licensed to You directly by its respective licensors, not sublicensed by Rookout. If, and to the extent, an OSS License requires that this EULA shall effectively impose, or incorporate by reference, certain disclaimers, provisions, prohibitions or restrictions, then such disclaimers, provisions, prohibitions or restrictions shall be deemed to be imposed, or incorporated by reference into this EULA, as required, and shall supersede any conflicting provision herein, solely with respect to the corresponding OSS which is governed by such OSS License.

If, and to the extent, an OSS License requires that the source code of its corresponding OSS be made available to You or any other third party, and such source code was not delivered to You with the Software, then Rookout hereby grants a written offer, valid for the period prescribed in such OSS License, to obtain a copy of the source code of the corresponding OSS from Rookout. To take up this offer, contact Rookout at liran@rookout.com.

  1. Support and maintenance
  1. Subject to Rookout’s ordinary terms for support of the Service, You shall be entitled to support and maintenance of the Software as well.
  2. Rookout will have access to Your installed instance of the Software for support purposes, in accordance with your permission for such access through the user interface of the Software.
  1. Intellectual property.
  1. The Software, the Documentation and all ideas underlying the Software, including any revisions, corrections, modifications, enhancements, updates and/or upgrades thereto, are and shall remain Rookout's property and protected under any applicable laws and treaties. All rights, title and interests in and to the Software, including associated intellectual property rights (including but not limited to patents, copyrights, trade secrets, trademarks, etc., all whether registered or not), evidenced by or embodied, attached, connected and/or related to the Software, and any goodwill associated therewith, are and shall remain Rookout's sole property, except for off-the-shelf components that are included therein. The License granted to You hereunder does not convey to You any interest in or to the Software, but only a limited right of use, revocable in accordance with the terms and conditions of this EULA.
  2. Nothing in this EULA constitutes a waiver of Rookout's intellectual property rights under any law. The License for the Software granted, pursuant to this EULA, gives You a limited right to use the Software, but does not constitute a sale of the Software.
  3.         Any use of the Software in violation of the limited License granted hereunder or restrictions imposed in this EULA may result in the revocation of the License and may expose You to claims for damages.
  1. Term.
  1. The License granted hereunder shall be in effect for as long as you subscribed to the Service (the "Term"). Notwithstanding the foregoing, in the event of a breach by Customer of any of the provisions of this EULA that has not been cured (to the extent such breach is curable) in such a manner satisfactory to Rookout, within 7 days from the receipt of a written notice, then (i) the License hereunder terminates; and (ii) the Customer must uninstall and remove all copies of the Software in its disposal or control. The foregoing shall be without prejudice to any other remedy Rookout may have under applicable law or agreement.
  2. Upon termination or expiration hereof for any or for no reason, the License granted hereunder shall terminate, and Customer shall not be allowed to further use the Software (including all copies of Documentation) or any part thereof. The provisions of paragraphs 5, 6, 8, 9, 10, 12 ‎, 13 and 14 will survive the termination or expiration of this EULA.
  1. Confidentiality.
  1. You acknowledge that the Software and all elements thereof, including without limitation, its design, structure, capabilities, functionality, payment details and Documentation, constitute Rookout’s confidential information. Accordingly, You must treat all such information as confidential material in a manner no less protective than You use to protect Your own similar assets, but in no event less than reasonable care. Without derogating from the foregoing, You will maintain in strict confidentiality any information regarding the Software's functionality, capabilities, structure, design and all other details related thereto, any of Rookout’s business practices, tutorials and training material, and will not disclose them, or have them disclosed, directly or indirectly to any third party without Rookout’s prior written consent.
  2. Notwithstanding the foregoing, You may disclose confidential information, only if and to the extent such disclosure is required in order to comply with a legal obligation including, orders, subpoenas, decrees or request prescribed by a competent judicial, administrative or regulatory authority, provided that, to the extent legally permitted, You promptly notify Rookout of such legal obligation, to give Rookout an opportunity to challenge the legally required disclosure.
  1. Disclaimers
  1. THE SOFTWARE IS PROVIDED "AS IS". TO THE MAXIMUM EXTENT PERMITTED BY LAW, ROOKOUT EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, CONDITIONS, REPRESENTATIONS, AND GUARANTEES WITH RESPECT TO THE SOFTWARE, WHETHER EXPRESS OR IMPLIED, ARISING BY LAW, CUSTOM, TRADE USAGE, PRIOR ORAL OR WRITTEN STATEMENTS, OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, EXPECTED RESULT, QUALITY, TITLE, PERFORMANCE, SECURITY OR COMPATIBILITY. NO REPRESENTATION OR OTHER AFFIRMATION OF FACT, INCLUDING, WITHOUT LIMITATION, STATEMENTS REGARDING CAPACITY, SUITABILITY FOR USE OR PERFORMANCE OF THE SOFTWARE, WHETHER MADE BY ROOKOUT, A REPRESENTATIVE OR OTHERWISE, WHICH IS NOT EXPRESSLY PROVIDED IN THIS EULA, SHALL BE DEEMED TO BE A WARRANTY BY ROOKOUT FOR ANY PURPOSE, OR GIVE RISE TO ANY LIABILITY OF ROOKOUT WHATSOEVER.
  2. Rookout make no representation or warranty that the Software comply with any third party or regulatory terms, conditions, rules or guidelines regarding software development.
  3. Rookout has no responsibility or liability in respect to Your reliance upon, or use of, the Software, any actions or omission You perform, or any consequences resulting therefrom.
  1. Limitation of liability. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, ROOKOUT AND ITS  EMPLOYEES, DIRECTORS, OFFICERS, SHAREHOLDERS, LICENSORS, ADVISORS, AND ANYONE ACTING ON THEIR BEHALF OR ANY THIRD-PARTY SUPPLIERS, WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, STATUTORY OR PUNITIVE DAMAGES, LOSSES (INCLUDING LOSS OF PROFIT AND LOSS OF DATA), COSTS, EXPENSES AND PAYMENTS, EITHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR IN ANY OTHER FORM OR THEORY OF LIABILITY, ARISING FROM, OR IN CONNECTION, WITH THIS EULA, THE SOFTWARE, EVEN IF ROOKOUT IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, LOSS, COSTS, EXPENSES OR PAYMENTS. WITHOUT DEROGATING FROM THE AFORESAID, IN NO EVENT WILL ROOKOUT’S CUMULATIVE LIABILITY HEREUNDER EXCEED THE HIGHER OF: (A) THE AMOUNT YOU PAID TO ROOKOUT (IF ANY) DURING THE SIX MONTHS PRECEDING THE EVENT PURPORTEDLY GIVING RISE TO THE DAMAGE, OR, (B) THE LOWEST DAMAGE CAP PERMITTED BY APPLICABLE LAW.
  2. Indemnity. You agree to indemnify and hold harmless Rookout and its respective directors, officers, employees, and subcontractors, upon Rookout’s request and at Your own expense, from, and against, any damages, liabilities, losses, costs, expenses and payments, including reasonable attorney’s fees and legal expenses, arising from or connected to any actual or claimed: (i) breach by the Customer of any provision or representation herein; (ii) use of the Software outside the scope of the license granted in, or contrary to, the provisions of this EULA; (iii) the combination of the Software with any other service or product; or (iv) infringement of any third party rights, including, but not limited to intellectual property rights.
  3. Contracting Entity; Governing law and venue. 
  1. If you are established or located in the United States of America, then the following apply:
  1. This EULA is concluded between you and Rookout, Inc., a Delaware Corporation.
  2. Regardless of Your jurisdiction of residence, Customer's jurisdiction of incorporation, the jurisdiction where the Customer engages in business or where You access or use the Software from, this EULA and Your use of the Software will be exclusively governed by and construed in accordance with the laws of the State of New York, excluding any otherwise applicable rules of conflict of laws, which would result in the application of the laws of a jurisdiction other than Israel. Any dispute, controversy or claim which may arise out of or in connection with this EULA, or the Software, shall be submitted to the sole and exclusive jurisdiction of the state and federal courts in New York County, New York and the U.S. District Court for the Southern District of New York.
  1. If you are established or located elsewhere than the United States of America, then the following apply:
  1. This EULA is concluded between you and Rookout Ltd., an Israeli company.
  2. Regardless of Your jurisdiction of residence, Customer's jurisdiction of incorporation, the jurisdiction where the Customer engages in business or where You access or use the Software from, this EULA and Your use of the Software will be exclusively governed by and construed in accordance with the laws of the State of Israel, excluding any otherwise applicable rules of conflict of laws, which would result in the application of the laws of a jurisdiction other than Israel. Any dispute, controversy or claim which may arise out of or in connection with this EULA, or the Software, shall be submitted to the sole and exclusive jurisdiction of the competent courts in Tel Aviv, Israel.
  1. Miscellaneous
  1. You may not assign or delegate this EULA or any of Your rights, performance or obligations hereunder, without Rookout’s prior written consent. Any purported assignment without Rookout’s prior written consent is void. Rookout may assign and delegate this EULA in its entirety, including all Rookout’s rights, duties, liabilities, performance and obligations herein, upon notice to You and without obtaining Your specific consent, to a third-party, upon a merger, acquisition, change of control or the sale of all or substantially all of Rookout’s equity or assets. By virtue of such assignment, the assignee assumes Rookout’s stead, including all right, duties, liabilities, performance and obligations, and Rookout shall be irrevocably released from the same.
  2. The relationship between You and Rookout is strictly that of independent contractors, and neither party is an agent, partner, joint venturer or employee of the other.
  3. This EULA constitutes the entire and complete agreement between You and Rookout concerning the subject matter herein. This EULA supersedes all prior oral or written statements, understandings, negotiations and representations with respect to the subject matter herein. If any provision of this EULA is held invalid or unenforceable, that provision shall be construed in a manner consistent with the applicable law to reflect, as nearly as possible, the original intent of the parties, and the remaining provisions will remain in full force and effect. This EULA may be modified or amended only in writing, signed by the duly authorized representatives of You and Rookout.
  4. Rookout shall not, by mere lapse of time, without giving express notice thereof, be deemed to have waived any breach by You, of any terms or provisions of this EULA. The waiver, by Rookout, of any breach by You, will not be construed as a waiver of subsequent breaches or as a continuing waiver of such breach.

* * * * *

\ No newline at end of file diff --git a/src/webapp/public/folders.svg b/src/webapp/public/folders.svg deleted file mode 100644 index bb273681..00000000 --- a/src/webapp/public/folders.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/webapp/public/logo.png b/src/webapp/public/logo.png index edfc5c0b..3cc240a2 100644 Binary files a/src/webapp/public/logo.png and b/src/webapp/public/logo.png differ diff --git a/src/webapp/src/App.css b/src/webapp/src/App.css index bae2f4ea..20dd13de 100644 --- a/src/webapp/src/App.css +++ b/src/webapp/src/App.css @@ -1,30 +1,24 @@ -html { - background-color: #3F4758; - font-family: Roboto; - color: white; +html { + font-family: DynatraceFlow; height: 100%; + background: #111223; } + #root { height: 100%; } -.primary { - color: #955FF8; - border-color: #955FF8; -} - .gray-shaded { - color: #B6C8D4; -} - -.rookout-gray { - color: #6E7A89; + color: #AEAFC980; } body { height: 100%; -ms-overflow-style: scrollbar; + margin: 0; + padding: 0; + font-family: sans-serif; } .App { @@ -38,51 +32,21 @@ div, span { } -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; -} - -.App-header { - background-color: #222; - height: 150px; - padding: 20px; - color: white; -} - -.App-title { - font-size: 1.5em; -} - -.App-intro { - font-size: large; -} - -@keyframes App-logo-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} - -.Header-line { - box-sizing: border-box; - height: 2px; - border: 1px solid #4D5667; -} - .Header-title { height: 24px; - color: #FFFFFF; - font-family: Roboto; + color: #F0F0F5; + font-family: DynatraceFlow; font-size: 20px; line-height: 24px; margin-bottom: 5px; margin-left: 10px; + font-weight: 600; } .Header-logo { margin-top: 5px; - width: 42px; - height: 42px; + width: 40px; + height: 34px; } .Header { @@ -92,74 +56,16 @@ div, span { padding-top: 10px; padding-bottom: 5px; padding-left: 25px; + align-items: center; } -#token-box { - display: flex; - height: 25px; - padding: 10px; - background-color: #2F3545; - width: 100%; - max-width: 500px; - color: #B6C8D4; - font-family: Roboto; - font-size: 18px; -} - -#token-wrapper { - display: -webkit-box; -} - -#token-show-eye { - margin-left: auto; - justify-self: flex-end; - cursor: pointer; -} - -.small-icon { - font-size: 18; - color: #5f697a; -} - -#copy-token-btn { - height: 44px; - font-weight: 400; - font-size: 14px; - font-family: Roboto; - color: white; - border-radius: 0; - background-color: #955FF8; -} - -.test-connection-btn { - font-weight: 400; - font-size: 14px; - font-family: Roboto; - color: white; - background-color: #955FF8; - margin-left: 10px; - padding: 0; - height: 25px; - width: 111px; - border-radius: 100px; -} - -#minimize-window-btn:hover, #close-window-btn:hover { - background-color: #c4cfd6; -} #close-window-btn { - color: white; - margin: 10px; + color: #F0F0F5; + margin: 28px 28px 0 0; -webkit-app-region: no-drag; } -#minimize-window-btn { - color: white; - margin: 10px; - margin-right: 0px; - -webkit-app-region: no-drag; -} #close-window-wrapper { float: right; @@ -168,36 +74,6 @@ div, span { cursor: pointer; } -#content-container { - margin-left: 25px; - text-align: left; -} - -.repo-name { - margin-top: 5px; - margin-left: 10px; -} - -.repo-name-edit { - margin-left: 10px; - min-width: 350px; - outline-width: 0; - background-color: transparent; - border-top: none; - border-left: none; - border-color: #955FF8; - border-right: none; - height: 25px; - font-size: 16px; - color: white; -} - -#repo-buttons { - justify-content: flex-end; - margin-left: auto; - margin-right: 25px; -} - #version-title { padding-top: 15px; margin-left: 5px; @@ -208,70 +84,20 @@ div, span { display: flex; } -#token-title { - margin-bottom: -12px; - align-items: center; - font-size: 16px; -} - -#token-lock { - margin-bottom: 5px; - height: 25px; - cursor: pointer; -} - #checkboxes-group { margin-left: 20px; margin-bottom: 8px; } -.eula-modal { - display: flex; - flex-direction: column; - background: white; - font-family: Roboto, sans-serif; - height: 100%; - padding-left: 5%; - padding-right: 5%; -} - -.eula-modal .headline { - color: black; - font-size: 24px; - margin-top: 30px; - font-weight: 300; -} - -.eula-modal .eula-iframe { - width: 100%; - height: 65%; -} -.eula-modal .eula-box { - width: 100%; - height: 65%; - overflow: auto; - background-color: gray; -} -.eula-modal .actions { - display: flex; - flex-direction: row; - justify-content: flex-end; - height: 35px; - margin-bottom: 20px; +#footer-container { + border-top: 1px solid #4D5667; + padding-top: 5px; } -.eula-modal .agree { - margin-left: 10px; -} - -.on-prem-input { - border-bottom: 2px solid #B6C8D4; - color: #b6c8d4 !important; -} -.on-prem-input:hover { - color: #b6c8d4; +#footer-container p { + color: #F0F0F5; } div::-webkit-scrollbar-track, span::-webkit-scrollbar-track, code::-webkit-scrollbar-track { diff --git a/src/webapp/src/App.js b/src/webapp/src/App.js index 117cec65..7404e928 100644 --- a/src/webapp/src/App.js +++ b/src/webapp/src/App.js @@ -1,18 +1,15 @@ import React, { useEffect, useState } from 'react' import { ipcRenderer } from 'electron' import './App.css' -import 'typeface-roboto/index.css' +import './Fonts.css' import { Header } from './components/Header' import Footer from './components/Footer' -import { ReposList } from './components/ReposList' -import { EulaModal } from './components/EulaModal' import { EmptyState } from './components/EmptyState' +import {ReposAddHandler} from "./components/ReposAddHandler"; -const INITIAL_HAS_SIGNED_EULA = ipcRenderer.sendSync('has-signed-eula') -export const App = ({ ...props }) => { +export const App = () => { const [loading, setLoading] = useState(true) - const [hasSignedEula, setHasSignedEula] = useState(INITIAL_HAS_SIGNED_EULA) useEffect(() => { // "indexer-worker-id" event should be subscribed to BEFORE "app-window-up" event @@ -30,21 +27,10 @@ export const App = ({ ...props }) => { return (
-
-
-
- {hasSignedEula && } - {hasSignedEula && } - {!hasSignedEula && ( -
-
- -
-
- )} -
-
-
+
+ + +
) } diff --git a/src/webapp/src/Fonts.css b/src/webapp/src/Fonts.css new file mode 100644 index 00000000..d994f962 --- /dev/null +++ b/src/webapp/src/Fonts.css @@ -0,0 +1,39 @@ +@font-face { + font-family: 'DynatraceFlow'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(./assets/fonts/DTFlow-Light.woff2) format('woff2'); +} +/* DT Flow Regular */ +@font-face { + font-family: 'DynatraceFlow'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(./assets/fonts/DTFlow-Regular.woff2) format('woff2'); +} +/* DT Flow Medium */ +@font-face { + font-family: 'DynatraceFlow'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("./assets/fonts/DTFlow-Medium.woff2") format('woff2'); +} +/* DT Flow Semibold */ +@font-face { + font-family: 'DynatraceFlow'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(./assets/fonts/DTFlow-Semibold.woff2) format('woff2'); +} +/* DT Flow Heavy */ +@font-face { + font-family: 'DynatraceFlow'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url(./assets/fonts/DTFlow-Heavy.woff2) format('woff2'); +} diff --git a/src/webapp/src/assets/fonts/DTFlow-Heavy.woff2 b/src/webapp/src/assets/fonts/DTFlow-Heavy.woff2 new file mode 100644 index 00000000..1f1a93d1 Binary files /dev/null and b/src/webapp/src/assets/fonts/DTFlow-Heavy.woff2 differ diff --git a/src/webapp/src/assets/fonts/DTFlow-Light.woff2 b/src/webapp/src/assets/fonts/DTFlow-Light.woff2 new file mode 100644 index 00000000..eef7b5a0 Binary files /dev/null and b/src/webapp/src/assets/fonts/DTFlow-Light.woff2 differ diff --git a/src/webapp/src/assets/fonts/DTFlow-Medium.woff2 b/src/webapp/src/assets/fonts/DTFlow-Medium.woff2 new file mode 100644 index 00000000..8739abbc Binary files /dev/null and b/src/webapp/src/assets/fonts/DTFlow-Medium.woff2 differ diff --git a/src/webapp/src/assets/fonts/DTFlow-Regular.woff2 b/src/webapp/src/assets/fonts/DTFlow-Regular.woff2 new file mode 100644 index 00000000..4cd3130e Binary files /dev/null and b/src/webapp/src/assets/fonts/DTFlow-Regular.woff2 differ diff --git a/src/webapp/src/assets/fonts/DTFlow-Semibold.woff2 b/src/webapp/src/assets/fonts/DTFlow-Semibold.woff2 new file mode 100644 index 00000000..c2609822 Binary files /dev/null and b/src/webapp/src/assets/fonts/DTFlow-Semibold.woff2 differ diff --git a/src/webapp/src/components/Checkbox.js b/src/webapp/src/components/Checkbox.js deleted file mode 100644 index e6a94a8f..00000000 --- a/src/webapp/src/components/Checkbox.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react"; -import { Checkbox, withStyles } from "@material-ui/core"; -import blueGrey from "@material-ui/core/colors/blueGrey"; - -const styles = { - root: { - color: blueGrey[500], - "&$checked": { - color: blueGrey[500], - }, - }, - checked: {}, -}; - -const checkbox = ({ classes, checked, onChange, children, ...props}) => { - return {children}; -}; - -export default withStyles(styles)(checkbox); diff --git a/src/webapp/src/components/ConfirmModal.js b/src/webapp/src/components/ConfirmModal.js deleted file mode 100644 index 0f5e7663..00000000 --- a/src/webapp/src/components/ConfirmModal.js +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useState } from 'react' -import { - Dialog, - DialogContent, - DialogActions, - DialogTitle, - DialogContentText, - Button, - FormControlLabel, - withStyles, -} from '@material-ui/core' -import Checkbox from './Checkbox' -import * as Store from 'electron-store' - -const style = { - checkBoxLabel: { - color: '#B6C8D4', - }, -} - -const store = new Store({ name: 'explorook' }) - -export const ConfirmModal = ({ - body, - title, - open, - onClose, - classes, - onCancel, - onAgree, -}) => { - const [askAgainChecked, setAskAgainChecked] = useState(false) - - return ( - - -

- {title} -

-
-
- - {body} - - - { - setAskAgainChecked(checked) - store.set('non-git-dialog-never-ask-again', checked) - }} - /> - } - label={'Never ask again'} - /> - - - -
- ) -} - -export const Confirm = withStyles(style)(ConfirmModal) diff --git a/src/webapp/src/components/EmptyState.js b/src/webapp/src/components/EmptyState.js index e6f18874..b37b3a70 100644 --- a/src/webapp/src/components/EmptyState.js +++ b/src/webapp/src/components/EmptyState.js @@ -3,14 +3,8 @@ import { Text } from './EmptyStateText' export const EmptyState = () => { return ( -
-
- -
- Sweet! Rookout desktop app - is up and running in the background -
-
+
+ App is up and running in the background
); } diff --git a/src/webapp/src/components/EmptyStateText.js b/src/webapp/src/components/EmptyStateText.js index cd411c4d..a80634d8 100644 --- a/src/webapp/src/components/EmptyStateText.js +++ b/src/webapp/src/components/EmptyStateText.js @@ -2,5 +2,5 @@ import React from 'react'; export const Text = ({ style, children, ...props }) => { - return

{children}

-} \ No newline at end of file + return

{children}

+} diff --git a/src/webapp/src/components/EulaModal.js b/src/webapp/src/components/EulaModal.js deleted file mode 100644 index 3c3b7c78..00000000 --- a/src/webapp/src/components/EulaModal.js +++ /dev/null @@ -1,116 +0,0 @@ -import React, { useState } from 'react' -import Modal from '@material-ui/core/Modal' -import Button from '@material-ui/core/Button' -import { withStyles } from '@material-ui/core/styles' -import Checkbox from '@material-ui/core/Checkbox' -import FormControlLabel from '@material-ui/core/FormControlLabel' -import { ipcRenderer } from 'electron' -import { closeWindow, exitApplication } from '../utils' - -const styles = { - disagreeButton: { - border: '1px solid #9962FF', - borderRadius: '17.5px', - color: '#9962FF', - height: 'inherit', - width: '9em' - }, - agreeButton: { - backgroundColor: '#9962FF', - borderRadius: '17.5px', - color: '#fff', - '&:hover': { - backgroundColor: '#AE83FF', - }, - height: 'inherit', - width: '9em' - }, - agreeButtonDisabled: { - backgroundColor: '#CAB4F3', - }, - checkboxDefault: {}, - checkboxChecked: {}, - root: { - color: '#9962FF !important', - '&$checked': { - color: '#9962FF !important', - }, - }, - label: { - color: '#000000', - fontSize: '15px', - }, -} - -const EulaModalComponent = ({ setSignedEula, ...props }) => { - const [isConfirmChecked, setIsConfirmChecked] = useState(false) - - const toggleConfirm = () => { - setIsConfirmChecked(!isConfirmChecked) - } - - const handleUserConfirmation = () => { - ipcRenderer.send('signed-eula') - setSignedEula(true) - closeWindow() - } - - return ( - { }} - > -
-

Software-as-a-Service Agreement

- -