From 4642935017fbb67b806d57b14b446b0112540259 Mon Sep 17 00:00:00 2001 From: rawagner Date: Thu, 20 Feb 2025 17:09:01 +0100 Subject: [PATCH] AGENT-1120: Initial Assisted Disconnected UI --- .../push-to-master-disconnected.yaml | 92 +++++++++++ .github/workflows/push-to-master.yaml | 1 + .gitignore | 1 + .../assisted-disconnected-ui/.containerignore | 2 + apps/assisted-disconnected-ui/.eslintrc.cjs | 55 +++++++ apps/assisted-disconnected-ui/.gitignore | 1 + apps/assisted-disconnected-ui/Containerfile | 24 +++ apps/assisted-disconnected-ui/README.md | 12 ++ apps/assisted-disconnected-ui/index.html | 14 ++ apps/assisted-disconnected-ui/package.json | 64 ++++++++ apps/assisted-disconnected-ui/proxy/app.go | 61 +++++++ .../proxy/bridge/common.go | 35 ++++ .../proxy/bridge/handler.go | 57 +++++++ .../proxy/config/config.go | 27 ++++ apps/assisted-disconnected-ui/proxy/go.mod | 13 ++ apps/assisted-disconnected-ui/proxy/go.sum | 20 +++ .../assisted-disconnected-ui/proxy/log/log.go | 13 ++ .../proxy/server/compression.go | 39 +++++ .../proxy/server/server.go | 40 +++++ .../public/favicon.ico | Bin 0 -> 15086 bytes apps/assisted-disconnected-ui/public/logo.svg | 1 + .../src/components/App.tsx | 39 +++++ .../src/components/EditWizard.tsx | 82 ++++++++++ .../src/components/Wizard.tsx | 37 +++++ apps/assisted-disconnected-ui/src/i18n.ts | 59 +++++++ apps/assisted-disconnected-ui/src/main.tsx | 13 ++ apps/assisted-disconnected-ui/src/styles.css | 2 + apps/assisted-disconnected-ui/tsconfig.json | 9 ++ apps/assisted-disconnected-ui/vite.config.ts | 45 ++++++ .../lib/ocm/components/clusterWizard/index.ts | 2 + .../lib/ocm/components/clusters/index.ts | 3 + libs/ui-lib/lib/ocm/components/index.ts | 2 + libs/ui-lib/lib/ocm/hooks/index.ts | 1 + libs/ui-lib/lib/ocm/hooks/useInfraEnv.ts | 2 +- libs/ui-lib/lib/ocm/index.ts | 1 + package.json | 1 + yarn.lock | 149 +++++++++++++++++- 37 files changed, 1013 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/push-to-master-disconnected.yaml create mode 100644 apps/assisted-disconnected-ui/.containerignore create mode 100644 apps/assisted-disconnected-ui/.eslintrc.cjs create mode 100644 apps/assisted-disconnected-ui/.gitignore create mode 100644 apps/assisted-disconnected-ui/Containerfile create mode 100644 apps/assisted-disconnected-ui/README.md create mode 100644 apps/assisted-disconnected-ui/index.html create mode 100644 apps/assisted-disconnected-ui/package.json create mode 100644 apps/assisted-disconnected-ui/proxy/app.go create mode 100644 apps/assisted-disconnected-ui/proxy/bridge/common.go create mode 100644 apps/assisted-disconnected-ui/proxy/bridge/handler.go create mode 100644 apps/assisted-disconnected-ui/proxy/config/config.go create mode 100644 apps/assisted-disconnected-ui/proxy/go.mod create mode 100644 apps/assisted-disconnected-ui/proxy/go.sum create mode 100644 apps/assisted-disconnected-ui/proxy/log/log.go create mode 100644 apps/assisted-disconnected-ui/proxy/server/compression.go create mode 100644 apps/assisted-disconnected-ui/proxy/server/server.go create mode 100644 apps/assisted-disconnected-ui/public/favicon.ico create mode 100644 apps/assisted-disconnected-ui/public/logo.svg create mode 100755 apps/assisted-disconnected-ui/src/components/App.tsx create mode 100644 apps/assisted-disconnected-ui/src/components/EditWizard.tsx create mode 100644 apps/assisted-disconnected-ui/src/components/Wizard.tsx create mode 100644 apps/assisted-disconnected-ui/src/i18n.ts create mode 100755 apps/assisted-disconnected-ui/src/main.tsx create mode 100644 apps/assisted-disconnected-ui/src/styles.css create mode 100644 apps/assisted-disconnected-ui/tsconfig.json create mode 100644 apps/assisted-disconnected-ui/vite.config.ts diff --git a/.github/workflows/push-to-master-disconnected.yaml b/.github/workflows/push-to-master-disconnected.yaml new file mode 100644 index 0000000000..44ece386a7 --- /dev/null +++ b/.github/workflows/push-to-master-disconnected.yaml @@ -0,0 +1,92 @@ +name: Assisted Disconnected UI - Push to master or release tag + +on: + push: + branches: + - master + tags: + - 'v*-dis' + +env: + QUAY_ORG: quay.io/edge-infrastructure + QUAY_REPO: assisted-disconnected-ui + +jobs: + preflight-check: + # Prevents running the workflow when a brand-new tag points to the same commit as the master branch + runs-on: ubuntu-latest + outputs: + skip: ${{ steps.check.outputs.skip }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Check if a tag points to the same commit as the master branch + id: check + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]] && [[ "${GITHUB_SHA}" == "$(git rev-parse origin/master)" ]]; then + skip=true + else + skip=false + fi + echo "skip=${skip}" >> $GITHUB_OUTPUT + echo "skip=${skip}" + + publish-assisted-disconnected-ui: + needs: preflight-check + if: needs.preflight-check.outputs.skip == 'false' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Generate AIUI_APP_VERSION + run: | + AIUI_APP_VERSION=latest + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + AIUI_APP_VERSION=${GITHUB_REF_NAME} + fi + echo "AIUI_APP_VERSION=${AIUI_APP_VERSION}" >> $GITHUB_ENV + echo "AIUI_APP_VERSION=${AIUI_APP_VERSION}" + + - name: Generate tags + id: generate-tags + run: | + tags=( latest-${GITHUB_SHA} latest ) + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + tags+=( ${GITHUB_REF_NAME} ) + if [[ ! "${GITHUB_REF_NAME}" =~ -cim$ ]]; then + tags+=( staging-released ) + fi + fi + echo "tags=${tags[@]}" >> $GITHUB_OUTPUT + echo "tags=${tags[@]}" + + - name: Build + id: build + uses: redhat-actions/buildah-build@v2 + with: + image: ${{ env.QUAY_REPO }} + tags: ${{ steps.generate-tags.outputs.tags }} + labels: | + org.openshift-assisted.github.repository=${{ github.repository }} + org.openshift-assisted.github.actor=${{ github.actor }} + org.openshift-assisted.github.run_id=${{ github.run_id }} + org.openshift-assisted.github.sha=${{ github.sha }} + org.openshift-assisted.github.ref_name=${{ github.ref_name }} + build-args: | + AIUI_APP_VERSION=${{ env.AIUI_APP_VERSION }} + AIUI_APP_GIT_SHA=${{ github.sha }} + AIUI_APP_IMAGE_REPO=${{ env.QUAY_ORG }}/${{ env.QUAY_REPO }} + containerfiles: apps/assisted-disconnected-ui/Containerfile + context: . + + - name: Push to Quay.io + id: push + uses: redhat-actions/push-to-registry@v2.7 + with: + image: ${{ steps.build.outputs.image }} + tags: ${{ steps.build.outputs.tags }} + registry: ${{ env.QUAY_ORG }} + username: ${{ secrets.QUAY_EDGE_INFRA_ROBOT_USERNAME }} + password: ${{ secrets.QUAY_EDGE_INFRA_ROBOT_PASSWORD }} diff --git a/.github/workflows/push-to-master.yaml b/.github/workflows/push-to-master.yaml index 8623549d31..83b5118fe5 100644 --- a/.github/workflows/push-to-master.yaml +++ b/.github/workflows/push-to-master.yaml @@ -7,6 +7,7 @@ on: tags: - 'v*' - '!v*-cim' + - '!v*-virt' env: QUAY_ORG: quay.io/edge-infrastructure diff --git a/.gitignore b/.gitignore index 3dbe2256f0..795c698c66 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ package-lock.json # Ignored apps apps/* !apps/assisted-ui +!apps/assisted-disconnected-ui diff --git a/apps/assisted-disconnected-ui/.containerignore b/apps/assisted-disconnected-ui/.containerignore new file mode 100644 index 0000000000..89aa5bb598 --- /dev/null +++ b/apps/assisted-disconnected-ui/.containerignore @@ -0,0 +1,2 @@ +**/node_modules/ +**/build/ \ No newline at end of file diff --git a/apps/assisted-disconnected-ui/.eslintrc.cjs b/apps/assisted-disconnected-ui/.eslintrc.cjs new file mode 100644 index 0000000000..e232428fc5 --- /dev/null +++ b/apps/assisted-disconnected-ui/.eslintrc.cjs @@ -0,0 +1,55 @@ +/** @type {import('eslint').ESLint.ConfigData} */ +module.exports = { + overrides: [ + { + files: ['./vite.config.ts'], + extends: ['@openshift-assisted/eslint-config'], + env: { + browser: false, + }, + parserOptions: { + tsconfigRootDir: __dirname, + }, + rules: { + 'no-console': 'off', + }, + }, + { + files: ['./src/**/*.{ts,tsx}'], + extends: ['@openshift-assisted/eslint-config', 'plugin:react/jsx-runtime'], + parserOptions: { + tsconfigRootDir: __dirname, + EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true, + }, + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'react-i18next', + importNames: ['useTranslation'], + message: + 'Import `useTranslation` from `lib/common/hooks/use-translation-wrapper.ts` instead', + }, + { + name: '@openshift-assisted/ui-lib', + message: 'Import from `@openshift-assisted/ui-lib/ocm` instead', + }, + { + name: '@patternfly/react-icons', + message: + 'Import using full path `@patternfly/react-icons/dist/js/icons/` instead', + }, + { + name: '@patternfly/react-tokens', + message: + 'Import using full path `@patternfly/react-tokens/dist/js/` instead', + }, + ], + }, + ], + }, + }, + ], +}; diff --git a/apps/assisted-disconnected-ui/.gitignore b/apps/assisted-disconnected-ui/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/apps/assisted-disconnected-ui/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/apps/assisted-disconnected-ui/Containerfile b/apps/assisted-disconnected-ui/Containerfile new file mode 100644 index 0000000000..6e3969f964 --- /dev/null +++ b/apps/assisted-disconnected-ui/Containerfile @@ -0,0 +1,24 @@ +FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:latest as ui-build +USER root +RUN microdnf install -y rsync git + +WORKDIR /app +COPY --chown=1001:0 / /app +RUN ls /app +ENV NODE_OPTIONS='--max-old-space-size=8192' +RUN git config --global --add safe.directory /app +RUN npm install -g corepack@0.24.1 +RUN yarn install --immutable && yarn build:all + +FROM registry.access.redhat.com/ubi9/go-toolset:1.21 as proxy-build +WORKDIR /app +COPY apps/assisted-disconnected-ui/proxy /app +USER 0 +RUN go build + +FROM registry.access.redhat.com/ubi9/ubi-micro +COPY --from=ui-build /app/apps/assisted-disconnected-ui/build /app/proxy/dist +COPY --from=proxy-build /app/assisted-disconnected-ui /app/proxy +WORKDIR /app/proxy +EXPOSE 8080 +CMD ./assisted-disconnected-ui diff --git a/apps/assisted-disconnected-ui/README.md b/apps/assisted-disconnected-ui/README.md new file mode 100644 index 0000000000..34f865f7dd --- /dev/null +++ b/apps/assisted-disconnected-ui/README.md @@ -0,0 +1,12 @@ +# The Assisted Installer Disconnected User Interface + +## Setting up a local dev-environment + +- Start [assisted-service](https://github.com/openshift/assisted-service). You can run it + [locally via podman](https://github.com/openshift/assisted-service/tree/master/deploy/podman) + +- Start UI + +```bash + AIUI_APP_API_URL= yarn start:assisted_disconnected_ui +``` diff --git a/apps/assisted-disconnected-ui/index.html b/apps/assisted-disconnected-ui/index.html new file mode 100644 index 0000000000..65f84075dc --- /dev/null +++ b/apps/assisted-disconnected-ui/index.html @@ -0,0 +1,14 @@ + + + + + + + + Assisted Installer + + +
+ + + diff --git a/apps/assisted-disconnected-ui/package.json b/apps/assisted-disconnected-ui/package.json new file mode 100644 index 0000000000..9b8cb6e79e --- /dev/null +++ b/apps/assisted-disconnected-ui/package.json @@ -0,0 +1,64 @@ +{ + "dependencies": { + "@openshift-assisted/ui-lib": "workspace:*", + "@openshift-console/dynamic-plugin-sdk": "0.0.3", + "@patternfly/patternfly": "5.2.0", + "@patternfly/react-code-editor": "5.2.0", + "@patternfly/react-core": "5.2.0", + "@patternfly/react-icons": "5.2.0", + "@patternfly/react-styles": "5.2.0", + "@patternfly/react-table": "5.2.0", + "@patternfly/react-tokens": "5.2.0", + "@reduxjs/toolkit": "^1.9.1", + "@sentry/browser": "^7.119", + "axios": ">=0.22.0 <2.0.0", + "i18next": "^20.4.0", + "i18next-browser-languagedetector": "^6.1.2", + "lodash": "^4", + "monaco-editor": "^0.44.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-i18next": "^11.11.4", + "react-monaco-editor": "^0.55.0", + "react-redux": "^8.0.5", + "react-router-dom": "^5.3.3", + "react-router-dom-v5-compat": "^6.21.2", + "react-tagsinput": "^3.20", + "redux": "^4", + "uuid": "^8.1", + "yup": "^1.4.0" + }, + "description": "A stand-alone web UI for the disconnected environments", + "devDependencies": { + "@tsconfig/vite-react": "^1.0.1", + "@types/react": "17.0.x", + "@vitejs/plugin-react-swc": "^3.0.1", + "concurrently": "^8.2.2", + "nodemon": "^3.0.3", + "vite": "^4.5.6", + "vite-plugin-environment": "^1.1.3" + }, + "overrides": { + "@patternfly/react-core": { + "attr-accept": "2.2.2" + } + }, + "engines": { + "node": ">=14" + }, + "license": "Apache-2.0", + "name": "@openshift-assisted/assisted-disconnected-ui", + "private": true, + "scripts": { + "build": "vite build -c vite.config.ts", + "check_types": "yarn run -T tsc --noEmit", + "clean": "yarn run -T rimraf node_modules build", + "preview": "vite preview -c vite.config.ts", + "serve": "concurrently \"vite serve -c vite.config.ts\" \"cd proxy && nodemon --watch './**/*' --exec 'go run' app.go --signal SIGTERM\"", + "format": "yarn run -T prettier --cache --check . \"!build\"", + "fix-code-style": "yarn lint --fix && yarn format --write", + "lint": "yarn run -T eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache ." + }, + "type": "module", + "version": "1.0.0" +} diff --git a/apps/assisted-disconnected-ui/proxy/app.go b/apps/assisted-disconnected-ui/proxy/app.go new file mode 100644 index 0000000000..cd6dac219e --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/app.go @@ -0,0 +1,61 @@ +package main + +import ( + "crypto/tls" + "net/http" + "time" + + "github.com/gorilla/mux" + + "github.com/openshift-assisted/assisted-disconnected-ui/bridge" + "github.com/openshift-assisted/assisted-disconnected-ui/config" + "github.com/openshift-assisted/assisted-disconnected-ui/log" + "github.com/openshift-assisted/assisted-disconnected-ui/server" +) + +func main() { + tlsConfig, err := bridge.GetTlsConfig() + if err != nil { + panic(err) + } + + log := log.InitLogs() + router := mux.NewRouter() + + apiHandler := bridge.NewAssistedAPIHandler(tlsConfig) + router.PathPrefix("/api/{forward:.*}").Handler(apiHandler) + + spa := server.SpaHandler{} + router.PathPrefix("/").Handler(server.GzipHandler(spa)) + + var serverTlsconfig *tls.Config + + if config.TlsKeyPath != "" && config.TlsCertPath != "" { + cert, err := tls.LoadX509KeyPair(config.TlsCertPath, config.TlsKeyPath) + if err != nil { + panic(err) + } + serverTlsconfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + + } + + srv := &http.Server{ + Handler: router, + Addr: config.BridgePort, + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Info("Proxy running at", config.BridgePort) + + if serverTlsconfig != nil { + srv.TLSConfig = serverTlsconfig + log.Info("Running as HTTPS") + log.Fatal(srv.ListenAndServeTLS("", "")) + } else { + log.Fatal(srv.ListenAndServe()) + } + +} diff --git a/apps/assisted-disconnected-ui/proxy/bridge/common.go b/apps/assisted-disconnected-ui/proxy/bridge/common.go new file mode 100644 index 0000000000..f69b858c2e --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/bridge/common.go @@ -0,0 +1,35 @@ +package bridge + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "os" + + "github.com/openshift-assisted/assisted-disconnected-ui/config" + log "github.com/sirupsen/logrus" +) + +func GetTlsConfig() (*tls.Config, error) { + tlsConfig := &tls.Config{} + + if config.ApiInsecure == "true" { + log.Warn("Using InsecureSkipVerify for API communication") + tlsConfig.InsecureSkipVerify = true + } + + _, err := os.Stat("../certs/ca.crt") + if errors.Is(err, os.ErrNotExist) { + return tlsConfig, nil + } + caCert, err := os.ReadFile("../certs/ca.crt") + if err != nil { + return nil, err + } + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + tlsConfig.RootCAs = caCertPool + return tlsConfig, nil +} diff --git a/apps/assisted-disconnected-ui/proxy/bridge/handler.go b/apps/assisted-disconnected-ui/proxy/bridge/handler.go new file mode 100644 index 0000000000..405a11f130 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/bridge/handler.go @@ -0,0 +1,57 @@ +package bridge + +import ( + "crypto/tls" + "net/http" + "net/http/httputil" + "net/url" + + "github.com/gorilla/mux" + + "github.com/openshift-assisted/assisted-disconnected-ui/config" +) + +type handler struct { + target *url.URL + proxy *httputil.ReverseProxy +} + +func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + r.URL.Host = h.target.Host + r.URL.Scheme = h.target.Scheme + r.Header.Set("X-Forwarded-Host", r.Header.Get("Host")) + r.Host = h.target.Host + r.URL.Path = mux.Vars(r)["forward"] + h.proxy.ServeHTTP(w, r) +} + +func createReverseProxy(apiURL string) (*url.URL, *httputil.ReverseProxy) { + target, err := url.Parse(apiURL) + if err != nil { + panic(err) + } + proxy := httputil.NewSingleHostReverseProxy(target) + proxy.ModifyResponse = func(r *http.Response) error { + filterHeaders := []string{ + "Access-Control-Allow-Headers", + "Access-Control-Allow-Methods", + "Access-Control-Allow-Origin", + "Access-Control-Expose-Headers", + } + for _, h := range filterHeaders { + r.Header.Del(h) + } + return nil + } + return target, proxy +} + +func NewAssistedAPIHandler(tlsConfig *tls.Config) handler { + target, proxy := createReverseProxy(config.AssistedApiUrl) + + proxy.Transport = &http.Transport{ + TLSClientConfig: tlsConfig, + } + + return handler{target: target, proxy: proxy} +} diff --git a/apps/assisted-disconnected-ui/proxy/config/config.go b/apps/assisted-disconnected-ui/proxy/config/config.go new file mode 100644 index 0000000000..ad8c075523 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/config/config.go @@ -0,0 +1,27 @@ +package config + +import ( + "os" + "strings" +) + +var ( + BridgePort = ":" + getEnvVar("BRIDGE_PORT", "3001") + AssistedApiUrl = getEnvUrlVar("AIUI_APP_API_URL", "") + ApiInsecure = getEnvVar("API_INSECURE_SKIP_VERIFY", "false") + TlsKeyPath = getEnvVar("TLS_KEY", "") + TlsCertPath = getEnvVar("TLS_CERT", "") +) + +func getEnvUrlVar(key string, defaultValue string) string { + urlValue := getEnvVar(key, defaultValue) + return strings.TrimSuffix(urlValue, "/") +} + +func getEnvVar(key string, defaultValue string) string { + val, ok := os.LookupEnv(key) + if !ok { + return defaultValue + } + return val +} diff --git a/apps/assisted-disconnected-ui/proxy/go.mod b/apps/assisted-disconnected-ui/proxy/go.mod new file mode 100644 index 0000000000..dcda9fd5c1 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/go.mod @@ -0,0 +1,13 @@ +module github.com/openshift-assisted/assisted-disconnected-ui + +go 1.21 + +require ( + github.com/gorilla/mux v1.8.1 + github.com/sirupsen/logrus v1.9.3 +) + +require ( + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/sys v0.22.0 // indirect +) diff --git a/apps/assisted-disconnected-ui/proxy/go.sum b/apps/assisted-disconnected-ui/proxy/go.sum new file mode 100644 index 0000000000..117fecf073 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/go.sum @@ -0,0 +1,20 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/apps/assisted-disconnected-ui/proxy/log/log.go b/apps/assisted-disconnected-ui/proxy/log/log.go new file mode 100644 index 0000000000..75f262ce96 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/log/log.go @@ -0,0 +1,13 @@ +package log + +import ( + "github.com/sirupsen/logrus" +) + +func InitLogs() *logrus.Logger { + log := logrus.New() + + log.SetReportCaller(true) + + return log +} diff --git a/apps/assisted-disconnected-ui/proxy/server/compression.go b/apps/assisted-disconnected-ui/proxy/server/compression.go new file mode 100644 index 0000000000..a3ea0585c1 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/server/compression.go @@ -0,0 +1,39 @@ +package server + +import ( + "compress/gzip" + "io" + "net/http" + "strings" +) + +type gzipResponseWriter struct { + io.Writer + http.ResponseWriter + sniffDone bool +} + +func (w *gzipResponseWriter) Write(b []byte) (int, error) { + if !w.sniffDone { + if w.Header().Get("Content-Type") == "" { + w.Header().Set("Content-Type", http.DetectContentType(b)) + } + w.sniffDone = true + } + return w.Writer.Write(b) +} + +// gzipHandler wraps a http.Handler to support transparent gzip encoding. +func GzipHandler(h http.Handler) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Vary", "Accept-Encoding") + if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { + h.ServeHTTP(w, r) + return + } + w.Header().Set("Content-Encoding", "gzip") + gz := gzip.NewWriter(w) + defer gz.Close() + h.ServeHTTP(&gzipResponseWriter{Writer: gz, ResponseWriter: w}, r) + } +} diff --git a/apps/assisted-disconnected-ui/proxy/server/server.go b/apps/assisted-disconnected-ui/proxy/server/server.go new file mode 100644 index 0000000000..fb672b2f81 --- /dev/null +++ b/apps/assisted-disconnected-ui/proxy/server/server.go @@ -0,0 +1,40 @@ +package server + +import ( + "bytes" + "net/http" + "os" + "path/filepath" + "time" +) + +type SpaHandler struct{} + +func serveIndexPage(w http.ResponseWriter, r *http.Request) { + content, err := os.ReadFile("./dist/index.html") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + http.ServeContent(w, r, "index.html", time.Time{}, bytes.NewReader(content)) + +} + +func (h SpaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + path := filepath.Join("./dist", r.URL.Path) + fi, err := os.Stat(path) + if os.IsNotExist(err) || fi.IsDir() || path == "index.html" { + serveIndexPage(w, r) + return + } + + if err != nil { + // if we got an error (that wasn't that the file doesn't exist) stating the + // file, return a 500 internal server error and stop + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // otherwise, use http.FileServer to serve the static file + http.FileServer(http.Dir("./dist")).ServeHTTP(w, r) +} diff --git a/apps/assisted-disconnected-ui/public/favicon.ico b/apps/assisted-disconnected-ui/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7206fc49595d25c091146de84556bb751a4ecac1 GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/apps/assisted-disconnected-ui/public/logo.svg b/apps/assisted-disconnected-ui/public/logo.svg new file mode 100644 index 0000000000..b7a88d40a5 --- /dev/null +++ b/apps/assisted-disconnected-ui/public/logo.svg @@ -0,0 +1 @@ +Logo-Red_Hat-OpenShift_Container_Platform-B-Black-RGB \ No newline at end of file diff --git a/apps/assisted-disconnected-ui/src/components/App.tsx b/apps/assisted-disconnected-ui/src/components/App.tsx new file mode 100755 index 0000000000..02e3425452 --- /dev/null +++ b/apps/assisted-disconnected-ui/src/components/App.tsx @@ -0,0 +1,39 @@ +import * as React from 'react'; +import { BrowserRouter, Routes, Route } from 'react-router-dom-v5-compat'; +import { Brand, Masthead, MastheadBrand, MastheadMain, Page } from '@patternfly/react-core'; +import '../i18n'; +import Wizard from './Wizard'; +import { Provider } from 'react-redux'; +import { Store } from '@openshift-assisted/ui-lib/ocm'; +import EditWizard from './EditWizard'; + +export const App: React.FC = () => { + const header = ( + + + + + + + + + + ); + + return ( + + + + + } /> + } /> + + + + + ); +}; diff --git a/apps/assisted-disconnected-ui/src/components/EditWizard.tsx b/apps/assisted-disconnected-ui/src/components/EditWizard.tsx new file mode 100644 index 0000000000..b19bc05af3 --- /dev/null +++ b/apps/assisted-disconnected-ui/src/components/EditWizard.tsx @@ -0,0 +1,82 @@ +import { + AlertsContextProvider, + CpuArchitecture, + ErrorState, + ResourceUIState, +} from '@openshift-assisted/ui-lib/common'; +import { + ClusterLoading, + ClusterWizardContextProvider, + useClusterPolling, + ClusterWizard, + useInfraEnv, + ModalDialogsContextProvider, + ClusterDefaultConfigurationProvider, + ClusterUiError, + OpenshiftVersionsContextProvider, + NewFeatureSupportLevelProvider, +} from '@openshift-assisted/ui-lib/ocm'; +import { PageSection, PageSectionVariants } from '@patternfly/react-core'; +import { useParams } from 'react-router-dom-v5-compat'; + +const EditWizard = () => { + const { clusterId } = useParams<{ clusterId: string }>() as { clusterId: string }; + const { cluster, uiState, errorDetail } = useClusterPolling(clusterId); + const pullSecret = ''; + const { + infraEnv, + isLoading: infraEnvLoading, + error: infraEnvError, + updateInfraEnv, + } = useInfraEnv( + clusterId, + cluster?.cpuArchitecture + ? (cluster.cpuArchitecture as CpuArchitecture) + : CpuArchitecture.USE_DAY1_ARCHITECTURE, + cluster?.name, + pullSecret, + cluster?.openshiftVersion, + ); + + if (uiState === ResourceUIState.LOADING || infraEnvLoading || !cluster || !infraEnv) { + return ; + } + + if (uiState === ResourceUIState.POLLING_ERROR || infraEnvError) { + return ( + + + + ); + } + + return ( + + + } + errorUI={} + > + + }> + + + + + + + + + + + ); +}; + +export default EditWizard; diff --git a/apps/assisted-disconnected-ui/src/components/Wizard.tsx b/apps/assisted-disconnected-ui/src/components/Wizard.tsx new file mode 100644 index 0000000000..d4fcd57965 --- /dev/null +++ b/apps/assisted-disconnected-ui/src/components/Wizard.tsx @@ -0,0 +1,37 @@ +import { AlertsContextProvider } from '@openshift-assisted/ui-lib/common'; +import { + ModalDialogsContextProvider, + OpenshiftVersionsContextProvider, + ClusterUiError, + ClusterDefaultConfigurationProvider, + ClusterLoading, + ClusterWizardContextProvider, + NewClusterWizard, + NewFeatureSupportLevelProvider, +} from '@openshift-assisted/ui-lib/ocm'; +import { PageSection, PageSectionVariants } from '@patternfly/react-core'; + +const Wizard = () => { + return ( + + + } + errorUI={} + > + + }> + + + + + + + + + + + ); +}; + +export default Wizard; diff --git a/apps/assisted-disconnected-ui/src/i18n.ts b/apps/assisted-disconnected-ui/src/i18n.ts new file mode 100644 index 0000000000..c5000fdf43 --- /dev/null +++ b/apps/assisted-disconnected-ui/src/i18n.ts @@ -0,0 +1,59 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import translation from '@openshift-assisted/locales/en/translation.json'; + +const dateTimeFormatter = new Intl.DateTimeFormat('default', { + month: 'short', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + year: 'numeric', +}); + +void i18n.use(initReactI18next).init({ + lng: 'en', + resources: { + en: { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + translation, + }, + }, + supportedLngs: ['en'], + fallbackLng: 'en', + load: 'languageOnly', + detection: { caches: [] }, + defaultNS: 'translation', + nsSeparator: '~', + keySeparator: false, + debug: true, + interpolation: { + format(value, format, lng) { + let output = value as unknown; + if (format === 'number' && (typeof value === 'number' || typeof value === 'bigint')) { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat#Browser_compatibility + output = new Intl.NumberFormat(lng).format(value); + } + + if (value instanceof Date) { + output = dateTimeFormatter.format(value); + } + + return String(output); + }, + escapeValue: false, // not needed for react as it escapes by default + }, + react: { + useSuspense: true, + transSupportBasicHtmlNodes: true, // allow
and simple html elements in translations + }, + missingKeyHandler(lng, ns, key) { + if (lng instanceof Array) { + for (const language of lng) { + // eslint-disable-next-line no-console + console.warn(`Missing i18n key '${key}' in namespace '${ns}' and language '${language}.'`); + } + } + }, +}); + +export default i18n; diff --git a/apps/assisted-disconnected-ui/src/main.tsx b/apps/assisted-disconnected-ui/src/main.tsx new file mode 100755 index 0000000000..96e9797e0d --- /dev/null +++ b/apps/assisted-disconnected-ui/src/main.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { App } from './components/App'; + +const rootElement = document.getElementById('root'); +if (rootElement) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + , + ); +} diff --git a/apps/assisted-disconnected-ui/src/styles.css b/apps/assisted-disconnected-ui/src/styles.css new file mode 100644 index 0000000000..a9648eb112 --- /dev/null +++ b/apps/assisted-disconnected-ui/src/styles.css @@ -0,0 +1,2 @@ +@import '@patternfly/patternfly/patternfly.css'; +@import '@patternfly/patternfly/patternfly-addons.css'; diff --git a/apps/assisted-disconnected-ui/tsconfig.json b/apps/assisted-disconnected-ui/tsconfig.json new file mode 100644 index 0000000000..dcea18059d --- /dev/null +++ b/apps/assisted-disconnected-ui/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@tsconfig/vite-react/tsconfig.json", + "include": ["src", "vite.config.ts"], + "references": [ + { + "path": "../../libs/ui-lib" + } + ] +} diff --git a/apps/assisted-disconnected-ui/vite.config.ts b/apps/assisted-disconnected-ui/vite.config.ts new file mode 100644 index 0000000000..ecb4cf684d --- /dev/null +++ b/apps/assisted-disconnected-ui/vite.config.ts @@ -0,0 +1,45 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react-swc'; +import EnvironmentPlugin from 'vite-plugin-environment'; +import 'zx/globals'; + +export const getDefaultValuesForEnvironmentVariables = async () => { + $.verbose = false; + const commitSignature = (await $`git rev-parse --short HEAD`).toString().trim(); + + return { + AIUI_APP_IMAGE_REPO: 'quay.io/edge-infrastructure/assisted-disconnected-ui', + AIUI_APP_GIT_SHA: commitSignature, + AIUI_APP_VERSION: `latest+sha.${commitSignature}`, + }; +}; + +export default defineConfig(async () => { + const envVarsPrefix = 'AIUI_'; + const defaultValues = await getDefaultValuesForEnvironmentVariables(); + + return { + build: { + emptyOutDir: true, + outDir: 'build', + sourcemap: true, + }, + resolve: { + conditions: ['source'], + }, + plugins: [ + EnvironmentPlugin(defaultValues, { + prefix: envVarsPrefix, + defineOn: 'process.env', + }), + react(), + ], + server: { + proxy: { + '/api': { + target: 'http://localhost:3001/api', + }, + }, + }, + }; +}); diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/index.ts b/libs/ui-lib/lib/ocm/components/clusterWizard/index.ts index 714829c504..1dafffed58 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/index.ts +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/index.ts @@ -1,3 +1,5 @@ export { default as ClusterDetailsForm } from './ClusterDetailsForm'; export { default as NewClusterWizard } from './NewClusterWizard'; +export { default as ClusterWizard } from './ClusterWizard'; export { default as ClusterWizardContextProvider } from './ClusterWizardContextProvider'; +export { OpenshiftVersionsContextProvider } from './OpenshiftVersionsContext'; diff --git a/libs/ui-lib/lib/ocm/components/clusters/index.ts b/libs/ui-lib/lib/ocm/components/clusters/index.ts index fab3088ed7..9d9e882b2e 100644 --- a/libs/ui-lib/lib/ocm/components/clusters/index.ts +++ b/libs/ui-lib/lib/ocm/components/clusters/index.ts @@ -1,6 +1,9 @@ export { default as Clusters } from './Clusters'; +export { default as ClusterLoading } from './ClusterLoading'; export { default as ClusterToolbar } from './ClusterToolbar'; +export { ClusterUiError } from './ClusterPageErrors'; export { default as ClusterStatus, ClusterStatusIcon } from './ClusterStatus'; export * from './NewClusterPage'; export * from './ClusterPage'; +export { useClusterPolling } from './clusterPolling'; diff --git a/libs/ui-lib/lib/ocm/components/index.ts b/libs/ui-lib/lib/ocm/components/index.ts index 7de09186fc..1f024501a3 100644 --- a/libs/ui-lib/lib/ocm/components/index.ts +++ b/libs/ui-lib/lib/ocm/components/index.ts @@ -6,3 +6,5 @@ export * from './AddHosts'; export * from './clusterWizard'; export * from './HostsClusterDetailTab'; export * from './featureSupportLevels'; +export * from './clusterConfiguration/ClusterDefaultConfigurationContext'; +export * from './hosts/ModalDialogsContext'; diff --git a/libs/ui-lib/lib/ocm/hooks/index.ts b/libs/ui-lib/lib/ocm/hooks/index.ts index 51bdb62cbd..1fd76841ff 100644 --- a/libs/ui-lib/lib/ocm/hooks/index.ts +++ b/libs/ui-lib/lib/ocm/hooks/index.ts @@ -4,3 +4,4 @@ export { default as useInfraEnvId } from './useInfraEnvId'; export { default as usePullSecret } from './usePullSecret'; export { default as useClusterPreflightRequirements } from './useClusterPreflightRequirements'; export { default as useUISettings } from './useUISettings'; +export { default as useInfraEnv } from './useInfraEnv'; diff --git a/libs/ui-lib/lib/ocm/hooks/useInfraEnv.ts b/libs/ui-lib/lib/ocm/hooks/useInfraEnv.ts index 4ee0eca127..49ecaa7f29 100644 --- a/libs/ui-lib/lib/ocm/hooks/useInfraEnv.ts +++ b/libs/ui-lib/lib/ocm/hooks/useInfraEnv.ts @@ -1,5 +1,5 @@ import React from 'react'; -import { useInfraEnvId } from '.'; +import useInfraEnvId from './useInfraEnvId'; import { CpuArchitecture } from '../../common'; import { getErrorMessage } from '../../common/utils'; import { InfraEnvsAPI } from '../services/apis'; diff --git a/libs/ui-lib/lib/ocm/index.ts b/libs/ui-lib/lib/ocm/index.ts index ba876c73b7..5f89b9e8fc 100644 --- a/libs/ui-lib/lib/ocm/index.ts +++ b/libs/ui-lib/lib/ocm/index.ts @@ -6,6 +6,7 @@ export * as Services from './services'; // without namespace export * from './components'; export * from './services'; +export * from './hooks'; // re-export selected from common export * as Features from '../common/features'; diff --git a/package.json b/package.json index 66d77b0de8..e8b6625a10 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "test:run": "yarn workspace @openshift-assisted/ui-lib-tests run cy:run", "test:unit": "yarn workspaces foreach -v run test", "start:assisted_ui": "yarn workspace @openshift-assisted/assisted-ui serve", + "start:assisted_disconnected_ui": "yarn workspace @openshift-assisted/assisted-disconnected-ui serve", "start:watch_mode": "yarn build:all && yarn run -T toolbox watch --dir=libs/ui-lib --dir=libs/types --dir=libs/locales 'yarn _build:ui-lib' 'yarn _yalc:push'", "start:vitest-ui": "vitest --ui" }, diff --git a/yarn.lock b/yarn.lock index 6db2363f35..2cf76cd96a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -744,6 +744,47 @@ __metadata: languageName: node linkType: hard +"@openshift-assisted/assisted-disconnected-ui@workspace:apps/assisted-disconnected-ui": + version: 0.0.0-use.local + resolution: "@openshift-assisted/assisted-disconnected-ui@workspace:apps/assisted-disconnected-ui" + dependencies: + "@openshift-assisted/ui-lib": "workspace:*" + "@openshift-console/dynamic-plugin-sdk": 0.0.3 + "@patternfly/patternfly": 5.2.0 + "@patternfly/react-code-editor": 5.2.0 + "@patternfly/react-core": 5.2.0 + "@patternfly/react-icons": 5.2.0 + "@patternfly/react-styles": 5.2.0 + "@patternfly/react-table": 5.2.0 + "@patternfly/react-tokens": 5.2.0 + "@reduxjs/toolkit": ^1.9.1 + "@sentry/browser": ^7.119 + "@tsconfig/vite-react": ^1.0.1 + "@types/react": 17.0.x + "@vitejs/plugin-react-swc": ^3.0.1 + axios: ">=0.22.0 <2.0.0" + concurrently: ^8.2.2 + i18next: ^20.4.0 + i18next-browser-languagedetector: ^6.1.2 + lodash: ^4 + monaco-editor: ^0.44.0 + nodemon: ^3.0.3 + react: ^18.2.0 + react-dom: ^18.2.0 + react-i18next: ^11.11.4 + react-monaco-editor: ^0.55.0 + react-redux: ^8.0.5 + react-router-dom: ^5.3.3 + react-router-dom-v5-compat: ^6.21.2 + react-tagsinput: ^3.20 + redux: ^4 + uuid: ^8.1 + vite: ^4.5.6 + vite-plugin-environment: ^1.1.3 + yup: ^1.4.0 + languageName: unknown + linkType: soft + "@openshift-assisted/assisted-ui@workspace:apps/assisted-ui": version: 0.0.0-use.local resolution: "@openshift-assisted/assisted-ui@workspace:apps/assisted-ui" @@ -2961,7 +3002,7 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^3.4.2, chokidar@npm:^3.5.3": +"chokidar@npm:^3.4.2, chokidar@npm:^3.5.2, chokidar@npm:^3.5.3": version: 3.6.0 resolution: "chokidar@npm:3.6.0" dependencies: @@ -3287,6 +3328,26 @@ __metadata: languageName: node linkType: hard +"concurrently@npm:^8.2.2": + version: 8.2.2 + resolution: "concurrently@npm:8.2.2" + dependencies: + chalk: ^4.1.2 + date-fns: ^2.30.0 + lodash: ^4.17.21 + rxjs: ^7.8.1 + shell-quote: ^1.8.1 + spawn-command: 0.0.2 + supports-color: ^8.1.1 + tree-kill: ^1.2.2 + yargs: ^17.7.2 + bin: + conc: dist/bin/concurrently.js + concurrently: dist/bin/concurrently.js + checksum: 8ac774df06869773438f1bf91025180c52d5b53139bc86cf47659136c0d97461d0579c515d848d1e945d4e3e0cafe646b2ea18af8d74259b46abddcfe39b2c6c + languageName: node + linkType: hard + "confbox@npm:^0.1.7": version: 0.1.7 resolution: "confbox@npm:0.1.7" @@ -3511,7 +3572,7 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^2.16.1": +"date-fns@npm:^2.16.1, date-fns@npm:^2.30.0": version: 2.30.0 resolution: "date-fns@npm:2.30.0" dependencies: @@ -3564,6 +3625,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4": + version: 4.4.0 + resolution: "debug@npm:4.4.0" + dependencies: + ms: ^2.1.3 + peerDependenciesMeta: + supports-color: + optional: true + checksum: fb42df878dd0e22816fc56e1fdca9da73caa85212fbe40c868b1295a6878f9101ae684f4eeef516c13acfc700f5ea07f1136954f43d4cd2d477a811144136479 + languageName: node + linkType: hard + "deep-eql@npm:^4.1.3": version: 4.1.3 resolution: "deep-eql@npm:4.1.3" @@ -5610,6 +5683,13 @@ __metadata: languageName: node linkType: hard +"ignore-by-default@npm:^1.0.1": + version: 1.0.1 + resolution: "ignore-by-default@npm:1.0.1" + checksum: 441509147b3615e0365e407a3c18e189f78c07af08564176c680be1fabc94b6c789cad1342ad887175d4ecd5225de86f73d376cec8e06b42fd9b429505ffcf8a + languageName: node + linkType: hard + "ignore@npm:^5.2.0, ignore@npm:^5.2.4": version: 5.3.1 resolution: "ignore@npm:5.3.1" @@ -6909,7 +6989,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.1.1": +"ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -7049,6 +7129,26 @@ __metadata: languageName: node linkType: hard +"nodemon@npm:^3.0.3": + version: 3.1.9 + resolution: "nodemon@npm:3.1.9" + dependencies: + chokidar: ^3.5.2 + debug: ^4 + ignore-by-default: ^1.0.1 + minimatch: ^3.1.2 + pstree.remy: ^1.1.8 + semver: ^7.5.3 + simple-update-notifier: ^2.0.0 + supports-color: ^5.5.0 + touch: ^3.1.0 + undefsafe: ^2.0.5 + bin: + nodemon: bin/nodemon.js + checksum: d045065dea08904f1356d18132538e71a61df12cb4e2852730310492943676d4789bedb28c343a5d85d5e07558bf47b73f000a8017409f0b7d522a3c1c42b2e5 + languageName: node + linkType: hard + "nopt@npm:^7.0.0": version: 7.2.0 resolution: "nopt@npm:7.2.0" @@ -7685,6 +7785,13 @@ __metadata: languageName: node linkType: hard +"pstree.remy@npm:^1.1.8": + version: 1.1.8 + resolution: "pstree.remy@npm:1.1.8" + checksum: 5cb53698d6bb34dfb278c8a26957964aecfff3e161af5fbf7cee00bbe9d8547c7aced4bd9cb193bce15fb56e9e4220fc02a5bf9c14345ffb13a36b858701ec2d + languageName: node + linkType: hard + "pump@npm:^2.0.0": version: 2.0.1 resolution: "pump@npm:2.0.1" @@ -8621,6 +8728,13 @@ __metadata: languageName: node linkType: hard +"shell-quote@npm:^1.8.1": + version: 1.8.2 + resolution: "shell-quote@npm:1.8.2" + checksum: 1e97b62ced1c4c5135015978ebf273bed1f425a68cf84163e83fbb0f34b3ff9471e656720dab2b7cbb4ae0f58998e686d17d166c28dfb3662acd009e8bd7faed + languageName: node + linkType: hard + "side-channel@npm:^1.0.4, side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" @@ -8654,6 +8768,15 @@ __metadata: languageName: node linkType: hard +"simple-update-notifier@npm:^2.0.0": + version: 2.0.0 + resolution: "simple-update-notifier@npm:2.0.0" + dependencies: + semver: ^7.5.3 + checksum: 9ba00d38ce6a29682f64a46213834e4eb01634c2f52c813a9a7b8873ca49cdbb703696f3290f3b27dc067de6d9418b0b84bef22c3eb074acf352529b2d6c27fd + languageName: node + linkType: hard + "sirv@npm:^2.0.3": version: 2.0.4 resolution: "sirv@npm:2.0.4" @@ -8746,7 +8869,7 @@ __metadata: languageName: node linkType: hard -"spawn-command@npm:^0.0.2-1": +"spawn-command@npm:0.0.2, spawn-command@npm:^0.0.2-1": version: 0.0.2 resolution: "spawn-command@npm:0.0.2" checksum: e35c5d28177b4d461d33c88cc11f6f3a5079e2b132c11e1746453bbb7a0c0b8a634f07541a2a234fa4758239d88203b758def509161b651e81958894c0b4b64b @@ -9044,7 +9167,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^5.3.0": +"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" dependencies: @@ -9297,6 +9420,15 @@ __metadata: languageName: node linkType: hard +"touch@npm:^3.1.0": + version: 3.1.1 + resolution: "touch@npm:3.1.1" + bin: + nodetouch: bin/nodetouch.js + checksum: fb8c54207500eb760b6b9d77b9c5626cc027c9ad44431eed4268845f00f8c6bbfc95ce7e9da8e487f020aa921982a8bc5d8e909d0606e82686bd0a08a8e0539b + languageName: node + linkType: hard + "tough-cookie@npm:^4.1.3": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3" @@ -9549,6 +9681,13 @@ __metadata: languageName: node linkType: hard +"undefsafe@npm:^2.0.5": + version: 2.0.5 + resolution: "undefsafe@npm:2.0.5" + checksum: f42ab3b5770fedd4ada175fc1b2eb775b78f609156f7c389106aafd231bfc210813ee49f54483d7191d7b76e483bc7f537b5d92d19ded27156baf57592eb02cc + languageName: node + linkType: hard + "underscore.string@npm:~3.3.4": version: 3.3.6 resolution: "underscore.string@npm:3.3.6"